~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Frontier Kernel
Frontier/Common/source/OpenTransportNetEvents.c

Version: ~ [ 10.0 ] ~

** Warning: Cannot open xref database.

1 2 /* $Id: OpenTransportNetEvents.c,v 1.8 2005/01/24 02:17:23 terry_teague Exp $ */ 3 4 /****************************************************************************** 5 6 UserLand Frontier(tm) -- High performance Web content management, 7 object database, system-level and Internet scripting environment, 8 including source code editing and debugging. 9 10 Copyright (C) 1992-2004 UserLand Software, Inc. 11 12 This program is free software; you can redistribute it and/or modify 13 it under the terms of the GNU General Public License as published by 14 the Free Software Foundation; either version 2 of the License, or 15 (at your option) any later version. 16 17 This program is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 26 ******************************************************************************/ 27 28 #include "frontier.h" 29 #include "standard.h" 30 31 #ifdef NeverDefine_For_Reference 32 For reference I am listing the error codes from the windows winsock.h file here 33 34 /* 35 * All Windows Sockets error constants are biased by WSABASEERR from 36 * the "normal" 37 */ 38 #define WSABASEERR 10000 39 /* 40 * Windows Sockets definitions of regular Microsoft C error constants 41 */ 42 #define WSAEINTR (WSABASEERR+4) 43 #define WSAEBADF (WSABASEERR+9) 44 #define WSAEACCES (WSABASEERR+13) 45 #define WSAEFAULT (WSABASEERR+14) 46 #define WSAEINVAL (WSABASEERR+22) 47 #define WSAEMFILE (WSABASEERR+24) 48 49 /* 50 * Windows Sockets definitions of regular Berkeley error constants 51 */ 52 #define WSAEWOULDBLOCK (WSABASEERR+35) 53 #define WSAEINPROGRESS (WSABASEERR+36) 54 #define WSAEALREADY (WSABASEERR+37) 55 #define WSAENOTSOCK (WSABASEERR+38) 56 #define WSAEDESTADDRREQ (WSABASEERR+39) 57 #define WSAEMSGSIZE (WSABASEERR+40) 58 #define WSAEPROTOTYPE (WSABASEERR+41) 59 #define WSAENOPROTOOPT (WSABASEERR+42) 60 #define WSAEPROTONOSUPPORT (WSABASEERR+43) 61 #define WSAESOCKTNOSUPPORT (WSABASEERR+44) 62 #define WSAEOPNOTSUPP (WSABASEERR+45) 63 #define WSAEPFNOSUPPORT (WSABASEERR+46) 64 #define WSAEAFNOSUPPORT (WSABASEERR+47) 65 #define WSAEADDRINUSE (WSABASEERR+48) 66 #define WSAEADDRNOTAVAIL (WSABASEERR+49) 67 #define WSAENETDOWN (WSABASEERR+50) 68 #define WSAENETUNREACH (WSABASEERR+51) 69 #define WSAENETRESET (WSABASEERR+52) 70 #define WSAECONNABORTED (WSABASEERR+53) 71 #define WSAECONNRESET (WSABASEERR+54) 72 #define WSAENOBUFS (WSABASEERR+55) 73 #define WSAEISCONN (WSABASEERR+56) 74 #define WSAENOTCONN (WSABASEERR+57) 75 #define WSAESHUTDOWN (WSABASEERR+58) 76 #define WSAETOOMANYREFS (WSABASEERR+59) 77 #define WSAETIMEDOUT (WSABASEERR+60) 78 #define WSAECONNREFUSED (WSABASEERR+61) 79 #define WSAELOOP (WSABASEERR+62) 80 #define WSAENAMETOOLONG (WSABASEERR+63) 81 #define WSAEHOSTDOWN (WSABASEERR+64) 82 #define WSAEHOSTUNREACH (WSABASEERR+65) 83 #define WSAENOTEMPTY (WSABASEERR+66) 84 #define WSAEPROCLIM (WSABASEERR+67) 85 #define WSAEUSERS (WSABASEERR+68) 86 #define WSAEDQUOT (WSABASEERR+69) 87 #define WSAESTALE (WSABASEERR+70) 88 #define WSAEREMOTE (WSABASEERR+71) 89 90 #define WSAEDISCON (WSABASEERR+101) 91 92 /* 93 * Extended Windows Sockets error constant definitions 94 */ 95 #define WSASYSNOTREADY (WSABASEERR+91) 96 #define WSAVERNOTSUPPORTED (WSABASEERR+92) 97 #define WSANOTINITIALISED (WSABASEERR+93) 98 99 /* 100 * Error return codes from gethostbyname() and gethostbyaddr() 101 * (when using the resolver). Note that these errors are 102 * retrieved via WSAGetLastError() and must therefore follow 103 * the rules for avoiding clashes with error numbers from 104 * specific implementations or language run-time systems. 105 * For this reason the codes are based at WSABASEERR+1001. 106 * Note also that [WSA]NO_ADDRESS is defined only for 107 * compatibility purposes. 108 */ 109 110 #define h_errno WSAGetLastError() 111 112 /* Authoritative Answer: Host not found */ 113 #define WSAHOST_NOT_FOUND (WSABASEERR+1001) 114 #define HOST_NOT_FOUND WSAHOST_NOT_FOUND 115 116 /* Non-Authoritative: Host not found, or SERVERFAIL */ 117 #define WSATRY_AGAIN (WSABASEERR+1002) 118 #define TRY_AGAIN WSATRY_AGAIN 119 120 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ 121 #define WSANO_RECOVERY (WSABASEERR+1003) 122 #define NO_RECOVERY WSANO_RECOVERY 123 124 /* Valid name, no data record of requested type */ 125 #define WSANO_DATA (WSABASEERR+1004) 126 #define NO_DATA WSANO_DATA 127 128 /* no address, look for MX record */ 129 #define WSANO_ADDRESS WSANO_DATA 130 #define NO_ADDRESS WSANO_ADDRESS 131 132 #endif 133 //This ends the Reference Section 134 135 136 static unsigned char * xtierrorstrings [] = { 137 "", /* 3149 */ 138 "\x1B" "A Bad address was specified", /* 3150 */ 139 "\x1A" "A Bad option was specified", /* 3151 */ 140 "\x19" "Missing access permission", /* 3152 */ 141 "\x16" "Bad provider reference", /* 3153 */ 142 "\x18" "No address was specified", /* 3154 */ 143 "\x1A" "Call issued in wrong state", /* 3155 */ 144 "\x21" "Sequence specified does not exist", /* 3156 */ 145 "\x17" "A system error occurred", /* 3157 */ 146 "\x21" "An event occurred - call OTLook()", /* 3158 */ 147 "\x27" "An illegal amount of data was specified", /* 3159 */ 148 "\x1C" "Passed buffer not big enough", /* 3160 */ 149 "\x1B" "Provider is flow-controlled", /* 3161 */ 150 "\x1D" "No data available for reading", /* 3162 */ 151 "\x22" "No disconnect indication available", /* 3163 */ 152 "\x27" "No Unit Data Error indication available", /* 3164 */ 153 "\x1D" "A Bad flag value was supplied", /* 3165 */ 154 "\x27" "No orderly release indication available", /* 3166 */ 155 "\x18" "Command is not supported", /* 3167 */ 156 "\x23" "State is changing - try again later", /* 3168 */ 157 "\x28" "Bad structure type requested for OTAlloc", /* 3169 */ 158 "\x1A" "Host not found (DNS error)", /* 3170 */ 159 "\x29" "A Bind to an in-use address with qlen > 0", /* 3171 */ 160 "\x23" "Address requested is already in use", /* 3172 */ 161 "\x27" "Accept failed because of pending listen", /* 3173 */ 162 "\x28" "Tried to accept on incompatible endpoint", /* 3174 */ 163 "", /* 3175 */ 164 "", /* 3176 */ 165 "", /* 3177 */ 166 "\x26" "An unspecified provider error occurred", /* 3178 */ 167 "\x24" "A synchronous call at interrupt time", /* 3179 */ 168 "\x19" "The command was cancelled" /* 3180 */ 169 }; 170 171 #if 0 172 173 static unsigned char * dnserrorstrings [5] = { 174 "", 175 "\x1b" "Host not found. (DNS error)", /* 1 */ 176 "\x37" "Non-authoritative host not found. (Temporary DNS error)", /* 2 */ 177 "\x22" "Non-recoverable error. (DNS error)", /* 3 */ 178 "\x39" "Valid name, no data record of requested type. (DNS error)", /* 4 */ 179 }; 180 181 #endif 182 183 static unsigned char * stdcliberrorstrings [80] = { 184 "", 185 "\x1b" "Permission denied", /* 1 */ 186 "\x37" "No such file or directory", /* 2 */ 187 "\x22" "No such resource", /* 3 */ 188 "\x39" "Interrupted system service", /* 4 */ 189 "\x12" "Input/output error", /* 5 */ 190 "\x15" "Device not configured", /* 6 */ 191 "\x16" "Argument list too long", /* 7 */ 192 "\x11" "Exec format error", /* 8 */ 193 "\x13" "Bad file descriptor", /* 9 */ 194 "\x12" "No child processes", /* 10 */ 195 "\x19" "Resource deadlock avoided", /* 11 */ 196 "\x16" "Cannot allocate memory", /* 12 */ 197 "\x11" "Permission denied", /* 13 */ 198 "\x0b" "Bad address", /* 14 */ 199 "\x15" "Block device required", /* 15 */ 200 "\x0b" "Device busy", /* 16 */ 201 "\x0b" "File exists", /* 17 */ 202 "\x11" "Cross-device link", /* 18 */ 203 "\x21" "Operation not supported by device", /* 19 */ 204 "\x0f" "Not a directory", /* 20 */ 205 "\x0e" "Is a directory", /* 21 */ 206 "\x10" "Invalid argument", /* 22 */ 207 "\x1d" "Too many open files in system", /* 23 */ 208 "\x15" "Too many open sockets", /* 24 */ 209 "\x1e" "Inappropriate ioctl for device", /* 25 */ 210 "\x0e" "Text file busy", /* 26 */ 211 "\x0e" "File too large", /* 27 */ 212 "\x17" "No space left on device", /* 28 */ 213 "\x0d" "Illegal seek", /* 29 */ 214 "\x15" "Read-only file system", /* 30 */ 215 "\x0e" "Too many links", /* 31 */ 216 "\x0b" "Broken pipe", /* 32 */ 217 "", 218 "", 219 220 /* non-blocking and interrupt i/o */ 221 "\x20" "Resource temporarily unavailable", /* 35 */ 222 223 /* ipc/network software -- argument errors */ 224 "\x23" "A blocking operation is in progress", /* 36 */ 225 "\x20" "Operation is already in progress", /* 37 */ 226 227 /* ipc/network software -- argument errors */ 228 "\x20" "Socket operation on a non-socket", /* 38 */ 229 "\x1f" "Destination address is required", /* 39 */ 230 "\x10" "Message too long", /* 40 */ 231 "\x1e" "Protocol wrong type for socket", /* 41 */ 232 "\x16" "Protocol not available", /* 42 */ 233 "\x16" "Protocol not supported", /* 43 */ 234 "\x19" "Socket type not supported", /* 44 */ 235 "\x21" "Operation not supported on socket", /* 45 */ 236 "\x1d" "Protocol family not supported", /* 46 */ 237 "\x2f" "Address family not supported by protocol family", /* 47 */ 238 "\x16" "Address already in use", /* 48 */ 239 "\x1e" "Can't assign requested address", /* 49 */ 240 241 /* ipc/network software -- operational errors */ 242 "\x0f" "Network is down", /* 50 */ 243 "\x16" "Network is unreachable", /* 51 */ 244 "\x23" "Network dropped connection on reset", /* 52 */ 245 "\x20" "Software caused connection abort", /* 53 */ 246 "\x18" "Connection reset by peer", /* 54 */ 247 "\x19" "No buffer space available", /* 55 */ 248 "\x1b" "Socket is already connected", /* 56 */ 249 "\x17" "Socket is not connected", /* 57 */ 250 "\x20" "Can't send after socket shutdown", /* 58 */ 251 "\x21" "Too many references: can't splice", /* 59 */ 252 "\x14" "Connection timed out", /* 60 */ 253 "\x12" "Connection refused", /* 61 */ 254 255 "\x21" "Too many levels of symbolic links", /* 62 */ 256 "\x12" "File name too long", /* 63 */ 257 258 "\x0c" "Host is down", /* 64 */ 259 "\x10" "No route to host", /* 65 */ 260 "\x13" "Directory not empty", /* 66 */ 261 "\x12" "Too many processes", /* 67 */ 262 "\x0e" "Too many users", /* 68 */ 263 "\x13" "Disc quota exceeded", /* 69 */ 264 265 /* Network File System */ 266 "\x15" "Stale NFS file handle", /* 70 */ 267 "\x21" "Too many levels of remote in path", /* 71 */ 268 "\x11" "RPC struct is bad", /* 72 */ 269 "\x11" "RPC version wrong", /* 73 */ 270 "\x13" "RPC prog. not avail", /* 74 */ 271 "\x15" "Program version wrong", /* 75 */ 272 "\x19" "Bad procedure for program", /* 76 */ 273 "\x12" "No locks available", /* 77 */ 274 "\x18" "Function not implemented", /* 78 */ 275 "\x21" "Inappropriate file type or format", /* 79 */ 276 }; //tcperrorstrings 277 278 #define wsprintf sprintf 279 280 #include "mac.h" 281 #include "error.h" 282 #include "kb.h" 283 #include "ops.h" 284 #include "memory.h" 285 #include "threads.h" 286 #include "strings.h" 287 #include "lang.h" 288 #include "langinternal.h" 289 #include "process.h" 290 #include "processinternal.h" 291 #include "shell.h" 292 #include "shellhooks.h" 293 #include "timedate.h" 294 #include "WinSockNetEvents.h" 295 #include "frontierdebug.h" 296 #include "file.h" 297 298 299 #ifndef OTAssert 300 #define OTAssert(name, cond) ((cond) ? ((void) 0) : (DebugStr( __FILE__ ": " #name ": " #cond ))) 301 #endif 302 303 #define NO_HOST_SERVICES NULL 304 305 #define SOCKTYPE_INVALID -1 306 #define SOCKTYPE_UNKNOWN 0 307 #define SOCKTYPE_OPEN 1 308 #define SOCKTYPE_DATA 2 309 #define SOCKTYPE_LISTENING 3 310 #define SOCKTYPE_CLOSED 4 311 #define SOCKTYPE_LISTENSTOPPED 5 312 #define SOCKTYPE_INACTIVE 6 313 314 #define INTNETERROR_INVALIDSTREAM -1 315 316 static const long kPacketSize = 8192L; 317 318 typedef short tysocktypeid; 319 320 typedef struct tylistenrecord * ListenRecordRef; 321 322 typedef struct tyendpointrecord * EndpointRecordRef; 323 324 typedef struct tyepstatsrecord { 325 long cttotal; 326 long ctidle; 327 long ctbroken; 328 long ctworking; 329 long ctwaiting; 330 } tyepstatsrecord; 331 332 /* 333 2004-10-28 aradke: OTLink and OTLIFO must be aligned on 32-bit boundaries! 334 */ 335 336 typedef struct tylistenrecord { 337 EndpointRef ep; 338 OTLink validationlink; /* Link into an OT FIFO (not atomic) */ 339 OTLIFO idleEPs; /* Endpoints ready to accept a new incoming connection */ 340 OTLIFO brokenEPs; /* Collect failed endpoints for recycling by worker thread */ 341 OTLIFO readyEPs; /* Ready to be picked up by the worker thread which will spawn a thread to call the daemon */ 342 OTLIFO waitingEPs; /* Endpoints waiting to complete an orderly disconnect */ 343 UInt8 stateflags; 344 OTConfigurationRef masterconfig; 345 EndpointRecordRef acceptors; 346 long maxdepth; 347 long refcon; 348 long idthread; 349 hdldatabaserecord hdatabase; 350 Handle hcallbacktree; 351 tyepstatsrecord stats; 352 tysocktypeid typeID; 353 boolean fllistenpending; 354 bigstring callback; 355 } tylistenrecord; 356 357 typedef struct tyendpointrecord { 358 EndpointRef ep; 359 OTLink link; /* Used for linking into TCP low-level lists (atomic) */ 360 OTLink validationlink; /* Used for linking into worker thread lists (atomic) */ 361 UInt8 stateflags; 362 UInt8 completionflags; 363 OSStatus result; 364 tysocktypeid typeID; 365 long timestamp; /* System time when we started waiting for an orderly disconnect */ 366 ListenRecordRef listener; /* Nil if not operated by a listener */ 367 TCall* sendCall; /* Not nil if we initiate a connection */ 368 } tyendpointrecord; 369 370 #if TARGET_API_MAC_CARBON == 1 371 /*Code change by Timothy Paustian Monday, September 25, 2000 8:34:30 PM 372 I added these globals to keep the UPPs for carbon.*/ 373 ThreadEntryTPP gThreadEntryCallback; 374 OTNotifyUPP gListenNotifierUPP; 375 OTListSearchUPP gListSearchUPP; 376 OTNotifyUPP gNotifierUPP; 377 OTListSearchUPP gEndListSearchUPP; 378 OTNotifyUPP gDNRNotifierUPP; 379 #endif 380 381 static tyepstatsrecord epstats; 382 383 static OTList sListenList; /* List of valid listen streams to verify against when receiving params from scripts */ 384 static OTList sEndpointList; /* List of valid active streams to verify against when receiving params from scripts */ 385 386 static OTLIFO sIdleEPs; /* Endpoints ready to accept a new incoming connection -- Listeners have their own private list */ 387 static OTLIFO sBrokenEPs; /* Collect failed endpoints for recycling by main thread -- Listeners have their own private list */ 388 static OTLIFO sWaitingEPs; /* Endpoints waiting to complete an orderly disconnect */ 389 390 static OTConfigurationRef sMasterConfig; 391 392 static OSType sOTVersionSelector = 'otvr'; 393 static long sOTVersion; 394 395 static short frontierWinSockCount = 0; 396 static boolean frontierWinSockLoaded = false; 397 398 399 enum { 400 kBrokenBit = 0, // Bit numbers in stateflags fields 401 kOpenInProgressBit = 1, 402 kPassconBit = 2, 403 kBoundBit = 3, 404 kDontDisposeBit = 4, 405 kWaitingForConnectBit = 5, 406 kWaitingForDisconnectBit = 6, 407 408 kConnectCompleteBit = 0, // Bit numbers in completionflags fields 409 kGetProtAddressBit = 1, 410 kRcvdDisconnectBit = 2, 411 kSntDisconnectBit = 3, 412 kRcvdOrderlyDisconnectBit = 4, 413 kIPReuseAddrBit = 5, 414 kTCPKeepAliveBit = 6, 415 416 kOTVersion111 = 0x01110000, // Minimum version of Open Transport required 417 418 kTCPKeepAliveInMinutes = 1, 419 kTCPWaitSecsForConnect = 30, // seconds allowed for connect to complete, when elapsed we return an OT error (-3260 or -3259) 420 421 kTCPWaitSecsForOrderlyDisconnect = 60, // seconds allowed for orderly disconnect to complete, when elapsed we initiate an abortive disconnect 422 423 kDontQueueIt = 0, 424 kQueueIt = 1 425 }; 426 427 // 428 // Option structure 429 // 430 // This is used to pass down both IP_REUSEADDR and TCP_KEEPALIVE in the 431 // same option message 432 // 433 434 struct TKeepAliveOpt { 435 UInt32 len; 436 OTXTILevel level; 437 OTXTIName name; 438 UInt32 status; 439 UInt32 tcpKeepAliveOn; 440 UInt32 tcpKeepAliveTimer; 441 }; 442 443 typedef struct TKeepAliveOpt TKeepAliveOpt; 444 445 446 /* DNS queries structure */ 447 448 const unsigned long fcomplete = 1L; 449 450 typedef struct { 451 OTResult result; 452 unsigned long flags; 453 } dnsquery; 454 455 456 /* Templates for static functions */ 457 458 static void InitEndpoint (EndpointRecordRef epref, EndpointRef ep, ListenRecordRef listenref); 459 static pascal void ReturnEndpoint (EndpointRecordRef epref, OTResult result, int completionbit); 460 static boolean CheckEndpointList (EndpointRecordRef epref); 461 static boolean CheckListenList (ListenRecordRef listenref); 462 static void CheckUnbind (EndpointRecordRef epref, OTResult result, Boolean queueIt); 463 static OSStatus DoBind (EndpointRecordRef epref); 464 static void DoRcvDisconnect (EndpointRecordRef epref); 465 static void EnterRcvDisconnect (EndpointRecordRef epref); 466 static void DoListenRcvDisconnect (ListenRecordRef listenref); 467 static void EnterListenAccept (ListenRecordRef listenref); 468 static OSStatus DoSndOrderlyDisconnect (EndpointRecordRef epref, boolean flrecurse); 469 //static OSStatus EnterSndOrderlyDisconnect (EndpointRecordRef epref); 470 static OSStatus DoSndDisconnect (EndpointRecordRef epref); 471 static OSStatus EnterSndDisconnect (EndpointRecordRef epref); 472 static void ReadAllAndClose (EndpointRecordRef epref); 473 //static void DoWaitList (ListenRecordRef listenref); 474 static pascal void DNRNotifier (void *context, OTEventCode event, OTResult result, void *cookie); 475 static pascal void ListenNotifier (void *context, OTEventCode code, OTResult result, void *cookie); 476 static pascal void Notifier (void *context, OTEventCode code, OTResult result, void *cookie); 477 static OSStatus EPOpen (EndpointRecordRef epref, OTConfigurationRef cfg); 478 static boolean EPClose (EndpointRecordRef epref); 479 static void Recycle (ListenRecordRef listenref); 480 481 /*Code change by Timothy Paustian Monday, September 25, 2000 8:58:07 PM 482 needed to add a declaration to get the new carbon stuff to compile.*/ 483 static void *fwsacceptingthreadmain (void *param); 484 485 486 /* TCPTRACKER stuff */ 487 488 static char * TCPGETTYPE (tysocktypeid typeID) { 489 switch (typeID) { 490 case SOCKTYPE_INVALID: 491 return ("INVALID"); 492 493 case SOCKTYPE_UNKNOWN: 494 return ("UNKNOWN"); 495 496 case SOCKTYPE_OPEN: 497 return ("OPEN"); 498 499 case SOCKTYPE_DATA: 500 return ("DATA"); 501 502 case SOCKTYPE_LISTENING: 503 return ("LISTENING"); 504 505 case SOCKTYPE_CLOSED: 506 return ("CLOSED"); 507 508 case SOCKTYPE_LISTENSTOPPED: 509 return ("LISTEN-STOPPED"); 510 511 case SOCKTYPE_INACTIVE: 512 return ("INACTIVE"); 513 514 default: 515 break; 516 } 517 518 return ("BAD Type value"); 519 } /*TCPGETTYPE*/ 520 521 522 /* 523 To disable the tcp tracker, don't define TCPTRACKER. 524 525 To enable tcp tracker ouput in the about window, define TCPTRACKER == 1. 526 527 To enable tcp tracker error ouput to a file, define TCPTRACKER == 2. 528 529 To enable full tcp tracker output to a file, define TCPTRACKER == 3. 530 */ 531 532 //#undef TCPTRACKER 533 #define TCPTRACKER 1 534 //#define TCPTRACKER 2 535 //#define TCPTRACKER 3 536 537 #if (TCPTRACKER == 3) 538 #pragma message ("*********************** TCPTRACKER is ON: Full output to tcpfile.txt ***********************") 539 540 static boolean fllogger = true; 541 542 #ifdef WIN95VERSION 543 extern DWORD ixthreadglobalsgrabcount; // Tls index of counter for nest globals grabbing 544 #endif 545 546 static FILE * tcpfile = NULL; 547 static char TCPmsg[400]; 548 549 #define TCPprintf(msg) msg 550 #define TCPERRORprintf(msg) msg 551 552 static void TCPWRITEMSG () { 553 unsigned long ticks = gettickcount (); 554 static unsigned long lastticks = 0; 555 #ifdef WIN95VERSION 556 DWORD idthread; 557 static DWORD idlastthread = 0; 558 long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount); 559 #endif 560 #ifdef MACVERSION 561 static ThreadID idlastthread = 0; 562 ThreadID idthread; 563 #endif 564 565 if (fllogger) { 566 if (tcpfile == NULL) { 567 tcpfile = fopen ("tcpfile.txt", "w+"); 568 } 569 #ifdef WIN95VERSION 570 idthread = GetCurrentThreadId(); 571 #endif 572 #ifdef MACVERSION 573 MacGetCurrentThread (&idthread); 574 #endif 575 576 if (idthread != idlastthread) { 577 fprintf (tcpfile, "\n"); 578 idlastthread = idthread; 579 } 580 581 #ifdef WIN95VERSION 582 fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg); 583 #endif 584 585 #ifdef MACVERSION 586 fprintf (tcpfile, "%08X (%04ld) | %04X | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg); 587 #endif 588 589 lastticks = ticks; 590 591 fflush (tcpfile); 592 } 593 } /*TCPWRITEMSG*/ 594 595 #define TCPERRORWRITEMSG TCPWRITEMSG 596 597 static void TCPTRACKERCLOSE () { 598 if (fllogger) { 599 if (tcpfile != NULL) 600 fclose (tcpfile); 601 } 602 } 603 604 605 #elif (TCPTRACKER == 2) 606 #pragma message ("*********************** TCPTRACKER is ON: Error output to tcpfile.txt **********************") 607 608 static boolean fllogger = true; 609 610 #ifdef WIN95VERSION 611 extern DWORD ixthreadglobalsgrabcount; // Tls index of counter for nest globals grabbing 612 #endif 613 614 static FILE * tcpfile = NULL; 615 static char TCPmsg[400]; 616 617 #define TCPprintf(msg) 618 #define TCPWRITEMSG() 619 620 #define TCPERRORprintf(msg) msg 621 622 static void TCPERRORWRITEMSG () { 623 unsigned long ticks = gettickcount (); 624 static unsigned long lastticks = 0; 625 #ifdef WIN95VERSION 626 DWORD idthread; 627 static DWORD idlastthread = 0; 628 long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount); 629 #endif 630 #ifdef MACVERSION 631 long idthread = (long) (**getcurrentthread ()).idthread; 632 static long idlastthread = 0; 633 #endif 634 635 if (fllogger) { 636 #ifdef WIN95VERSION 637 idthread = GetCurrentThreadId(); 638 #endif 639 640 if (tcpfile == NULL) { 641 tcpfile = fopen ("tcpfile.txt", "w+"); 642 } 643 644 if (idthread != idlastthread) { 645 fprintf (tcpfile, "\n"); 646 idlastthread = idthread; 647 } 648 649 #ifdef WIN95VERSION 650 fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg); 651 #endif 652 653 #ifdef MACVERSION 654 fprintf (tcpfile, "%08X (%04ld) | %04X | %s\n", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg); 655 #endif 656 657 lastticks = ticks; 658 659 fflush (tcpfile); 660 } 661 } /*TCPWRITEMSG*/ 662 663 664 static void TCPTRACKERCLOSE () { 665 if (fllogger) { 666 if (tcpfile != NULL) 667 fclose (tcpfile); 668 } 669 } 670 671 #elif (TCPTRACKER == 1) 672 #pragma message ("*********************** TCPTRACKER is ON: Full output to About window **********************") 673 674 #include "about.h" 675 #define fllogger (aboutstatsshowing()) 676 #define TCPprintf(msg) msg 677 #define TCPERRORprintf(msg) msg 678 679 static char TCPmsg[400]; 680 681 static void TCPWRITEMSG () { 682 683 if (fllogger) { 684 685 convertcstring (TCPmsg); 686 687 aboutsetmiscstring (TCPmsg); 688 } 689 } /*TCPWRITEMSG*/ 690 691 #define TCPERRORWRITEMSG TCPWRITEMSG 692 693 #define TCPTRACKERCLOSE() 694 695 #else 696 697 #define TCPprintf(msg) 698 #define TCPERRORprintf(msg) 699 #define TCPWRITEMSG() 700 #define TCPERRORWRITEMSG() 701 #define TCPTRACKERIN(functionName, linenumber, streamID) 702 #define TCPTRACKEROUT(functionName, linenumber, streamID) 703 #define TCPTRACKERCLOSE() 704 705 #endif 706 707 #if (defined (TCPTRACKER) && (TCPTRACKER==1 || TCPTRACKER==3)) 708 709 static void TCPTRACKERIN (char * functionName, int linenumber, EndpointRecordRef epref, ListenRecordRef listenref) { 710 if (fllogger) { 711 712 if (epref) { 713 if (!CheckEndpointList (epref)) { 714 wsprintf (TCPmsg, "Entering %s at line %d, EndpointRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) epref); 715 TCPWRITEMSG (); 716 return; 717 } 718 719 wsprintf (TCPmsg, "Entering %s at line %d, EndpointRecordRef = %08lx, Endpoint = %08lx, Type = %s, State Flags = %02x, Completion Flags = %02x, Listen Ref = %08lX.", 720 functionName, linenumber, (long) epref, (long) epref->ep, TCPGETTYPE (epref->typeID), epref->stateflags, epref->completionflags, (long) epref->listener); 721 722 TCPWRITEMSG (); 723 } 724 725 if (listenref) { 726 if (!CheckListenList (listenref)) { 727 wsprintf (TCPmsg, "Entering %s at line %d, ListenRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) listenref); 728 TCPWRITEMSG (); 729 return; 730 } 731 732 wsprintf (TCPmsg, "Entering %s at line %d, ListenRecordRef = %08lx, Endpoint = %08lx, Type = %s, Max Depth = %ld, Refcon = %08lX, Thread = %ld", 733 functionName, linenumber, (long) listenref, (long) listenref->ep, TCPGETTYPE (listenref->typeID), listenref->maxdepth, listenref->refcon, listenref->idthread); 734 735 TCPWRITEMSG (); 736 } 737 } 738 } /*TCPTRACKERIN*/ 739 740 741 static void TCPTRACKEROUT (char * functionName, int linenumber, EndpointRecordRef epref, ListenRecordRef listenref) { 742 if (fllogger) { 743 744 if (epref) { 745 if (!CheckEndpointList (epref)) { 746 wsprintf (TCPmsg, "Exiting %s at line %d, EndpointRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) epref); 747 TCPWRITEMSG (); 748 return; 749 } 750 751 wsprintf (TCPmsg, "Exiting %s at line %d, EndpointRecordRef = %08lx, Endpoint = %08lx, Type = %s, State Flags = %02x, Completion Flags = %02x, Listen Ref = %08lX.", 752 functionName, linenumber, (long) epref, (long) epref->ep, TCPGETTYPE (epref->typeID), epref->stateflags, epref->completionflags, (long) epref->listener); 753 754 TCPWRITEMSG (); 755 } 756 757 if (listenref) { 758 if (!CheckListenList (listenref)) { 759 wsprintf (TCPmsg, "Exiting %s at line %d, ListenRecordRef = %08lx - INVALID ENPOINT.", functionName, linenumber, (long) listenref); 760 TCPWRITEMSG (); 761 return; 762 } 763 764 wsprintf (TCPmsg, "Exiting %s at line %d, ListenRecordRef = %08lx, Endpoint = %08lx, Type = %s, Max Depth = %ld, Refcon = %08lX, Thread = %ld", 765 functionName, linenumber, (long) listenref, (long) listenref->ep, TCPGETTYPE (listenref->typeID), listenref->maxdepth, listenref->refcon, listenref->idthread); 766 767 TCPWRITEMSG (); 768 } 769 } 770 } /*TCPTRACKEROUT*/ 771 772 #else 773 774 #define TCPTRACKERIN(functionName, linenumber, epref, listenref) 775 #define TCPTRACKEROUT(functionName, linenumber, epref, listenref) 776 777 #endif 778 779 780 #ifdef PIKE /*7.1b3 PBS: maxconnections is now variable.*/ 781 782 /*extern const*/ /*long maxconnections = 5;*/ 783 784 long maxconnections = longinfinity; /*7.1b5 PBS: no more connection limit*/ 785 786 #else 787 788 /*extern const*/ long maxconnections = longinfinity; /*7.0b37 PBS: reported in system.environment table in Frontier*/ 789 790 #endif 791 792 static long ctconnections = 0; 793 794 795 long fwsNetEventGetConnectionCount (void) { 796 797 /*7.0b37 PBS: return current count of TCP connections. 798 Used by tcp.countConnections verb. 799 */ 800 801 return (ctconnections); 802 } /*fwsNetEventGetConnectionCount*/ 803 804 805 static boolean incrementconnectioncounter (void) { 806 807 if (ctconnections >= maxconnections) 808 return (false); 809 810 ctconnections++; 811 812 return (true); 813 }/*incrementconnectioncounter*/ 814 815 static void decrementconnectioncounter (void) { 816 817 ctconnections--; 818 819 if (ctconnections < 0) /*7.0b53 PBS: a script can abort or close a stream multiple times.*/ 820 /*Instead we should get this info from the OS, but until then we do this.*/ 821 ctconnections = 0; 822 823 //assert (ctconnections >= 0); 824 825 }/*decrementconnectioncounter*/ 826 827 828 829 //#else 830 // #define incrementconnectioncounter() (true) 831 // #define decrementconnectioncounter() ((void *)0L); 832 //#endif 833 834 835 static pascal boolean listendatabasevisit (const void* ref, OTLink* linkToCheck) { 836 837 hdldatabaserecord hdatabase = (hdldatabaserecord) ref; 838 839 return (hdatabase == (OTGetLinkObject (linkToCheck, tylistenrecord, validationlink))->hdatabase); 840 }/*listendatabasevisit*/ 841 842 843 static pascal boolean listenlinkvisit (const void* ref, OTLink* linkToCheck) { 844 845 ListenRecordRef listenref = (ListenRecordRef) ref; 846 847 return (listenref == OTGetLinkObject (linkToCheck, tylistenrecord, validationlink)); 848 }/*listenlinkvisit*/ 849 850 851 static pascal boolean endpointlinkvisit (const void* ref, OTLink* linkToCheck) { 852 853 EndpointRecordRef epref = (EndpointRecordRef) ref; 854 855 return (epref == OTGetLinkObject (linkToCheck, tyendpointrecord, validationlink)); 856 }/*endpointlinkvisit*/ 857 858 859 static boolean CheckEndpointList (EndpointRecordRef epref) { 860 861 OTLink *eplink; 862 863 #if TARGET_API_MAC_CARBON == 1 864 eplink = OTFindLink (&sEndpointList, gEndListSearchUPP, (void *) epref); 865 #else 866 eplink = OTFindLink (&sEndpointList, &endpointlinkvisit, (void *) epref); 867 #endif 868 869 return (nil != eplink); 870 }/*CheckEndpointList*/ 871 872 873 static boolean CheckListenList (ListenRecordRef listenref) { 874 875 OTLink *listenlink; 876 877 #if TARGET_API_MAC_CARBON == 1 878 listenlink = OTFindLink (&sListenList, gListSearchUPP, (void *) listenref); 879 #else 880 listenlink = OTFindLink (&sListenList, &listenlinkvisit, (void *) listenref); 881 #endif 882 883 return (nil != listenlink); 884 }/*CheckListenList*/ 885 886 887 static void InitEndpoint (EndpointRecordRef epref, EndpointRef ep, ListenRecordRef listenref) { 888 889 OTMemzero (epref, sizeof (tyendpointrecord)); 890 891 epref->ep = ep; 892 893 epref->listener = listenref; 894 895 epref->typeID = SOCKTYPE_INVALID; 896 897 return; 898 }/*InitEndpoint*/ 899 900 901 static pascal void ReturnEndpoint (EndpointRecordRef epref, OTResult result, int completionbit) { 902 903 if (OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) { 904 905 epref->result = result; 906 907 OTAtomicClearBit (&epref->stateflags, kWaitingForConnectBit); 908 909 OTAtomicSetBit (&epref->completionflags, completionbit); 910 } 911 else { 912 boolean flbound = OTAtomicTestBit (&epref->stateflags, kBoundBit); 913 914 if (flbound) 915 result = OTUnbind (epref->ep); 916 917 CheckUnbind (epref, result, !flbound); 918 } 919 }/*ReturnEndpoint*/ 920 921 922 // 923 // CheckUnbind 924 // 925 // This routine checks the results of an unbind. Due to various problems 926 // in OpenTransport, an OTUnbind can fail for a number of reasons. This problem 927 // is timing related so you usually won't hit it. When an OTUnbind fails, 928 // we assume the best way to recover is to throw the endpoint on the broken 929 // list to be recycled. Later, in the recycle routine, it will be closed 930 // and a new endpoint will be opened to replace it. If the OTUnbind is 931 // successful, the endpoint is put back on the free list to be reused. 932 // 933 // Since the unbind failure is timing related, a more efficient solution 934 // would probably be to wait and retry the unbind in a few seconds, 935 // expecting that the call would not fail on the next try. 936 // 937 static void CheckUnbind (EndpointRecordRef epref, OTResult result, Boolean queueIt) { 938 939 ListenRecordRef listenref = epref->listener; 940 941 if (kOTNoError != result) { 942 943 if (0 == OTAtomicSetBit (&epref->stateflags, kBrokenBit)) { 944 /* 945 The OTAtomicSetBit guarantee's that the EPInfo won't be 946 enqueued twice. We only enqueue the EPInfo if the previous 947 state of the bit was 0. 948 */ 949 if (nil != listenref) { 950 951 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link); 952 953 listenref->stats.ctworking--; 954 955 listenref->stats.ctbroken++; 956 } 957 else { 958 959 OTLIFOEnqueue (&sBrokenEPs, &epref->link); 960 961 epstats.ctworking--; 962 963 epstats.ctbroken++; 964 } 965 } 966 } 967 else { 968 if (queueIt) { 969 970 TCP_ASSERT_1 (nil != epref->ep); 971 972 if (nil != listenref) { 973 974 OTLIFOEnqueue (&listenref->idleEPs, &epref->link); 975 976 listenref->stats.ctworking--; 977 978 listenref->stats.ctidle++; 979 980 if (listenref->fllistenpending) 981 EnterListenAccept (listenref); 982 } 983 else { 984 985 #if TARGET_API_MAC_CARBON == 1 986 987 EPClose (epref); 988 989 epstats.ctworking--; 990 991 #else 992 993 OTLIFOEnqueue (&sIdleEPs, &epref->link); 994 995 epstats.ctworking--; 996 997 epstats.ctidle++; 998 #endif 999 } 1000 } 1001 } 1002 }/*CheckUnbind*/ 1003 1004 1005 // 1006 // DoBind 1007 // 1008 // This routine requests a wildcard port binding from the transport protocol. 1009 // Since the program doesn't care what port is returned, it passes in NULL 1010 // for the bind return parameter. The bind request structure is ephemeral 1011 // and can be a local stack variable since OT is done with it when the call returns. 1012 // The bind is done when the notifier receives a T_BINDCOMPLETE event. 1013 // 1014 static OSStatus DoBind (EndpointRecordRef epref) { 1015 1016 OSStatus err; 1017 TBind bindReq; 1018 InetAddress inAddr; 1019 1020 /* 1021 Bind the endpoint to a wildcard address (assign us a port, we don't care which one). 1022 */ 1023 OTInitInetAddress(&inAddr, 0, 0); 1024 1025 bindReq.addr.len = sizeof (InetAddress); 1026 bindReq.addr.buf = (unsigned char *) &inAddr; 1027 bindReq.qlen = 0; 1028 1029 err = OTBind (epref->ep, &bindReq, NULL); 1030 1031 if (err != kOTNoError) 1032 TCP_MSG_1 ("DoBind: OTBind returned an error"); 1033 1034 return (err); 1035 }/*DoBind*/ 1036 1037 1038 static OSStatus EnterBind (EndpointRecordRef epref) { 1039 1040 OSStatus err; 1041 boolean doLeave = OTEnterNotifier (epref->ep); 1042 1043 err = DoBind (epref); 1044 1045 if (doLeave) 1046 OTLeaveNotifier (epref->ep); 1047 1048 return (err); 1049 }/*EnterBind*/ 1050 1051 1052 static void DoRcvOrderlyDisconnect (EndpointRecordRef epref) { 1053 1054 OSStatus err; 1055 1056 err = OTRcvOrderlyDisconnect (epref->ep); 1057 1058 if (kOTNoError != err) 1059 return; 1060 1061 OTAtomicSetBit (&epref->completionflags, kRcvdOrderlyDisconnectBit); 1062 1063 if (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) 1064 if (T_IDLE == OTGetEndpointState (epref->ep)) 1065 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 1066 }/*DoRcvOrderlyDisconnect*/ 1067 1068 1069 static void EnterRcvOrderlyDisconnect (EndpointRecordRef epref) { 1070 1071 boolean doLeave = OTEnterNotifier (epref->ep); 1072 1073 DoRcvOrderlyDisconnect (epref); 1074 1075 if (doLeave) 1076 OTLeaveNotifier (epref->ep); 1077 }/*EnterRcvOrderlyDisconnect*/ 1078 1079 1080 1081 static void DoRcvDisconnect (EndpointRecordRef epref) { 1082 1083 OSStatus err; 1084 TDiscon discon; 1085 1086 discon.udata.len = nil; 1087 1088 err = OTRcvDisconnect (epref->ep, &discon); 1089 1090 1091 switch (err) { 1092 1093 case kOTNoError: 1094 epref->result = E2OSStatus (discon.reason); 1095 OTAtomicSetBit (&epref->completionflags, kRcvdDisconnectBit); 1096 break; 1097 1098 case kOTBufferOverflowErr: 1099 epref->result = kECONNREFUSEDErr; /*most likely cause*/ 1100 OTAtomicSetBit (&epref->completionflags, kRcvdDisconnectBit); 1101 break; 1102 1103 default: 1104 if (err != kOTNoDisconnectErr) 1105 TCP_MSG_1 ("DoRcvDisconnect: OTRcvDisconnect on endpoint returned an error"); 1106 epref->result = err; 1107 break; 1108 } 1109 1110 if (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) 1111 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 1112 }/*DoRcvDisconnect*/ 1113 1114 1115 static void EnterRcvDisconnect (EndpointRecordRef epref) { 1116 1117 boolean doLeave = OTEnterNotifier (epref->ep); 1118 1119 DoRcvDisconnect (epref); 1120 1121 if (doLeave) 1122 OTLeaveNotifier (epref->ep); 1123 }/*EnterRcvDisconnect*/ 1124 1125 1126 // 1127 // DoListenRcvDisconnect 1128 // 1129 // This routine is called from ListenNotifier in T_LISTEN handling 1130 // upon getting a kOTLookErr back indicating a T_DISCONNECT needs to be handled. 1131 // 1132 static void DoListenRcvDisconnect (ListenRecordRef listenref) { 1133 1134 OSStatus err; 1135 1136 err = OTRcvDisconnect (listenref->ep, NULL); 1137 1138 if (kOTNoError != err) 1139 TCP_MSG_1 ("DoListenRcvDisconnect: OTRcvDisconnect on listener returned an error"); 1140 1141 return; 1142 }/*DoListenRcvDisconnect*/ 1143 1144 1145 // 1146 // DoListenAccept 1147 // 1148 // The handling of a T_LISTEN is greatly simplified by use 1149 // of the tilisten module, which serializes inbound connections. 1150 // This means that when doing an OTAccept we won't get a kOTLookErr 1151 // because another inbound connection arrived and created a T_LISTEN. 1152 // Without the tilisten module, we have to use the "8 step 1153 // listen/accept/disconnect method", which is documented elsewhere. 1154 // At this point, if we have a free endpoint, accept the connection. 1155 // If we don't, assume we are overloaded and reject the connection. 1156 // 1157 // When we are called from inside the notifier due to a T_LISTEN, 1158 // DoListenAccept() is called directly. 1159 // 1160 // When we restart delayed handling of a T_LISTEN, either because of 1161 // doing a throttle-back or because the program ran out of free endpoints, 1162 // EnterListenAccept() is called for synchronization on the listener endpoint. 1163 // 1164 1165 static void DoListenAccept (ListenRecordRef listenref) { 1166 1167 OTLink* acceptor_link; 1168 EndpointRecordRef acceptor; 1169 TCall call; 1170 InetAddress clientaddr; 1171 OTResult lookResult; 1172 OSStatus err; 1173 1174 /* if (!incrementconnectioncounter ()) { 1175 OTSndDisconnect (listenref->ep, nil); /%6.2b13 AR: reject connection (PIKE) %/ 1176 return; 1177 }*/ 1178 1179 if (!incrementconnectioncounter ()) { 1180 1181 listenref->fllistenpending = true; 1182 1183 return; 1184 } /*if*/ 1185 1186 // 1187 // Get an EPInfo & endpoint. If none are available, defer handling the T_LISTEN. 1188 // 1189 acceptor_link = OTLIFODequeue (&listenref->idleEPs); 1190 1191 if (acceptor_link == NULL) { 1192 decrementconnectioncounter(); 1193 listenref->fllistenpending = true; 1194 return; 1195 } 1196 1197 listenref->fllistenpending = false; 1198 1199 listenref->stats.ctidle--; 1200 1201 listenref->stats.ctworking++; 1202 1203 acceptor = OTGetLinkObject (acceptor_link, tyendpointrecord, link); 1204 1205 InitEndpoint (acceptor, acceptor->ep, listenref); 1206 1207 call.addr.maxlen = sizeof(InetAddress); 1208 call.addr.buf = (unsigned char*) &clientaddr; 1209 call.opt.maxlen = 0; 1210 call.opt.buf = NULL; 1211 call.udata.maxlen = 0; 1212 call.udata.buf = NULL; 1213 1214 err = OTListen (listenref->ep, &call); 1215 1216 if (kOTNoError != err) { 1217 // 1218 // Only two errors are expected at this point. 1219 // One would be a kOTNoDataErr, indicating the inbound connection 1220 // was unavailable, temporarily hidden by a higher priority streams 1221 // message, etc. The more likely error is a kOTLookErr, 1222 // which indicates a T_DISCONNECT on the OTLook() 1223 // happens when the call we were going to process disconnected. 1224 // In that case, go away and wait for the next T_LISTEN event. 1225 // 1226 OTLIFOEnqueue (&listenref->idleEPs, &acceptor->link); 1227 1228 listenref->stats.ctworking--; 1229 1230 listenref->stats.ctidle++; 1231 1232 if (kOTNoDataErr != err) { 1233 lookResult = OTLook (listenref->ep); 1234 1235 if (kOTLookErr == err && T_DISCONNECT == lookResult) 1236 DoListenRcvDisconnect (listenref); 1237 else 1238 TCP_MSG_1 ("Notifier: T_LISTEN - OTListen returned an error"); 1239 } 1240 1241 decrementconnectioncounter(); 1242 1243 return; 1244 } 1245 1246 err = OTAccept (listenref->ep, acceptor->ep, &call); 1247 1248 if (kOTNoError != err) { 1249 // 1250 // Again, we have to be able to handle the connection being disconnected 1251 // while we were trying to accept it. 1252 // 1253 OTLIFOEnqueue (&listenref->idleEPs, &acceptor->link); 1254 1255 listenref->stats.ctworking--; 1256 1257 listenref->stats.ctidle++; 1258 1259 lookResult = OTLook (listenref->ep); 1260 1261 if (kOTLookErr == err && T_DISCONNECT == lookResult) 1262 DoListenRcvDisconnect (listenref); 1263 else 1264 TCP_MSG_1 ("Notifier: T_LISTEN - OTAccept returned an error"); 1265 1266 decrementconnectioncounter(); 1267 } 1268 }/*DoListenAcceept*/ 1269 1270 1271 // 1272 // EnterListenAccept 1273 // 1274 // This is a front end to DoListenAccept() which is used whenever 1275 // it is not being called from inside the listener endpoint's notifier. 1276 // We do this for synchronization. If we were processing an OTListen() 1277 // or an OTAccept() and we were interrupted at the listener endpoint's 1278 // notifier with a T_LISTEN, etc, it would be inconvenient and would require 1279 // some more sophisticated synchronization code to deal with the problem. 1280 // The easy way to avoid this is to do an OTEnterNotifier() on the listener's 1281 // endpoint. 1282 // 1283 // Important note - doing OTEnterNotifier on one endpoint only prevents that 1284 // endpoint's notifier for interrupting us. Since the same notifier code 1285 // is used for lots of endpoints here, remember that the one endpoint's 1286 // notifier can interrupt another. Doing an OTEnterNotifier() on the 1287 // listener endpoint prevents the listener from interrupting us, but it 1288 // does not prevent the Notifier() routine from interrupting us via 1289 // another endpoint which also uses the same routine. 1290 // 1291 // Important note #2 - Don't ever do an OTEnterNotifier on an acceptor endpoint 1292 // before doing the OTAccept(). This confuses OT and creates problems. 1293 // 1294 static void EnterListenAccept (ListenRecordRef listenref) { 1295 1296 boolean doLeave = OTEnterNotifier (listenref->ep); 1297 1298 DoListenAccept (listenref); 1299 1300 if (doLeave) 1301 OTLeaveNotifier(listenref->ep); 1302 } 1303 1304 1305 // 1306 // DoSndOrderlyDisconnect 1307 // 1308 // This routine is a front end to OTSndOrderlyDisconnect(). It's only called 1309 // from fwsNetEventCloseStream but not from the Notifier. 1310 // 1311 static OSStatus DoSndOrderlyDisconnect (EndpointRecordRef epref, boolean flrecurse) { 1312 1313 OSStatus err; 1314 1315 /* Indicate to the notifier that it's now responsible for recycling this endpoint */ 1316 1317 err = OTSndOrderlyDisconnect (epref->ep); 1318 1319 if (kOTNoError != err) { 1320 1321 if (kOTLookErr == err) { 1322 1323 OTResult result = OTLook (epref->ep); 1324 1325 switch (result) { 1326 1327 case T_DISCONNECT: 1328 DoRcvDisconnect (epref); 1329 break; 1330 1331 case T_ORDREL: 1332 DoRcvOrderlyDisconnect (epref); 1333 if (flrecurse) 1334 err = DoSndOrderlyDisconnect (epref, false); // try again, but only once 1335 break; 1336 1337 default: { 1338 TCP_MSG_1 ("DoSndOrderlyDisconnect: OTLook returned an unhandled event"); 1339 CheckUnbind (epref, kOTLookErr, kDontQueueIt); 1340 } 1341 } 1342 } 1343 else { 1344 TCP_MSG_1 ("DoSndOrderlyDisconnect: OTSndOrderlyDisconnect returned an error"); 1345 CheckUnbind (epref, err, kDontQueueIt); 1346 } 1347 } 1348 else 1349 ReadAllAndClose (epref); 1350 1351 return (err); 1352 }/*DoSndOrderlyDisconnect*/ 1353 1354 #if 0 1355 1356 static OSStatus EnterSndOrderlyDisconnect (EndpointRecordRef epref) { 1357 1358 OSStatus err; 1359 boolean doLeave = OTEnterNotifier (epref->ep); 1360 1361 err = DoSndOrderlyDisconnect (epref); 1362 1363 if (doLeave) 1364 OTLeaveNotifier(epref->ep); 1365 1366 return (err); 1367 }/*EnterSndOrderlyDisconnect*/ 1368 1369 #endif 1370 1371 // 1372 // DoSndDisconnect 1373 // 1374 // This routine is a front end to OTSndDisconnect(). It's only called from 1375 // EnterSndDisconnect and DoSndOrderlyDisconnect but not from the Notifier. 1376 // We give up control of the endpoint at this point. The Notifier is supposed to do the clean up. 1377 // 1378 static OSStatus DoSndDisconnect (EndpointRecordRef epref) { 1379 1380 OSStatus err; 1381 1382 /* Indicate to the notifier that it's now responsible for recycling this endpoint */ 1383 1384 OTAtomicClearBit (&epref->stateflags, kDontDisposeBit); 1385 1386 /* Initiate disconnect */ 1387 1388 err = OTSndDisconnect (epref->ep, nil); 1389 1390 if (kOTNoError != err) { 1391 1392 if (kOTLookErr == err) { 1393 1394 OTResult result = OTLook (epref->ep); 1395 1396 switch (result) { 1397 1398 case T_DISCONNECT: 1399 DoRcvDisconnect (epref); 1400 break; 1401 1402 default: 1403 TCP_MSG_1 ("DoSndDisconnect: OTLook returned an unhandled event"); 1404 CheckUnbind (epref, kOTLookErr, kDontQueueIt); 1405 break; 1406 } 1407 } 1408 else { 1409 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 1410 TCP_MSG_1 ("DoSndDisconnect: OTSndOrderlyDisconnect returned an error"); 1411 } 1412 } 1413 1414 return (err); 1415 }/*DoSndDisconnect*/ 1416 1417 1418 // 1419 // EnterSndDisconnect 1420 // 1421 // A thin wrapper around DoSndDisconnect. 1422 // Called from fwsNetEventAbortStream to initiate an abortive disconnect. 1423 // 1424 static OSStatus EnterSndDisconnect (EndpointRecordRef epref) { 1425 1426 OSStatus err; 1427 boolean doLeave = OTEnterNotifier (epref->ep); 1428 1429 err = DoSndDisconnect (epref); 1430 1431 if (doLeave) 1432 OTLeaveNotifier(epref->ep); 1433 1434 return (err); 1435 }/*EnterSndDisconnect*/ 1436 1437 1438 // 1439 // ReadAndClose: 1440 // 1441 // This routine attempts to read all available data from an endpoint. 1442 // Check the endpoint state to see if there's any data left to be read. 1443 // If so, read until we get an error -- most likely a kOTNoDataErr. 1444 // 1445 // Then check the endpoint state to see if we are in T_IDLE. If so, 1446 // the connection is fully broken down and we can unbind and requeue 1447 // the endpoint for reuse. 1448 // 1449 // Otherwise, the notifier will eventually get a T_ORDREL, T_DISCONNECT, 1450 // or another T_DATA event and take care of the rest. 1451 // 1452 static void ReadAllAndClose (EndpointRecordRef epref) { 1453 1454 OTResult epstate = OTGetEndpointState (epref->ep); 1455 1456 switch (epstate) { 1457 1458 case T_INREL: 1459 DoRcvOrderlyDisconnect (epref); 1460 return; 1461 1462 case T_DATAXFER: { 1463 char buffer[kPacketSize]; 1464 OTResult result; 1465 OTFlags junkFlags; 1466 1467 do { 1468 result = OTRcv (epref->ep, buffer, kPacketSize, &junkFlags); 1469 } while (result >= 0); 1470 1471 epstate = OTGetEndpointState (epref->ep); 1472 } 1473 }/*switch*/ 1474 1475 if (T_IDLE == epstate && 0 == OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) { 1476 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 1477 } 1478 }/*ReadAllAndClose*/ 1479 1480 1481 static pascal void DNRNotifier (void *context, OTEventCode event, OTResult result, void *cookie) { 1482 1483 #pragma unused (cookie) 1484 1485 switch (event) { 1486 1487 case T_DNRADDRTONAMECOMPLETE: 1488 case T_DNRSTRINGTOADDRCOMPLETE: { 1489 dnsquery *q = (dnsquery *) context; 1490 1491 q->result = result; 1492 1493 q->flags |= fcomplete; 1494 1495 break; 1496 } 1497 } 1498 1499 return; 1500 }/*dnsnotifier*/ 1501 1502 static pascal void ListenNotifier (void* context, OTEventCode code, OTResult result, void* cookie) { 1503 1504 #pragma unused (cookie) 1505 1506 ListenRecordRef listenref = (ListenRecordRef) context; 1507 1508 switch (code) { 1509 1510 /* 1511 T_DISCONNECT: 1512 1513 Call DoListenRcvDisconnect to do all the work 1514 */ 1515 case T_DISCONNECT: { 1516 DoListenRcvDisconnect (listenref); 1517 return; 1518 } 1519 1520 /* 1521 T_DISCONNECTCOMPLETE: 1522 */ 1523 case T_DISCONNECTCOMPLETE: { 1524 if (kOTNoError != result) 1525 TCP_MSG_1 ("ListenNotifier: T_DISCONNECT_COMPLETE returned an error"); 1526 return; 1527 } 1528 1529 /* 1530 T_LISTEN: 1531 1532 Call DoListenAccept() to do all the work. 1533 */ 1534 case T_LISTEN: { 1535 DoListenAccept (listenref); 1536 break; 1537 } 1538 1539 /* 1540 T_ACCEPTCOMPLETE: 1541 1542 This event is received by the listener endpoint only. 1543 The acceptor endpoint will get a T_PASSCON event instead. 1544 */ 1545 case T_ACCEPTCOMPLETE: 1546 OTAssert ("ListenNotifier: T_ACCEPTCOMPLETE returned an error.", result == kOTNoError); 1547 return; 1548 1549 /* 1550 default: 1551 1552 There are events which we don't handle, but we don't expect to see 1553 any of them. When running in debugging mode while developing a program, 1554 we exit with an informational alert. Later, in the production version 1555 of the program, we ignore the event and try to keep running. 1556 */ 1557 default: { 1558 TCP_MSG_1 ("ListenNotifier: unknown event"); 1559 return; 1560 } 1561 1562 }/*switch (event)*/ 1563 1564 }/*ListenNotifier*/ 1565 1566 static OSStatus SetIpReuseAddrOption (EndpointRecordRef epref) { 1567 1568 TOptMgmt optReq; 1569 TOption opt; 1570 1571 optReq.flags = T_NEGOTIATE; 1572 optReq.opt.len = kOTFourByteOptionSize; 1573 optReq.opt.buf = (unsigned char *) &opt; 1574 1575 opt.len = sizeof(TOption); 1576 opt.level = INET_IP; 1577 opt.name = kIP_REUSEADDR; 1578 opt.status = 0; 1579 opt.value[0] = 1; 1580 1581 return (OTOptionManagement (epref->ep, &optReq, nil)); 1582 }/*SetIpReuseAddrOption*/ 1583 1584 1585 static OSStatus SetTcpKeepAliveOption (EndpointRecordRef epref) { 1586 1587 TOptMgmt optReq; 1588 TKeepAliveOpt opt; 1589 1590 optReq.flags = T_NEGOTIATE; 1591 optReq.opt.len = sizeof (TKeepAliveOpt); 1592 optReq.opt.buf = (unsigned char *) &opt; 1593 1594 opt.len = sizeof (TKeepAliveOpt); 1595 opt.level = INET_TCP; 1596 opt.name = TCP_KEEPALIVE; 1597 opt.status = 0; 1598 opt.tcpKeepAliveOn = 1; 1599 opt.tcpKeepAliveTimer = kTCPKeepAliveInMinutes; 1600 1601 return (OTOptionManagement (epref->ep, &optReq, nil)); 1602 }/*SetTcpKeepAliveOption*/ 1603 1604 1605 static OSStatus SetTcpConnAbortThresholdOption (EndpointRecordRef epref) { 1606 1607 TOptMgmt optReq; 1608 TOption opt; 1609 1610 optReq.flags = T_NEGOTIATE; 1611 optReq.opt.len = kOTFourByteOptionSize; 1612 optReq.opt.buf = (unsigned char *) &opt; 1613 1614 opt.len = sizeof(TOption); 1615 opt.level = INET_TCP; 1616 opt.name = TCP_CONN_ABORT_THRESHOLD; 1617 opt.status = 0; 1618 opt.value[0] = kTCPWaitSecsForConnect * 1000; /*milliseconds*/ 1619 1620 return (OTOptionManagement (epref->ep, &optReq, nil)); 1621 }/*SetTcpConnAbortThresholdOption*/ 1622 1623 1624 static pascal void Notifier (void* context, OTEventCode code, OTResult result, void* cookie) { 1625 1626 /* 1627 2002-10-30 AR: Fixed a possible connection leak in the T_PASSCON handler 1628 where we neglected to return the endpoint to the broken queue 1629 in case of an error. 1630 */ 1631 1632 EndpointRecordRef epref = (EndpointRecordRef) context; 1633 OSStatus err = noErr; 1634 1635 switch (code) { 1636 1637 /* 1638 T_OPENCOMPLETE: 1639 1640 This event occurs when an OTAsyncOpenEndpoint() completes. Note that this event, 1641 just like any other async call made from outside the notifier, can occur during 1642 the call to OTAsyncOpenEndpoint(). That is, in the main thread the program did 1643 the OTAsyncOpenEndpoint(), and the notifier is invoked before control is returned 1644 to the line of code following the call to OTAsyncOpenEndpoint(). This is one 1645 event we need to keep track of even if we are shutting down the program since there 1646 is no way to cancel outstanding OTAsyncOpenEndpoint() calls. 1647 */ 1648 case T_OPENCOMPLETE: { 1649 1650 /* Clear the OpenInProgress bit and check result of OTAsyncOpenEndpoint */ 1651 1652 OTAtomicClearBit (&epref->stateflags, kOpenInProgressBit); 1653 1654 if (kOTNoError == result) 1655 epref->ep = (EndpointRef) cookie; 1656 else { 1657 TCP_MSG_1 ("Notifier: T_OPENCOMPLETE returned an error"); 1658 ReturnEndpoint (epref, result, kConnectCompleteBit); 1659 return; 1660 } 1661 1662 /* We should insert a test here to break out if we're in the process of shutting down the listener or the app */ 1663 1664 /* Set endpoint to blocking mode */ 1665 1666 err = OTSetBlocking (epref->ep); 1667 1668 if (kOTNoError != err) { 1669 TCP_MSG_1 ("Notifier: T_OPENCOMPLETE - OTSetBlocking returned an error"); 1670 ReturnEndpoint (epref, err, kConnectCompleteBit); 1671 return; 1672 } 1673 1674 /* Option Management - Turn on ip_reuseaddr so we don't have port conflicts in general. */ 1675 1676 if (kOTNoError != SetIpReuseAddrOption (epref)) { 1677 TCP_MSG_2 ("Notifier: T_OPENCOMPLETE - OTOptionManagement returned an error"); 1678 ReturnEndpoint (epref, err, kConnectCompleteBit); 1679 return; 1680 } 1681 1682 /* Code path resumes at T_OPTMGMTCOMPLETE */ 1683 1684 return; 1685 } 1686 1687 /* 1688 T_OPTMGMTCOMPLETE: 1689 1690 An OTOptionManagement() call has completed. We set the ip_reuseaddr option 1691 for all endpoints right after they have been opened. We set the TCP_KEEPALIVE 1692 option for all endpoints every time we accept or intiate a new connection. 1693 We also set the TCP_CONN_ABORT_THRESHOLD option for all active endpoints 1694 whenever we we initiate a new connection. 1695 */ 1696 case T_OPTMGMTCOMPLETE: { 1697 1698 ListenRecordRef listenref = epref->listener; 1699 1700 if (result != kOTNoError) { 1701 TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE returned an error"); 1702 ReturnEndpoint (epref, result, kConnectCompleteBit); 1703 return; 1704 } 1705 1706 if (nil != listenref) { 1707 1708 /* 1709 This is the branch where we deal with passive endpoints that are used by 1710 the listener to accept incoming connections. If we just opened the endpoint, 1711 the T_OPENCOMPLETE handler just negotiated the ip_reuseaddr option. 1712 In this case, the next thing to do is to add the endpoint to the list of idle endpoints. 1713 If there is a connection pending, we accept it right away. 1714 */ 1715 if (0 == OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit)) { 1716 1717 OTLIFOEnqueue (&listenref->idleEPs, &epref->link); 1718 1719 listenref->stats.ctworking--; 1720 1721 listenref->stats.ctidle++; 1722 1723 if (listenref->fllistenpending) 1724 EnterListenAccept (listenref); 1725 1726 return; 1727 } 1728 1729 /* 1730 If we get here, the T_PASSCON handler just negotiated the TCP_KEEPALIVE option. 1731 After setting the appropriate completion flag, we are ready to go to work. 1732 */ 1733 if (0 == OTAtomicSetBit (&epref->completionflags, kTCPKeepAliveBit)) { 1734 1735 OTAtomicSetBit (&epref->stateflags, kDontDisposeBit); 1736 1737 OTLIFOEnqueue (&epref->listener->readyEPs, &epref->link); 1738 1739 return; 1740 } 1741 1742 /* 1743 We should never ever manage to get here, so post a debug message. 1744 */ 1745 TCP_MSG_1 ("Notifier: T_OPTMGMTCOMPLETE got triggered unexpectedly"); 1746 return; 1747 } 1748 1749 else { 1750 1751 /* 1752 This is the branch where we deal with active endpoints. If we just opened the endpoint, 1753 the last thing we did was to negotiate the ip_reuseaddr option. In this case, 1754 the next thing to do is to bind the endpoint if it was opened by fwsOpenStream, 1755 or to add it to the list of idle endpoints if it was re-opened by Recycle. 1756 */ 1757 if (0 == OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit)) { 1758 1759 if (nil != epref->sendCall) { 1760 1761 /* 1762 The endpoint was just opened by fwsOpenStream. The next thing to do is to bind it. 1763 If the DoBind call succeeds, the code path will resume at T_BINDCOMPLETE. 1764 */ 1765 err = DoBind (epref); 1766 1767 if (kOTNoError != err) { 1768 TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE - DoBind returned an error"); 1769 ReturnEndpoint (epref, err, kConnectCompleteBit); 1770 } 1771 } 1772 else { 1773 1774 /* 1775 The endpoint was just re-opened by Recycle. Now it's ready to go on the list of idle endpoints. 1776 Eventually, it will be dequeued by fwsOpenStream in order to be bound again. 1777 If that DoBind call succeeds, the code path will resume at T_BINDCOMPLETE. 1778 */ 1779 OTLIFOEnqueue (&sIdleEPs, &epref->link); 1780 1781 epstats.ctworking--; 1782 1783 epstats.ctidle++; 1784 } 1785 1786 return; 1787 } 1788 1789 /* 1790 If the TCP_KEEPALIVE flag hasn't been set yet, T_BINDCOMPLETE just negotiated the TCP_KEEPALIVE option. 1791 In that case, the next thing to do is to also negotiate the TCP_CONN_ABORT_THRESHOLD option. 1792 */ 1793 if (0 == OTAtomicSetBit (&epref->completionflags, kTCPKeepAliveBit)) { 1794 1795 if (kOTNoError != SetTcpConnAbortThresholdOption (epref)) { 1796 TCP_MSG_2 ("Notifier: T_OPTMGMTCOMPLETE - OTOptionManagement returned an error"); 1797 ReturnEndpoint (epref, err, kConnectCompleteBit); 1798 } 1799 1800 return; 1801 } 1802 1803 /* 1804 We get here if both the TCP_KEEPALIVE and TCP_CONN_ABORT_THRESHOLD options have been negotiated. 1805 Now we are ready to connect to the peer. 1806 */ 1807 err = OTConnect (epref->ep, epref->sendCall, nil); 1808 1809 if (err != kOTNoDataErr) { 1810 /* anything other than kOTNoDataErr means that a connection has not been initiated */ 1811 TCP_MSG_1 ("Notifier: T_OPTMGMTCOMPLETE - OTConnect returned an error"); 1812 ReturnEndpoint (epref, err, kConnectCompleteBit); 1813 return; 1814 } 1815 /* 1816 If OTConnect returned the expected kOTNoDataErr, the code path will resume at T_CONNECT. 1817 */ 1818 } 1819 1820 return; 1821 } 1822 1823 /* 1824 T_PASSCON: 1825 1826 This event happens on the accepting endpoint, not the listening endpoint. 1827 At this point the connection is fully established and we can begin the 1828 process of downloading data. Note that due to a problem in OT it is 1829 possible for a T_DATA to beat a T_PASSCON to the notifier. When this 1830 happens we note it in the T_DATA case and then start processing the 1831 data here. 1832 */ 1833 case T_PASSCON: { 1834 1835 if (kOTNoError != result) { 1836 TCP_MSG_1 ("Notifier: T_PASSCON returned an error"); 1837 decrementconnectioncounter(); 1838 ReturnEndpoint (epref, result, kConnectCompleteBit); /* 2002-10-30 AR: don't leak endpoint */ 1839 return; 1840 } 1841 1842 if (0 != OTAtomicSetBit (&epref->stateflags, kPassconBit)) { 1843 1844 /* 1845 A T_DATA previously beat the T_PASSCON to our notifier. 1846 Here we help OT out by having deferred data processing until now. 1847 */ 1848 if (OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit)) { 1849 ReadAllAndClose (epref); 1850 return; 1851 } 1852 } 1853 1854 /* 1855 Before we can get to work, we need to negotiate the TCP_KEEPALIVE option. 1856 First, we set the ip_reuseaddr bit to make sure that 1857 the T_OPTMGMTCOMPLETE handler does the right thing. 1858 */ 1859 OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit); 1860 1861 if (kOTNoError != SetTcpKeepAliveOption (epref)) { 1862 TCP_MSG_2 ("Notifier: T_PASSCON - OTOptionManagement returned an error"); 1863 ReturnEndpoint (epref, err, kConnectCompleteBit); 1864 } 1865 1866 /* 1867 If SetTcpKeepAliveOption succeeded, the code path will resume at T_OPTMGMTCOMPLETE. 1868 */ 1869 return; 1870 } 1871 1872 /* 1873 T_BINDCOMPLETE: 1874 1875 This event is returned when an endpoint has been bound to a wildcard address. 1876 No errors are expected. We should only get here if the endpoint belongs 1877 to an active connection, initiated by fwsOpenStream rather than by a listener. 1878 We set the bound bit and the ip_reuseaddr bit so that the Notifier will do the right thing. 1879 Then we negotiate the TCP_KEEPALIVE option. 1880 */ 1881 case T_BINDCOMPLETE: { 1882 1883 if (kOTNoError != result) { 1884 TCP_MSG_1 ("Notifier: T_BINDCOMPLETE returned an error"); 1885 ReturnEndpoint (epref, result, kConnectCompleteBit); 1886 return; 1887 } 1888 1889 OTAtomicSetBit (&epref->stateflags, kBoundBit); /* so we know to unbind... */ 1890 1891 OTAtomicSetBit (&epref->completionflags, kIPReuseAddrBit); /* make sure we do the right thing in the notifier*/ 1892 1893 if (kOTNoError != SetTcpKeepAliveOption (epref)) { 1894 TCP_MSG_2 ("Notifier: T_BINDCOMPLETE - OTOptionManagement returned an error"); 1895 ReturnEndpoint (epref, err, kConnectCompleteBit); 1896 } 1897 1898 /* 1899 If SetTcpKeepAliveOption succeeded, the code path will resume at T_OPTMGMTCOMPLETE. 1900 */ 1901 return; 1902 } 1903 1904 /* 1905 T_CONNECT: 1906 1907 This event is returned when a connection is established to the server. 1908 The program must call OTRcvConnect() to get the connection information 1909 and clear the T_CONNECT event from the stream. Since OTRcvConnect() 1910 returns immediately (rather than via a completion event to the notifier) 1911 we can use local stack structures for parameters. 1912 */ 1913 case T_CONNECT: { 1914 1915 if (result != kOTNoError) { 1916 TCP_MSG_1 ("Notifier: T_CONNECT returned an error"); 1917 ReturnEndpoint (epref, result, kConnectCompleteBit); 1918 return; 1919 } 1920 1921 err = OTRcvConnect (epref->ep, nil); 1922 1923 if (err != kOTNoError) 1924 TCP_MSG_1 ("Notifier: T_CONNECT - OTRcvConnect returned an error"); 1925 1926 /* We're done, one way or another... */ 1927 1928 ReturnEndpoint (epref, err, kConnectCompleteBit); 1929 1930 return; 1931 } 1932 1933 /* 1934 T_DATA: 1935 1936 The main rule for processing T_DATA's is to remember that once you have 1937 a T_DATA, you won't get another one until you have read to a kOTNoDataErr. 1938 The advanced rule is to remember that you could get another T_DATA 1939 during an OTRcv() which will eventually return kOTNoDataErr, presenting 1940 the application with a synchronization issue to be most careful about. 1941 */ 1942 case T_DATA: { 1943 /* 1944 Here we work around a small OpenTransport bug. 1945 It turns out, since this program does almost everything from inside the notifier, 1946 that during a T_UNBINDCOMPLETE we can put an EPInfo back into the idle list. 1947 If that notification is interrupted by a T_LISTEN at the notifier, we could 1948 end up starting a new connection on the endpoint before OT unwinds the stack 1949 out of the code which delivered the T_UNBINDCOMPLETE. OT has some specific 1950 code to protect against a T_DATA arriving before the T_PASSCON, but in this 1951 case it gets confused and the events arrive out of order. If we try to 1952 do an OTRcv() at this point we will get a kOTStateChangeErr because the endpoint 1953 is still locked by the earlier OTAccept call until the T_PASSCON is delivered 1954 to us. This is fairly benign and can be worked around easily. What we do 1955 is note that the T_PASSCON hasn't arrived yet and defer the call to ReadData() 1956 until it does. 1957 */ 1958 if (0 != OTAtomicSetBit (&epref->stateflags, kPassconBit)) { 1959 /* 1960 Because are are running completely inside notifiers, 1961 it is possible for a T_DATA to beat a T_PASSCON to us. 1962 We need to help OT out when this occurs and defer the 1963 data read until the T_PASSCON arrives. 1964 */ 1965 if (OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit)) 1966 ReadAllAndClose (epref); 1967 } 1968 return; 1969 } 1970 1971 /* 1972 T_GODATA: 1973 */ 1974 case T_GODATA: { 1975 return; 1976 } 1977 1978 /* 1979 T_ORDREL: 1980 1981 This event occurs when an orderly release has been received on the stream. 1982 */ 1983 case T_ORDREL: { 1984 1985 DoRcvOrderlyDisconnect (epref); 1986 1987 return; 1988 } 1989 1990 /* 1991 T_DISCONNECT: 1992 1993 Call DoRcvDisconnect to do all the work 1994 */ 1995 case T_DISCONNECT: { 1996 /* 1997 If the kWaitingForConnectBit is set, it means that the owning thread 1998 sits in a loop in fwsOpenStream, waiting for the connection request 1999 to complete. However, the peer didn't accept the connection, so we receive 2000 the disconnection request and return the reason for the disconnect 2001 to the owning thread in the epref->result field by calling DoRcvDisconnect. 2002 */ 2003 2004 if (OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)) 2005 if (!OTAtomicTestBit (&epref->stateflags, kWaitingForConnectBit) 2006 && !OTAtomicTestBit (&epref->stateflags, kWaitingForDisconnectBit)) { 2007 2008 /* 2009 Deal with it in the worker thread. We will get a kOTLookErr 2010 when we try to read or write. In that case we call OTLook, 2011 and proceed to process the event. 2012 */ 2013 return; 2014 } 2015 2016 DoRcvDisconnect (epref); 2017 2018 if (OTAtomicTestBit (&epref->stateflags, kWaitingForConnectBit)) { 2019 2020 OTAtomicClearBit (&epref->stateflags, kWaitingForConnectBit); 2021 2022 OTAtomicSetBit (&epref->completionflags, kConnectCompleteBit); 2023 } 2024 2025 return; 2026 } 2027 2028 /* 2029 T_DISCONNECTCOMPLETE: 2030 */ 2031 case T_DISCONNECTCOMPLETE: { 2032 2033 TCP_ASSERT_1 (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)); 2034 2035 if (result != kOTNoError) 2036 TCP_MSG_1 ("Notifier: T_DISCONNECT_COMPLETE returned an error"); 2037 2038 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 2039 2040 return; 2041 } 2042 2043 /* 2044 T_UNBINDCOMPLETE: 2045 2046 This event occurs on completion of an OTUnbind(). 2047 The endpoint is ready for reuse on a new inbound connection. 2048 Put it back into the queue of idle endpoints. 2049 Note that the OTLIFO structure has atomic queue and dequeue, 2050 which can be helpful for synchronization protection. 2051 */ 2052 case T_UNBINDCOMPLETE: { 2053 2054 TCP_ASSERT_1 (!OTAtomicTestBit (&epref->stateflags, kDontDisposeBit)); 2055 2056 if (kOTNoError == result) 2057 OTAtomicClearBit (&epref->stateflags, kBoundBit); 2058 2059 CheckUnbind (epref, result, kQueueIt); 2060 2061 return; 2062 } 2063 2064 /* 2065 T_GETPROTADDRCOMPLETE: 2066 2067 GetProtAddress call initiated by fwsNetEventsGetPeerAddress is complete, 2068 so go ahead and set the completion flag. 2069 */ 2070 case T_GETPROTADDRCOMPLETE: { 2071 OTAtomicSetBit (&epref->completionflags, kGetProtAddressBit); 2072 return; 2073 } 2074 2075 /* 2076 default: 2077 2078 There are events which we don't handle, but we don't expect to see 2079 any of them. When running in debugging mode while developing a program, 2080 we exit with an informational alert. Later, in the production version 2081 of the program, we ignore the event and try to keep running. 2082 */ 2083 default: { 2084 //char str[256]; 2085 //sprintf (str, "Notifier: unknown event (%08lx)", code); 2086 //TCP_MSG_1 (str); 2087 return; 2088 } 2089 2090 }/*switch (code)*/ 2091 2092 }/*Notifier*/ 2093 2094 // 2095 // EPOpen: 2096 // 2097 // A front end to OTAsyncOpenEndpoint. 2098 // A status bit is set so we know there is an open in progress. 2099 // It is cleared when the notifier gets a T_OPENCOMPLETE where the context 2100 // pointer is this EPInfo. Until that happens, this EPInfo can't be cleaned 2101 // up and released. 2102 // 2103 static OSStatus EPOpen (EndpointRecordRef epref, OTConfigurationRef cfg) { 2104 2105 OSStatus err; 2106 2107 // 2108 // Clear all old state bits and set the open in progress bit. 2109 // This doesn't need to be done atomicly because we are 2110 // single threaded on this endpoint at this point. 2111 // 2112 2113 OTAtomicSetBit (&epref->stateflags, kOpenInProgressBit); 2114 2115 #if TARGET_API_MAC_CARBON == 1 2116 err = OTAsyncOpenEndpointInContext (cfg, 0, nil, gNotifierUPP, epref, nil); //see OpenTransport.h line 1939 2117 2118 #else 2119 err = OTAsyncOpenEndpoint (cfg, 0, nil, &Notifier, epref); 2120 #endif 2121 2122 if (kOTNoError != err) 2123 OTAtomicClearBit (&epref->stateflags, kOpenInProgressBit); 2124 2125 return (err); 2126 }/*EPOpen*/ 2127 2128 2129 // 2130 // EPClose 2131 // 2132 // This routine is a front end to OTCloseProvider. Centralizing closing of 2133 // endpoints makes debugging and instrumentation easier. Also, since this 2134 // program uses Ack Sends to avoid data copies when doing OTSnd(), some special 2135 // care is required at close time. 2136 // 2137 static boolean EPClose (EndpointRecordRef epref) { 2138 2139 OSStatus err; 2140 2141 /* 2142 If an endpoint is still being opened, we can't close it yet. 2143 There is no way to cancel an OTAsyncOpenEndpoint, so we just 2144 have to wait for the T_OPENCOMPLETE event at the notifier. 2145 */ 2146 if (0 != OTAtomicTestBit (&epref->stateflags, kOpenInProgressBit)) 2147 return (false); 2148 2149 /* 2150 If the OTAsyncOpenEndpoint failed, the endpoint ref will be NULL, 2151 and we don't need to close it now. 2152 */ 2153 if (nil == epref->ep) 2154 return true; 2155 2156 err = OTCloseProvider (epref->ep); 2157 2158 epref->ep = NULL; 2159 2160 if (kOTNoError != noErr) 2161 TCP_MSG_1 ("EPClose: OTCloseProvider returned an error"); 2162 2163 return (true); 2164 }/*EPClose*/ 2165 2166 2167 // 2168 // Recycle: 2169 // 2170 // This routine shouldn't be necessary, but it is helpful to work around both 2171 // problems in OpenTransport and bugs in this program. Basically, whenever an 2172 // unexpected error occurs which shouldn't be fatal to the program, the EPInfo 2173 // is queued on the BrokenEP queue. When recycle is called, once per pass around 2174 // the event loop, it will attempt to close the associated endpoint and open 2175 // a new one to replace it using the same EPInfo structure. This process of 2176 // closing an errant endpoint and opening a replacement is probably the most 2177 // reliable way to make sure that this program and OpenTransport can recover 2178 // from unexpected happenings in a clean manner. 2179 // 2180 static void Recycle (ListenRecordRef listenref) { 2181 2182 OTLink* nomad; 2183 OTLIFO* brokenlist; 2184 EndpointRecordRef epref; 2185 OTConfigurationRef cfg; 2186 2187 if (nil != listenref) { 2188 brokenlist = &listenref->brokenEPs; 2189 cfg = listenref->masterconfig; 2190 } 2191 else { 2192 brokenlist = &sBrokenEPs; 2193 cfg = sMasterConfig; 2194 } 2195 2196 nomad = OTLIFOStealList (brokenlist); 2197 2198 while (nil != nomad) { 2199 2200 epref = OTGetLinkObject (nomad, tyendpointrecord, link); 2201 2202 nomad = nomad->fNext; 2203 2204 if (!EPClose (epref)) { 2205 2206 OTLIFOEnqueue (brokenlist, &epref->link); 2207 2208 continue; 2209 } 2210 2211 OTAtomicClearBit (&epref->stateflags, kBrokenBit); 2212 2213 InitEndpoint (epref, nil, listenref); 2214 2215 if (kOTNoError != EPOpen (epref, OTCloneConfiguration (cfg))) { 2216 2217 OTLIFOEnqueue (brokenlist, &epref->link); 2218 2219 continue; 2220 } 2221 2222 if (nil != listenref) { 2223 listenref->stats.ctbroken--; 2224 2225 listenref->stats.ctworking++; 2226 } 2227 else { 2228 epstats.ctbroken--; 2229 2230 epstats.ctworking++; 2231 } 2232 }/*while*/ 2233 }/*Recycle*/ 2234 2235 2236 static void ProcessWaitingEndpoints (ListenRecordRef listenref) { 2237 2238 boolean doLeave; 2239 OTLink* nomad; 2240 EndpointRecordRef epref; 2241 OTLIFO* waitinglist = (listenref != nil) ? &listenref->waitingEPs : &sWaitingEPs; 2242 2243 nomad = OTLIFOStealList (waitinglist); 2244 2245 while (nil != nomad) { 2246 2247 epref = OTGetLinkObject (nomad, tyendpointrecord, link); 2248 2249 nomad = nomad->fNext; 2250 2251 doLeave = OTEnterNotifier (epref->ep); 2252 2253 /*bundle*/ { 2254 2255 if (listenref != nil) { /*required to keep the stats accurate if CheckUnbind is called*/ 2256 listenref->stats.ctwaiting--; 2257 listenref->stats.ctworking++; 2258 } 2259 else { 2260 epstats.ctwaiting--; 2261 epstats.ctworking++; 2262 } 2263 2264 if (T_IDLE == OTGetEndpointState (epref->ep)) { 2265 2266 OTAtomicClearBit (&epref->stateflags, kDontDisposeBit); /*pass on responsibility to the Notifier*/ 2267 2268 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 2269 } 2270 else if (epref->timestamp + kTCPWaitSecsForOrderlyDisconnect < timenow()) 2271 DoSndDisconnect (epref); 2272 else { 2273 2274 if (listenref != nil) { 2275 listenref->stats.ctworking--; 2276 listenref->stats.ctwaiting++; 2277 } 2278 else { 2279 epstats.ctworking--; 2280 epstats.ctwaiting++; 2281 } 2282 2283 OTLIFOEnqueue (waitinglist, &epref->link); /*try again later*/ 2284 } 2285 } 2286 2287 if (doLeave) 2288 OTLeaveNotifier (epref->ep); 2289 }/*while*/ 2290 2291 }/*ProcessWaitingEndpoints*/ 2292 2293 2294 static void gettcperrorstring (int errcode, bigstring bs) { 2295 2296 int ixtcperr = errcode; 2297 2298 if (IsEError (errcode)) { 2299 2300 ixtcperr = OSStatus2E (errcode); 2301 2302 copystring (stdcliberrorstrings [ixtcperr], bs); //handles nil source 2303 2304 if (!isemptystring (bs)) { 2305 2306 pushchar ('.', bs); 2307 2308 return; 2309 } 2310 } 2311 2312 if (IsXTIError (errcode)) { 2313 2314 ixtcperr = OSStatus2XTI (errcode); 2315 2316 copystring (xtierrorstrings [ixtcperr], bs); //handles nil source 2317 2318 if (!isemptystring (bs)) { 2319 2320 pushchar ('.', bs); 2321 2322 return; 2323 } 2324 } 2325 2326 getsystemerrorstring (errcode, bs); 2327 } /*gettcperrorstring*/ 2328 2329 2330 static void plainneterror (bigstring bs) { 2331 2332 /* 2333 6.1b15 AR 2334 */ 2335 2336 bigstring errbs; 2337 2338 copystring (bs, errbs); 2339 2340 nullterminate (errbs); 2341 2342 TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs))); 2343 TCPERRORWRITEMSG (); 2344 2345 langerrormessage (bs); 2346 } /*neterror*/ 2347 2348 2349 static void closedunexpectedlyerror (char * cannot) { 2350 2351 /* 2352 6.2b17 AR 2353 */ 2354 2355 bigstring bs; 2356 char prestring[256]; 2357 2358 wsprintf (prestring, "Can't %s because the TCP connection was closed unexpectedly.", cannot); 2359 copyctopstring (prestring, bs); 2360 2361 plainneterror (bs); 2362 } /*neterror*/ 2363 2364 2365 static void neterror (char * cannot, long errcode) { 2366 2367 bigstring bs; 2368 bigstring errbs; 2369 char prestring[256]; 2370 2371 wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode); 2372 copyctopstring (prestring, errbs); 2373 2374 gettcperrorstring (errcode, bs); 2375 2376 if (!isemptystring (bs)) { 2377 2378 pushstring ("\x03" " - ", errbs); 2379 2380 pushstring (bs, errbs); 2381 } 2382 else { 2383 pushchar ('.', errbs); 2384 } 2385 2386 nullterminate (errbs); 2387 2388 TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs))); 2389 TCPERRORWRITEMSG (); 2390 2391 langerrormessage (errbs); 2392 } /*neterror*/ 2393 2394 #if 0 2395 2396 static void dnserror (char *cannot, long errcode) { 2397 2398 if (errcode == kOTBadNameErr) { /* Host not found */ 2399 2400 bigstring bs; 2401 bigstring errbs; 2402 char prestring[256]; 2403 2404 wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode); 2405 copyctopstring (prestring, errbs); 2406 2407 copystring (dnserrorstrings [1], bs); //handles nil source 2408 2409 pushstring ("\x03" " - ", errbs); 2410 2411 pushstring (bs, errbs); 2412 2413 pushchar ('.', errbs); 2414 2415 nullterminate (errbs); 2416 2417 TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s", stringbaseaddress(errbs))); 2418 TCPERRORWRITEMSG (); 2419 2420 langerrormessage (errbs); 2421 2422 return; 2423 } 2424 2425 neterror (cannot, errcode); 2426 } 2427 2428 #endif 2429 2430 2431 static void intneterror (long errcode) { 2432 bigstring bs; 2433 2434 if (errcode == INTNETERROR_INVALIDSTREAM) 2435 copyctopstring ("Invalid stream", bs); 2436 else 2437 copyctopstring ("Unknown stream error", bs); 2438 2439 langerrormessage (bs); 2440 } /*intneterror*/ 2441 2442 2443 static boolean fwsbackgroundtask (void) { 2444 2445 boolean fl = true; 2446 2447 if (inmainthread ()) { 2448 EventRecord ev; 2449 short mask = osMask|activMask|mDownMask|keyDownMask; //|highLevelEventMask|updateMask 2450 long sleepTime = 6; // 1/10 of a second by default 2451 2452 if (WaitNextEvent (mask, &ev, sleepTime, nil)) /*migh return false to indicate a null event, but that's not an error*/ 2453 fl = shellprocessevent (&ev); 2454 } 2455 else 2456 fl = langbackgroundtask (true); 2457 2458 return (fl); 2459 }/*fwsbackgroundtask*/ 2460 2461 2462 static boolean fwsNetEventLaunch (struct hostData *data) { 2463 2464 /* 2465 Initialize the NetEvents system 2466 2467 5.0.2b5 dmb: added hostData parameter and GUSI support to handle threading 2468 */ 2469 2470 #pragma unused (data) 2471 2472 if (!frontierWinSockLoaded) { 2473 2474 //Code change by Timothy Paustian Monday, June 26, 2000 3:55:47 PM 2475 //OpenTransport takes a context for all of its calls. Applications 2476 //do not need this, so pass nil 2477 OSStatus err = noErr; 2478 2479 #if TARGET_API_MAC_CARBON ==1 2480 err = InitOpenTransportInContext(kInitOTForApplicationMask, nil); 2481 #else 2482 err = InitOpenTransport (); 2483 #endif 2484 2485 if (err != kOTNoError) { 2486 neterror ("initialize Open Transport", err); 2487 return (false); 2488 } 2489 2490 err = Gestalt (sOTVersionSelector, (long*) &sOTVersion); 2491 2492 if (err || (sOTVersion < kOTVersion111)) { 2493 plainneterror ("\x23" "Please install Open Transport 1.1.1 or later."); 2494 return (false); 2495 } 2496 2497 clearbytes (&epstats, sizeof (epstats)); 2498 2499 sListenList.fHead = nil; 2500 sEndpointList.fHead = nil; 2501 2502 sIdleEPs.fHead = nil; 2503 sBrokenEPs.fHead = nil; 2504 sWaitingEPs.fHead = nil; 2505 2506 sMasterConfig = OTCreateConfiguration ("tcp"); 2507 2508 #if TARGET_API_MAC_CARBON == 1 2509 gThreadEntryCallback = NewThreadEntryUPP (fwsacceptingthreadmain); 2510 2511 if(gThreadEntryCallback == nil) { 2512 memoryerror (); 2513 return (false); 2514 } 2515 2516 gListenNotifierUPP = NewOTNotifyUPP(ListenNotifier); 2517 2518 if(gListenNotifierUPP == nil) { 2519 memoryerror (); 2520 return (false); 2521 } 2522 2523 gListSearchUPP = NewOTListSearchUPP(listenlinkvisit); 2524 2525 if(gListSearchUPP == nil) { 2526 memoryerror (); 2527 return (false); 2528 } 2529 2530 gNotifierUPP = NewOTNotifyUPP(Notifier); 2531 2532 if(gNotifierUPP == nil) { 2533 memoryerror (); 2534 return (false); 2535 } 2536 2537 gDNRNotifierUPP = NewOTNotifyUPP (DNRNotifier); 2538 2539 if (gDNRNotifierUPP == nil) { 2540 memoryerror (); 2541 return (false); 2542 } 2543 2544 gEndListSearchUPP = NewOTListSearchUPP(endpointlinkvisit); 2545 2546 if(gEndListSearchUPP == nil) { 2547 memoryerror (); 2548 return (false); 2549 } 2550 2551 #endif 2552 } 2553 2554 frontierWinSockLoaded = true; 2555 2556 ++frontierWinSockCount; 2557 2558 return (true); 2559 } /*fwsNetEventLaunch*/ 2560 2561 2562 boolean fwsNetEventQuit (void) { 2563 2564 frontierWinSockCount = 0; 2565 2566 TCPTRACKERCLOSE(); 2567 2568 if (frontierWinSockLoaded) { 2569 frontierWinSockLoaded = false; 2570 2571 //Code change by Timothy Paustian Sunday, May 7, 2000 9:29:38 PM 2572 //Changed to Opaque call for Carbon 2573 #if TARGET_API_MAC_CARBON == 1 2574 2575 //get rid of our UPPs 2576 DisposeOTNotifyUPP(gNotifierUPP); 2577 gNotifierUPP = nil; 2578 DisposeOTNotifyUPP (gDNRNotifierUPP); 2579 DisposeOTListSearchUPP(gEndListSearchUPP); 2580 gEndListSearchUPP = nil; 2581 DisposeOTListSearchUPP(gListSearchUPP); 2582 gListSearchUPP = nil; 2583 DisposeOTNotifyUPP(gListenNotifierUPP); 2584 gListenNotifierUPP = nil; 2585 DisposeThreadEntryUPP(gThreadEntryCallback); 2586 gThreadEntryCallback = nil; 2587 2588 //This has to be switched to NULL when we link against the carbon lib. 2589 CloseOpenTransportInContext(nil); 2590 #else 2591 CloseOpenTransport (); 2592 #endif 2593 2594 return (true); 2595 } 2596 2597 return (false); 2598 } /*fwsNetEventShutDown*/ 2599 2600 2601 boolean fwsNetEventAddressDecode (unsigned long addr, bigstring IPaddr) { 2602 2603 /* Convert an address (4 byte) into a dotted IP address */ 2604 2605 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 2606 return (false); 2607 2608 setstringlength (IPaddr, 0); 2609 2610 OTInetHostToString (addr, stringbaseaddress (IPaddr)); 2611 2612 setstringlength (IPaddr, strlen (stringbaseaddress (IPaddr))); 2613 2614 return (true); 2615 } /*fwsNetEventAddressDecode*/ 2616 2617 2618 boolean fwsNetEventAddressEncode (bigstring IPaddr, unsigned long * addr) { 2619 2620 /* Convert a dotted IP address into an address (4 byte) */ 2621 2622 InetHost host; 2623 OSStatus err; 2624 2625 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 2626 return (false); 2627 2628 nullterminate (IPaddr); 2629 2630 err = OTInetStringToHost (stringbaseaddress (IPaddr), &host); 2631 2632 if (err != kOTNoError) { 2633 2634 langparamerror (cantencodeaddress, IPaddr); 2635 2636 return (false); 2637 } 2638 2639 *addr = host; 2640 2641 return (true); 2642 } /*fwsNetEventAddressEncode*/ 2643 2644 2645 boolean fwsNetEventAddressToName (unsigned long addr, bigstring domainName) { 2646 2647 /* 2648 Convert an address (4 byte) into a domain name 2649 */ 2650 2651 dnsquery query; 2652 InetSvcRef inetservice; 2653 OSStatus err; 2654 2655 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 2656 return (false); 2657 2658 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventAddressToName at line %d. Address: %ld.", __LINE__, addr)); 2659 TCPWRITEMSG(); 2660 2661 /*open dns service provider*/ 2662 2663 #if TARGET_API_MAC_CARBON == 1 2664 inetservice = OTOpenInternetServicesInContext (kDefaultInternetServicesPath, 0L, &err, nil); 2665 #else 2666 inetservice = OTOpenInternetServices (kDefaultInternetServicesPath, 0L, &err); 2667 #endif 2668 2669 if (err != kOTNoError) { 2670 neterror("convert address", err); 2671 return (false); 2672 } 2673 2674 /*install the notifier*/ 2675 2676 OTMemzero (&query, sizeof (query)); 2677 2678 #if TARGET_API_MAC_CARBON == 1 2679 err = OTInstallNotifier (inetservice, gDNRNotifierUPP, &query); 2680 #else 2681 err = OTInstallNotifier (inetservice, &DNRNotifier, &query); 2682 #endif 2683 2684 if (err != kOTNoError) 2685 goto exit; 2686 2687 /*switch to async mode*/ 2688 2689 err = OTSetAsynchronous (inetservice); 2690 2691 if (err != kOTNoError) 2692 goto exit2; 2693 2694 /*fire off query*/ 2695 2696 err = OTInetAddressToName (inetservice, (InetHost) addr, stringbaseaddress (domainName)); 2697 2698 if (err != kOTNoError) 2699 goto exit2; 2700 2701 /*spin until query completes*/ 2702 2703 while (0 == (query.flags & fcomplete)) 2704 YieldToAnyThread (); 2705 2706 /*clean up*/ 2707 2708 #if TARGET_API_MAC_CARBON == 1 2709 OTRemoveNotifier (inetservice); 2710 #endif 2711 2712 OTCloseProvider (inetservice); 2713 2714 /*retrieve query result and return*/ 2715 2716 if (query.result != kOTNoError) { 2717 neterror ("convert address", query.result); 2718 return (false); 2719 } 2720 2721 setstringlength (domainName, strlen (stringbaseaddress (domainName))); 2722 2723 poptrailingchars (domainName, '.'); 2724 2725 TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventAddressToName at line %d. Domain name: %s.", __LINE__, stringbaseaddress (domainName))); 2726 TCPWRITEMSG(); 2727 2728 return (true); 2729 2730 /*error handling*/ 2731 2732 exit2: 2733 2734 #if TARGET_API_MAC_CARBON == 1 2735 OTRemoveNotifier (inetservice); 2736 #endif 2737 2738 exit: 2739 2740 OTCloseProvider (inetservice); 2741 2742 neterror ("convert name", err); 2743 2744 return (false); 2745 } /*fwsNetEventAddressToName*/ 2746 2747 2748 boolean fwsNetEventNameToAddress (bigstring domainName, unsigned long * addr) { 2749 2750 /* 2751 Convert a domain name into an address (4 byte) 2752 2753 7.0b44 PBS: OS X -- make the domain name all lower to prevent an error. 2754 */ 2755 2756 char sysstring[256]; 2757 dnsquery query; 2758 InetHostInfo hostinfo; 2759 InetSvcRef inetservice; 2760 OSStatus err; 2761 2762 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 2763 return (false); 2764 2765 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventNameToAddress at line %d. Domain name: %s.", __LINE__, stringbaseaddress (domainName))); 2766 TCPWRITEMSG(); 2767 2768 #if TARGET_API_MAC_CARBON == 1 2769 2770 alllower (domainName); /*7.0b44 PBS: OS X may return an error otherwise.*/ 2771 2772 #endif 2773 2774 copyptocstring (domainName, sysstring); 2775 2776 /*open dns service provider*/ 2777 2778 #if TARGET_API_MAC_CARBON == 1 2779 inetservice = OTOpenInternetServicesInContext (kDefaultInternetServicesPath, 0L, &err, nil); 2780 #else 2781 inetservice = OTOpenInternetServices (kDefaultInternetServicesPath, 0L, &err); 2782 #endif 2783 2784 if (err != kOTNoError) { 2785 neterror("convert name", err); 2786 return (false); 2787 } 2788 2789 /*install the notifier*/ 2790 2791 OTMemzero (&query, sizeof (query)); 2792 2793 #if TARGET_API_MAC_CARBON == 1 2794 err = OTInstallNotifier (inetservice, gDNRNotifierUPP, &query); 2795 #else 2796 err = OTInstallNotifier (inetservice, &DNRNotifier, &query); 2797 #endif 2798 2799 if (err != kOTNoError) 2800 goto exit; 2801 2802 /*switch to async mode*/ 2803 2804 err = OTSetAsynchronous (inetservice); 2805 2806 if (err != kOTNoError) 2807 goto exit; 2808 2809 /*fire off query*/ 2810 2811 err = OTInetStringToAddress (inetservice, sysstring, &hostinfo); 2812 2813 if (err != kOTNoError) 2814 goto exit; 2815 2816 /*spin until query completes*/ 2817 2818 while (0 == (query.flags & fcomplete)) 2819 YieldToAnyThread (); 2820 2821 /*clean up*/ 2822 2823 OTCloseProvider (inetservice); 2824 2825 /*retrieve query result and return*/ 2826 2827 if (query.result != kOTNoError) { 2828 neterror ("convert name", query.result); 2829 return (false); 2830 } 2831 2832 *addr = hostinfo.addrs[0]; 2833 2834 TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventNameToAddress at line %d. Address: %08lx.", __LINE__, *addr)); 2835 TCPWRITEMSG(); 2836 2837 return (true); 2838 2839 /*error handling*/ 2840 2841 exit: 2842 2843 OTCloseProvider (inetservice); 2844 2845 neterror ("convert name", err); 2846 2847 return (false); 2848 } /*fwsNetEventNameToAddress*/ 2849 2850 2851 boolean fwsNetEventMyAddress (unsigned long * addr) { 2852 2853 /* Get the hosts address */ 2854 2855 OSStatus err; 2856 OSStatus junk; 2857 EndpointRef dummyEP; 2858 InetInterfaceInfo info; 2859 Boolean fl = false; 2860 TEndpointInfo epInfo; 2861 2862 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 2863 return (false); 2864 2865 //Code change by Timothy Paustian Monday, June 26, 2000 4:04:28 PM 2866 // 2867 #if TARGET_API_MAC_CARBON == 1 2868 dummyEP = OTOpenEndpointInContext (OTCreateConfiguration ("tcp"), 0, &epInfo, &err, nil); 2869 #else 2870 dummyEP = OTOpenEndpoint (OTCreateConfiguration ("tcp"), 0, &epInfo, &err); 2871 #endif 2872 2873 if (err != kOTNoError) { 2874 neterror("get local address", err); 2875 return (false); 2876 } 2877 2878 err = OTInetGetInterfaceInfo (&info, 0); 2879 2880 if (err == kOTNoError) { 2881 2882 *addr = info.fAddress; 2883 2884 fl = true; 2885 } 2886 else 2887 neterror("get local address", err); 2888 2889 if (dummyEP != nil) { 2890 junk = OTCloseProvider(dummyEP); 2891 OTAssert("fwsNetEventMyAddress: Failed closing dummy endpoint", junk == kOTNoError); 2892 } 2893 2894 return (fl); 2895 } /*fwsNetEventMyAddress*/ 2896 2897 2898 static boolean fwsgetcallbackcodetree (bigstring bs, Handle *htree) { 2899 2900 Handle htext; 2901 boolean fl; 2902 unsigned long savelines; 2903 unsigned short savechars; 2904 hdltreenode hmodule = nil; 2905 2906 if (!newtexthandle (bs, &htext)) 2907 return (false); 2908 2909 savelines = ctscanlines; 2910 2911 savechars = ctscanchars; 2912 2913 fl = langcompiletext (htext, false, &hmodule); /*always disposes htext*/ 2914 2915 ctscanlines = savelines; 2916 2917 ctscanchars = savechars; 2918 2919 if (!fl) 2920 return (false); 2921 2922 fl = langpacktree ((**hmodule).param1, htree); /*make a copy of the sub-tree*/ 2923 2924 langdisposetree (hmodule); 2925 2926 return (fl); 2927 } /*fwsgetcallbackcodetree*/ 2928 2929 2930 static boolean fwsnewprocess (hdltreenode hcode, bigstring bsname, hdlprocessrecord *hprocess) { 2931 2932 register hdlprocessrecord hp; 2933 hdlerrorstack herrorstack; 2934 hdltablestack htablestack; 2935 tyerrorrecord item; 2936 2937 if (!newclearhandle (sizeof (typrocessrecord), (Handle *) hprocess)) 2938 return (false); 2939 2940 hp = *hprocess; /*copy into register*/ 2941 2942 if (!newclearhandle (sizeof (tyerrorstack), (Handle *) &herrorstack)) { 2943 2944 disposehandle ((Handle) hp); 2945 2946 return (false); 2947 } 2948 2949 if (!newclearhandle (sizeof (tytablestack), (Handle *) &htablestack)) { 2950 2951 disposehandle ((Handle) hp); 2952 2953 disposehandle ((Handle) herrorstack); 2954 2955 return (false); 2956 } 2957 2958 (**hp).hcode = hcode; 2959 2960 (**hp).floneshot = true; 2961 2962 (**hp).errormessagecallback = &langerrordialog; 2963 2964 (**hp).debugerrormessagecallback = (langerrormessagecallback) &truenoop; 2965 2966 (**hp).htablestack = htablestack; 2967 2968 (**hp).herrorstack = herrorstack; 2969 2970 (**hp).processstartedroutine = (langvoidcallback) &truenoop; 2971 2972 (**hp).processkilledroutine = (langvoidcallback) &truenoop; 2973 2974 item.errorcallback = nil; 2975 2976 item.errorline = 0; 2977 2978 item.errorchar = 0; 2979 2980 item.errorrefcon = 0; 2981 2982 #ifdef flnewfeatures 2983 item.profilebase = 0; 2984 #endif 2985 2986 (**herrorstack).stack [(**herrorstack).toperror++] = item; 2987 2988 copystring (bsname, (**hp).bsname); 2989 2990 return (true); 2991 } /*newprocess*/ 2992 2993 2994 static boolean fwsruncallback (EndpointRecordRef epref) { 2995 2996 hdltreenode hcallbackaddress; 2997 hdltreenode hfunctioncall; 2998 hdltreenode hcode; 2999 hdltreenode hparam1; 3000 hdltreenode hparam2; 3001 tyvaluerecord val; 3002 hdlprocessrecord hprocess; 3003 Handle h; 3004 3005 ListenRecordRef listenref = epref->listener; 3006 long refcon = listenref->refcon; 3007 Handle hcallbacktree = listenref->hcallbacktree; 3008 bigstring bsname; 3009 3010 copystring (listenref->callback, bsname); 3011 3012 //build code tree 3013 3014 if (!copyhandle (hcallbacktree, &h)) 3015 return (false); 3016 3017 if (!langunpacktree (h, &hcallbackaddress)) 3018 return (false); 3019 3020 setlongvalue ((long) epref, &val); 3021 3022 if (!newconstnode (val, &hparam1)) { 3023 langdisposetree (hcallbackaddress); 3024 return (false); 3025 } 3026 3027 setlongvalue (refcon, &val); 3028 3029 if (!newconstnode (val, &hparam2)) { 3030 langdisposetree (hcallbackaddress); 3031 langdisposetree (hparam1); 3032 return (false); 3033 } 3034 3035 pushlastlink (hparam2, hparam1); 3036 3037 if (!pushbinaryoperation (functionop, hcallbackaddress, hparam1, &hfunctioncall)) 3038 return (false); 3039 3040 if (!pushbinaryoperation (moduleop, hfunctioncall, nil, &hcode)) 3041 return (false); 3042 3043 //create new process 3044 3045 if (!fwsnewprocess (hcode, bsname, &hprocess)) { 3046 langdisposetree (hcode); 3047 return (false); 3048 } 3049 3050 //add new process 3051 3052 return (addprocess (hprocess)); 3053 }/*fwsruncallback*/ 3054 3055 3056 static long fwsprocesspendingconnections (ListenRecordRef listenref) { 3057 3058 OTLink* nomad = OTLIFOStealList (&listenref->readyEPs); 3059 OTLink* next; 3060 EndpointRecordRef epref; 3061 long ct = 0; 3062 boolean fl; 3063 3064 while (nil != nomad) { 3065 3066 next = nomad->fNext; 3067 3068 epref = OTGetLinkObject (nomad, tyendpointrecord, link); 3069 3070 OTAddFirst (&sEndpointList, &epref->validationlink); 3071 3072 epref->typeID = SOCKTYPE_OPEN; 3073 3074 TCPprintf (wsprintf (TCPmsg, "In fwsacceptpendingconnections at line %d. Accepted new connection #%08ld on listener %08lx: %s (%08lx, %ld).", 3075 __LINE__, ct, (long) listenref, stringbaseaddress (listenref->callback), (long) epref, listenref->refcon)); 3076 TCPWRITEMSG(); 3077 3078 fl = fwsruncallback (epref); 3079 3080 TCP_ASSERT_1 (fl); 3081 3082 nomad = next; 3083 3084 ct++; 3085 }/*while*/ 3086 3087 return (ct); 3088 }/*fwsprocesspendingconnections*/ 3089 3090 3091 static void fwscleanuplistener (ListenRecordRef listenref) { 3092 3093 EndpointRecordRef epref; 3094 OTLink* nomad; 3095 OTLink* next; 3096 long ctepsclosed = 0; 3097 3098 /* Process pending connections for one last time */ 3099 3100 fwsprocesspendingconnections (listenref); /* listenref->readyEPs is now empty and remains empty */ 3101 3102 /* Now enter a loop in which we close idle and broken eps until we've closed all dependent acceptors */ 3103 3104 while (ctepsclosed < listenref->maxdepth) { 3105 3106 YieldToAnyThread (); 3107 3108 nomad = OTLIFOStealList (&listenref->idleEPs); 3109 3110 while (nomad != nil) { 3111 3112 next = nomad->fNext; 3113 3114 epref = OTGetLinkObject (nomad, tyendpointrecord, link); 3115 3116 nomad = next; 3117 3118 if (EPClose (epref)) { 3119 3120 ++ctepsclosed; 3121 3122 listenref->stats.ctidle--; 3123 } 3124 else { 3125 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link); 3126 3127 listenref->stats.ctidle--; 3128 3129 listenref->stats.ctbroken++; 3130 } 3131 }/*while*/ 3132 3133 YieldToAnyThread (); 3134 3135 nomad = OTLIFOStealList (&listenref->brokenEPs); 3136 3137 while (nomad != nil) { 3138 3139 next = nomad->fNext; 3140 3141 epref = OTGetLinkObject (nomad, tyendpointrecord, link); 3142 3143 nomad = next; 3144 3145 if (EPClose (epref)) { 3146 3147 ++ctepsclosed; 3148 3149 listenref->stats.ctbroken--; 3150 } 3151 else 3152 OTLIFOEnqueue (&listenref->brokenEPs, &epref->link); 3153 }/*while*/ 3154 3155 }/*while*/ 3156 3157 assert (listenref->stats.ctbroken == 0); 3158 3159 assert (listenref->stats.ctidle == 0); 3160 3161 assert (listenref->stats.ctworking == 0); 3162 3163 /* Finally, dispose all allocated memory structures */ 3164 3165 OTDestroyConfiguration (listenref->masterconfig); 3166 3167 disposehandle (listenref->hcallbacktree); 3168 3169 DisposePtr ((Ptr) listenref->acceptors); 3170 3171 DisposePtr ((Ptr) listenref); 3172 3173 return; 3174 }/*fwscleanuplistener*/ 3175 3176 3177 static void *fwsacceptingthreadmain (void *param) { 3178 3179 /* 3180 We sit in a loop waiting for connections that are ready to be picked up and sent to the daemon. 3181 We are also responsible for shutting down the listener and all dependent endpoints. 3182 */ 3183 3184 ListenRecordRef listenref = (ListenRecordRef) param; 3185 OSStatus err; 3186 long ct = 0; 3187 3188 TCPTRACKERIN ("fwsacceptingthreadmain", __LINE__, nil, listenref); 3189 3190 while (SOCKTYPE_LISTENSTOPPED != listenref->typeID) { 3191 3192 ct += fwsprocesspendingconnections (listenref); 3193 3194 ProcessWaitingEndpoints (listenref); 3195 3196 Recycle (listenref); 3197 3198 if (listenref->fllistenpending) 3199 EnterListenAccept (listenref); 3200 3201 err = YieldToAnyThread (); 3202 3203 TCP_ASSERT_1 (err == kOTNoError); 3204 }/*while*/ 3205 3206 TCPprintf (wsprintf (TCPmsg, "In fwsacceptingthreadmain at line %d, broke out of loop after accepting %ld connections on listener %08lx. Now starting clean-up.", 3207 __LINE__, ct, (long) listenref)); 3208 TCPWRITEMSG(); 3209 3210 fwscleanuplistener (listenref); 3211 3212 TCPprintf (wsprintf (TCPmsg, "Exiting fwsacceptingthreadmain at line %d.", __LINE__)); 3213 TCPWRITEMSG(); 3214 3215 return (nil); 3216 }/*fwsacceptingthreadmain*/ 3217 3218 3219 static boolean fwslaunchacceptingthread (ListenRecordRef listenref) { 3220 3221 OSStatus err; 3222 3223 #if TARGET_API_MAC_CARBON == 1 3224 err = NewThread (kCooperativeThread, gThreadEntryCallback, (void *)listenref, 0, kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, &listenref->idthread); 3225 #else 3226 err = NewThread (kCooperativeThread, fwsacceptingthreadmain, (void *)listenref, 0, kUsePremadeThread + kCreateIfNeeded + kFPUNotNeeded, nil, &listenref->idthread); 3227 #endif 3228 3229 if (kOTNoError != err) { 3230 oserror (err); 3231 return (false); 3232 } 3233 3234 return (true); 3235 }/*fwslaunchacceptingthread*/ 3236 3237 3238 boolean fwsNetEventListenStream (unsigned long port, long depth, bigstring callback, unsigned long refcon, unsigned long * stream, unsigned long ipaddr, long hdatabase) { 3239 3240 /* Set up a listner on a port */ 3241 3242 Handle hcallbacktree = nil; 3243 OSStatus err; 3244 TBind bindReq; 3245 InetAddress ipAddress; 3246 ListenRecordRef listenref = nil; 3247 EndpointRecordRef epref = nil; 3248 TOptMgmt optReq; 3249 TOption opt; 3250 long i; 3251 3252 nullterminate (callback); 3253 TCPprintf(wsprintf(TCPmsg, "Entering fwsNetEventListenStream at line %d. Port = %ld, Depth = %ld, Refcon = %ld, Callback = %s.", __LINE__, port, depth, refcon, stringbaseaddress(callback))); 3254 TCPWRITEMSG (); 3255 3256 /* Initialize Open Transport and static data structures */ 3257 3258 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3259 return (false); 3260 3261 /* Compile and pack a code tree for the address of the daemon script */ 3262 3263 if (!fwsgetcallbackcodetree (callback, &hcallbacktree)) 3264 return (false); 3265 3266 /* Allocate and clear memory for the listener */ 3267 3268 listenref = (ListenRecordRef) NewPtr (sizeof (tylistenrecord)); 3269 3270 if (listenref == nil) { 3271 memoryerror (); 3272 goto exit; 3273 } 3274 3275 OTMemzero (listenref, sizeof (tylistenrecord)); 3276 3277 /* Initialize further status fields */ 3278 copystring (callback, listenref->callback); 3279 3280 listenref->maxdepth = depth; 3281 3282 listenref->refcon = refcon; 3283 3284 listenref->hcallbacktree = hcallbacktree; 3285 3286 listenref->hdatabase = (hdldatabaserecord) hdatabase; 3287 3288 /* Open synchronous listener and set to blocking mode */ 3289 3290 #if TARGET_API_MAC_CARBON == 1 3291 listenref->ep = OTOpenEndpointInContext (OTCreateConfiguration ("tilisten,tcp"), nil, nil, &err, nil); 3292 #else 3293 listenref->ep = OTOpenEndpoint (OTCreateConfiguration ("tilisten,tcp"), nil, nil, &err); 3294 #endif 3295 3296 if (kOTInvalidEndpointRef == listenref->ep || kOTNoError != err) { 3297 neterror ("create listen stream", err); 3298 goto exit; 3299 } 3300 3301 err = OTSetBlocking (listenref->ep); 3302 3303 if (kOTNoError != err) { 3304 OSStatus status; 3305 status = OTCloseProvider (listenref->ep); 3306 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3307 neterror ("set listen stream to blocking mode", err); 3308 goto exit; 3309 } 3310 3311 /* Option Management - Turn on ip_reuseaddr so we don't have port conflicts in general. */ 3312 3313 optReq.flags = T_NEGOTIATE; 3314 optReq.opt.len = kOTFourByteOptionSize; 3315 optReq.opt.buf = (unsigned char *) &opt; 3316 3317 opt.len = sizeof (TOption); 3318 opt.level = INET_IP; 3319 opt.name = kIP_REUSEADDR; 3320 opt.status = 0; 3321 opt.value[0] = 1; 3322 3323 err = OTOptionManagement (listenref->ep, &optReq, nil); 3324 3325 if (kOTNoError != err) { 3326 OSStatus status; 3327 status = OTCloseProvider (listenref->ep); 3328 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3329 neterror ("set IP_REUSEADDR option on listen stream", err); 3330 goto exit; 3331 } 3332 3333 /* Bind listener to specified address or default address if ipaddr is nil */ 3334 3335 OTInitInetAddress (&ipAddress, port, ipaddr); 3336 3337 bindReq.addr.buf = (UInt8 *) &ipAddress; 3338 3339 bindReq.addr.len = sizeof (ipAddress); 3340 3341 bindReq.qlen = depth; 3342 3343 err = OTBind (listenref->ep, &bindReq, nil); 3344 3345 if (kOTNoError != err) { 3346 OSStatus status; 3347 status = OTCloseProvider (listenref->ep); 3348 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3349 neterror ("bind listen stream", err); 3350 goto exit; 3351 } 3352 3353 /* Install a notifier for the listener and switch to async mode */ 3354 #if TARGET_API_MAC_CARBON == 1 3355 err = OTInstallNotifier (listenref->ep, gListenNotifierUPP, (void *) listenref); 3356 #else 3357 err = OTInstallNotifier (listenref->ep, &ListenNotifier, (void *) listenref); 3358 #endif 3359 3360 if (kOTNoError != err) { 3361 OSStatus status; 3362 status = OTCloseProvider (listenref->ep); 3363 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3364 neterror ("install notifier for listen stream", err); 3365 goto exit; 3366 } 3367 3368 err = OTSetAsynchronous (listenref->ep); 3369 3370 if (kOTNoError != err) { 3371 OSStatus status; 3372 status = OTCloseProvider (listenref->ep); 3373 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3374 neterror ("set listen stream to async mode", err); 3375 goto exit; 3376 } 3377 3378 /* Push the listener on the global list of listeners, so we can close it on shutdown */ 3379 3380 OTAddFirst (&sListenList, &listenref->validationlink); 3381 3382 /* Launch the worker thread that manages incoming connections */ 3383 3384 if (!fwslaunchacceptingthread (listenref)) { /* takes care of closing ep and cleaning up, even if we fail further down */ 3385 OSStatus status; 3386 status = OTCloseProvider (listenref->ep); 3387 OTAssert ("fwsNetEventListenStream: Could not close listener", status == kOTNoError); 3388 goto exit; 3389 } 3390 3391 /* Create configuration to be cloned for accepters */ 3392 3393 listenref->masterconfig = OTCreateConfiguration ("tcp"); 3394 3395 if (kOTInvalidConfigurationPtr == listenref->masterconfig || kOTNoMemoryConfigurationPtr == listenref->masterconfig) { 3396 memoryerror (); 3397 goto exit; 3398 } 3399 3400 /* Allocate and clear memory for block of acceptors */ 3401 3402 listenref->acceptors = (EndpointRecordRef) NewPtr (depth * sizeof (tyendpointrecord)); 3403 3404 if (listenref->acceptors == nil) { 3405 memoryerror (); 3406 goto exit; 3407 } 3408 3409 listenref->stats.cttotal = depth; 3410 3411 OTMemzero (listenref->acceptors, depth * sizeof (tyendpointrecord)); 3412 3413 /* Loop over acceptors and open them asynchronously one by one */ 3414 for (epref = listenref->acceptors, i = 0; i < depth; epref++, i++) { 3415 3416 epref->listener = listenref; 3417 3418 err = EPOpen (epref, OTCloneConfiguration (listenref->masterconfig)); 3419 3420 if (kOTNoError != err) { 3421 neterror ("create worker streams for listen stream", err); 3422 goto exit; 3423 } 3424 3425 listenref->stats.ctworking++; 3426 } 3427 3428 /* Signal to the worker thread that we are ready to go */ 3429 3430 listenref->typeID = SOCKTYPE_LISTENING; 3431 3432 /* Return to caller */ 3433 3434 *stream = (long) listenref; 3435 3436 TCPTRACKEROUT ("fwsNetEventListenStream", __LINE__, nil, listenref); 3437 3438 return (true); 3439 3440 exit: 3441 3442 //disposehandle (hcallbacktree); 3443 3444 //neterror ("set up listen stream", err); 3445 3446 return (false); 3447 } /*fwsNetEventListenStream*/ 3448 3449 3450 boolean fwsNetEventCloseListen (unsigned long stream) { 3451 3452 /* 3453 Close a listen and delete associated data 3454 3455 7.0b35 PBS: pass gListSearchUPP to OTFindAndRemoveLink. 3456 */ 3457 3458 ListenRecordRef listenref = (ListenRecordRef) stream; 3459 OSStatus err; 3460 3461 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3462 return (false); 3463 3464 TCPTRACKERIN ("fwsNetEventCloseListen", __LINE__, nil, listenref); 3465 3466 /* Find and remove from listener list */ 3467 3468 #if TARGET_API_MAC_CARBON == 1 3469 if (!OTFindAndRemoveLink (&sListenList, gListSearchUPP, (void *)listenref)) { 3470 intneterror (INTNETERROR_INVALIDSTREAM); 3471 return (false); 3472 } 3473 #else 3474 if (!OTFindAndRemoveLink (&sListenList, &listenlinkvisit, (void *)listenref)) { 3475 intneterror (INTNETERROR_INVALIDSTREAM); 3476 return (false); 3477 } 3478 #endif 3479 3480 /* Remove the notifier function */ 3481 3482 OTRemoveNotifier (listenref->ep); 3483 3484 /* Set the listener to synchronous mode */ 3485 3486 err = OTSetSynchronous (listenref->ep); 3487 3488 if (kOTNoError != err) { 3489 TCPERRORprintf (wsprintf (TCPmsg, "In fwscleanuplistener at line %d, error %ld setting listener %08lx to synchronous mode.", __LINE__, err, (long) listenref)); 3490 TCPERRORWRITEMSG(); 3491 } 3492 3493 /* Close the listening endpoint itself */ 3494 3495 err = OTCloseProvider (listenref->ep); 3496 3497 if (kOTNoError != err) { 3498 TCPERRORprintf (wsprintf (TCPmsg, "In fwscleanuplistener at line %d, error %ld closing listener %08lx.", __LINE__, err, (long) listenref)); 3499 TCPERRORWRITEMSG(); 3500 } 3501 3502 /* Refer the actual clean up to the worker thread associated with the listener */ 3503 3504 listenref->typeID = SOCKTYPE_LISTENSTOPPED; 3505 3506 TCPTRACKEROUT ("fwsNetEventCloseListen", __LINE__, nil, listenref); 3507 3508 return (true); 3509 } /*fwsNetEventCloseListen*/ 3510 3511 3512 void fwsNetEventShutdownDependentListeners (long hdatabase) { 3513 3514 OTLink* listitem; 3515 ListenRecordRef listenref; 3516 3517 #if TARGET_API_MAC_CARBON == 1 3518 OTListSearchUPP listendatabaseUPP = NewOTListSearchUPP(listendatabasevisit); 3519 #endif 3520 3521 if (!frontierWinSockLoaded) 3522 return; 3523 3524 3525 while (true) { 3526 3527 #if TARGET_API_MAC_CARBON == 1 3528 listitem = OTFindLink (&sListenList, listendatabaseUPP, (void *) hdatabase); 3529 #else 3530 listitem = OTFindLink (&sListenList, &listendatabasevisit, (void *) hdatabase); 3531 #endif 3532 3533 if (listitem == nil) 3534 break; 3535 3536 listenref = OTGetLinkObject (listitem, tylistenrecord, validationlink); 3537 3538 OTRemoveLink (&sListenList, &listenref->validationlink); 3539 3540 listenref->typeID = SOCKTYPE_LISTENSTOPPED; /* Leave clean up to worker thread */ 3541 } 3542 3543 #if TARGET_API_MAC_CARBON == 1 3544 DisposeOTListSearchUPP(listendatabaseUPP); 3545 #endif 3546 }/*fwsNetEventShutdownDependentListeners*/ 3547 3548 3549 boolean fwsNetEventCheckAndAcceptSocket (void) { 3550 3551 /* 3552 This is called from the main event loop. 3553 We don't have to do any accepting here, 3554 but use the opportunity to recycle broken EPs. 3555 */ 3556 3557 if (frontierWinSockLoaded) 3558 3559 ProcessWaitingEndpoints (nil); 3560 3561 Recycle (nil); 3562 3563 return (true); 3564 } 3565 3566 3567 static short is_ipaddress (char *name) { 3568 3569 short ctfields = 1; 3570 short fieldlen = 0; 3571 char *p = name; 3572 3573 for (p = name; *p; ++p) { 3574 3575 if (*p == '.') { 3576 3577 if (fieldlen == 0) //leading dot, or consequtive dots 3578 return (false); 3579 3580 ++ctfields; 3581 3582 fieldlen = 0; 3583 } 3584 else { 3585 if (!isdigit (*p)) 3586 return (false); 3587 3588 if (++fieldlen > 3) // four consecutive digits 3589 return (false); 3590 } 3591 } 3592 3593 return (ctfields == 4); 3594 } /*is_ipaddress*/ 3595 3596 3597 static boolean fwsOpenStream (TCall *ptrSndCall, unsigned long * stream) { 3598 3599 /* 3600 Open a new endpoint asynchronously. 3601 */ 3602 3603 EndpointRecordRef epref; 3604 OTLink *epref_link = nil; 3605 OSStatus err; 3606 3607 if (!incrementconnectioncounter ()) { 3608 3609 plainneterror ("\x54" "Can't open stream because no more than five TCP connections may be open at any time."); 3610 3611 return (false); 3612 } 3613 3614 /* Try to obtain a new endpoint from the static list of idle endpoints */ 3615 3616 #if TARGET_API_MAC_CARBON != 1 3617 3618 /*Always create new endpoints on OS X.*/ 3619 3620 epref_link = OTLIFODequeue (&sIdleEPs); 3621 3622 #endif 3623 3624 if (nil == epref_link) { /* No endpoints available, need to allocate and open a new one */ 3625 3626 epref = (EndpointRecordRef) NewPtr (sizeof (tyendpointrecord)); 3627 3628 if (nil == epref) { 3629 neterror ("open stream", memFullErr); 3630 decrementconnectioncounter(); 3631 return (false); 3632 } 3633 3634 InitEndpoint (epref, nil, nil); 3635 3636 epref->sendCall = ptrSndCall; 3637 3638 OTAtomicSetBit (&epref->stateflags, kWaitingForConnectBit); 3639 3640 OTAtomicSetBit (&epref->stateflags, kDontDisposeBit); 3641 3642 err = EPOpen (epref, OTCloneConfiguration (sMasterConfig)); 3643 3644 if (kOTNoError != err) { 3645 DisposePtr ((Ptr) epref); 3646 neterror ("open stream", err); 3647 decrementconnectioncounter(); 3648 return (false); 3649 } 3650 3651 epstats.cttotal++; 3652 3653 epstats.ctworking++; 3654 } 3655 else { 3656 3657 epstats.ctidle--; 3658 3659 epstats.ctworking++; 3660 3661 epref = OTGetLinkObject (epref_link, tyendpointrecord, link); 3662 3663 InitEndpoint (epref, epref->ep, nil); 3664 3665 epref->sendCall = ptrSndCall; 3666 3667 OTAtomicSetBit (&epref->stateflags, kWaitingForConnectBit); 3668 3669 OTAtomicSetBit (&epref->stateflags, kDontDisposeBit); 3670 3671 err = EnterBind (epref); 3672 3673 if (kOTNoError != err) { 3674 neterror ("open stream", err); 3675 CheckUnbind (epref, err, kQueueIt); 3676 decrementconnectioncounter(); 3677 return (false); 3678 } 3679 } 3680 3681 /* Loop until open, bind, and connect have completed */ 3682 3683 while (!OTAtomicTestBit (&epref->completionflags, kConnectCompleteBit)) 3684 if (!fwsbackgroundtask ()) { 3685 if (OTAtomicTestBit (&epref->stateflags, kBoundBit)) 3686 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 3687 else 3688 CheckUnbind (epref, userCanceledErr, kQueueIt); 3689 decrementconnectioncounter(); 3690 return (false); 3691 } 3692 3693 err = epref->result; 3694 3695 if (kOTNoError != err) { 3696 neterror ("open stream", err); 3697 if (OTAtomicTestBit (&epref->stateflags, kBoundBit)) 3698 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 3699 else 3700 CheckUnbind (epref, err, kQueueIt); 3701 decrementconnectioncounter(); 3702 return (false); 3703 } 3704 3705 /* Clean up and return */ 3706 3707 epref->typeID = SOCKTYPE_OPEN; 3708 3709 OTAddFirst (&sEndpointList, &epref->validationlink); 3710 3711 *stream = (long) epref; 3712 3713 return (true); 3714 }/*fwsOpenStream*/ 3715 3716 3717 boolean fwsNetEventOpenAddrStream (unsigned long addr, unsigned long port, unsigned long * stream) { 3718 3719 /* 3720 6.2b6 AR: Open Transport version 3721 */ 3722 3723 TCall sndCall; 3724 InetAddress hostAddress; 3725 3726 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3727 return (false); 3728 3729 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenAddrStream at line %d. Address: %ld.", __LINE__, addr)); 3730 TCPWRITEMSG(); 3731 3732 OTInitInetAddress (&hostAddress, port, addr); 3733 3734 sndCall.addr.buf = (UInt8 *) &hostAddress; 3735 sndCall.addr.len = sizeof (hostAddress); 3736 sndCall.opt.buf = nil; // no connection options 3737 sndCall.opt.len = 0; 3738 sndCall.udata.buf = nil; // no connection data 3739 sndCall.udata.len = 0; 3740 sndCall.sequence = 0; // ignored by OTConnect 3741 3742 return (fwsOpenStream (&sndCall, stream)); 3743 } /*fwsNetEventOpenAddrStream*/ 3744 3745 3746 boolean fwsNetEventOpenNameStream (bigstring name, unsigned long port, unsigned long * stream) { 3747 3748 /* 3749 6.2b6 AR: Open Transport version. 3750 3751 7.0b53 PBS: lower-case the domain name in the OS X version, else an error may be reported. 3752 */ 3753 3754 char sysstring[256]; 3755 unsigned long addr; 3756 TCall sndCall; 3757 DNSAddress dnsaddress; 3758 3759 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3760 return (false); 3761 3762 #if TARGET_API_MAC_CARBON == 1 3763 3764 alllower (name); /*7.0b44 PBS: OS X may return an error otherwise.*/ 3765 3766 #endif 3767 3768 copyptocstring (name, sysstring); 3769 3770 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenNameStream at line %d. Domain name: %s.", __LINE__, sysstring)); 3771 TCPWRITEMSG(); 3772 3773 if (is_ipaddress (sysstring)) { 3774 3775 if (!fwsNetEventAddressEncode (name, &addr)) 3776 return (false); 3777 3778 return (fwsNetEventOpenAddrStream (addr, port, stream)); 3779 } 3780 3781 #if TARGET_API_MAC_CARBON == 1 /*7.0b53 PBS: check the domain name*/ 3782 3783 if (!fwsNetEventNameToAddress (name, &addr)) 3784 return (false); 3785 3786 #endif 3787 3788 wsprintf (sysstring, "%s:%ld", sysstring, port); 3789 3790 sndCall.addr.len = OTInitDNSAddress (&dnsaddress, sysstring); 3791 sndCall.addr.buf = (UInt8 *) &dnsaddress; 3792 sndCall.opt.buf = nil; // no connection options 3793 sndCall.opt.len = 0; 3794 sndCall.udata.buf = nil; // no connection data 3795 sndCall.udata.len = 0; 3796 sndCall.sequence = 0; // ignored by OTConnect 3797 3798 return (fwsOpenStream (&sndCall, stream)); 3799 } /*fwsNetEventOpenNameStream*/ 3800 3801 3802 boolean fwsNetEventAbortStream (unsigned long stream) { 3803 3804 /* 3805 Abort a stream and delete associated data 3806 3807 We trust the notifier and EnterSndDisconnect 3808 to do the right thing regarding clean-up. 3809 */ 3810 3811 EndpointRecordRef epref = (EndpointRecordRef) stream; 3812 OSStatus err; 3813 3814 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3815 return (false); 3816 3817 TCPTRACKERIN ("fwsNetEventAbortStream", __LINE__, epref, nil); 3818 3819 /* Validate endpoint reference */ 3820 3821 if (!CheckEndpointList (epref)) { 3822 intneterror (INTNETERROR_INVALIDSTREAM); 3823 return (false); 3824 } 3825 3826 /* Remove from list of valid endpoint references */ 3827 3828 OTRemoveLink (&sEndpointList, &epref->validationlink); 3829 3830 /* Initiate abortive disconnect */ 3831 3832 err = EnterSndDisconnect (epref); 3833 3834 if (kOTNoError != err) { // Scripts don't have to care about this error, it has already been taken care off anyway 3835 TCPERRORprintf (wsprintf (TCPmsg, "In fwsNetEventAbortStream at line %d, error %ld disconnecting endpoint %08lx.", __LINE__, err, (long) epref)); 3836 TCPERRORWRITEMSG(); 3837 } 3838 3839 decrementconnectioncounter(); 3840 3841 TCPTRACKEROUT ("fwsNetEventAbortStream", __LINE__, epref, nil); 3842 3843 return (true); 3844 } /*fwsNetEventAbortStream*/ 3845 3846 3847 boolean fwsNetEventCloseStream (unsigned long stream) { 3848 3849 /* 3850 Close a stream and delete associated data 3851 3852 We trust the notifier and EnterSndOrderlyDisconnect 3853 to do the right thing regarding clean-up. 3854 */ 3855 3856 EndpointRecordRef epref = (EndpointRecordRef) stream; 3857 boolean doLeave; 3858 3859 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3860 return (false); 3861 3862 /* Validate endpoint reference */ 3863 3864 if (!CheckEndpointList (epref)) { 3865 intneterror (INTNETERROR_INVALIDSTREAM); 3866 return (false); 3867 } 3868 3869 TCPTRACKEROUT ("fwsNetEventCloseStream", __LINE__, epref, nil); 3870 3871 /* Remove from list of valid endpoint references */ 3872 3873 OTRemoveLink (&sEndpointList, &epref->validationlink); 3874 3875 /* Initiate graceful disconnect */ 3876 3877 doLeave = OTEnterNotifier (epref->ep); 3878 3879 3880 /*bundle*/ { 3881 ListenRecordRef listenref = epref->listener; 3882 3883 DoSndOrderlyDisconnect (epref, true); 3884 3885 if (0 == OTAtomicTestBit (&epref->stateflags, kBrokenBit)) { 3886 3887 if (T_IDLE == OTGetEndpointState (epref->ep)) { 3888 3889 OTAtomicClearBit (&epref->stateflags, kDontDisposeBit); /*pass on responsibility to the Notifier*/ 3890 3891 CheckUnbind (epref, OTUnbind (epref->ep), kDontQueueIt); 3892 } 3893 else { 3894 3895 epref->timestamp = timenow (); 3896 3897 OTAtomicSetBit (&epref->stateflags, kWaitingForDisconnectBit); 3898 3899 if (listenref != nil) { 3900 listenref->stats.ctworking--; 3901 listenref->stats.ctwaiting++; 3902 OTLIFOEnqueue (&listenref->waitingEPs, &epref->link); /*try again later*/ 3903 } 3904 else { 3905 epstats.ctworking--; 3906 epstats.ctwaiting++; 3907 OTLIFOEnqueue (&sWaitingEPs, &epref->link); /*try again later*/ 3908 } 3909 } 3910 } 3911 } 3912 3913 if (doLeave) 3914 OTLeaveNotifier (epref->ep); 3915 3916 decrementconnectioncounter(); 3917 3918 TCPTRACKEROUT ("fwsNetEventCloseStream", __LINE__, epref, nil); 3919 3920 return (true); 3921 } /*fwsNetEventCloseStream*/ 3922 3923 3924 boolean fwsNetEventReadStream (unsigned long stream, unsigned long * bytesToRead, char * buffer) { 3925 3926 /* Read from a stream */ 3927 3928 OTResult result; 3929 OTFlags junkFlags; 3930 EndpointRecordRef epref = (EndpointRecordRef) stream; 3931 long ix = 0; 3932 long readcount = *bytesToRead; 3933 boolean doLeave = false; 3934 3935 *bytesToRead = 0; 3936 3937 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 3938 return (false); 3939 3940 TCPTRACKERIN ("fwsNetEventReadStream", __LINE__, epref, nil); 3941 3942 if (!CheckEndpointList (epref)) { 3943 intneterror (INTNETERROR_INVALIDSTREAM); 3944 return (false); 3945 } 3946 3947 doLeave = OTEnterNotifier (epref->ep); 3948 3949 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) { 3950 closedunexpectedlyerror ("read stream"); 3951 goto error; 3952 } 3953 3954 while (readcount > 0) { 3955 3956 result = OTRcv (epref->ep, (void *) (buffer + ix), readcount, &junkFlags); 3957 3958 if (result < 0) { 3959 3960 if (kOTNoDataErr == result) { /* No data available for reading */ 3961 if (!fwsbackgroundtask ()) { 3962 if (doLeave) 3963 OTLeaveNotifier (epref->ep); 3964 return (false); 3965 } 3966 continue; 3967 } 3968 3969 if (kOTLookErr == result) { 3970 3971 OTResult eventcode = OTLook (epref->ep); 3972 3973 switch (eventcode) { 3974 3975 case T_DISCONNECT: { /* Receive and break out */ 3976 EnterRcvDisconnect (epref); 3977 closedunexpectedlyerror ("read stream"); 3978 goto error; 3979 } 3980 3981 case T_ORDREL: { /* Receive and try again */ 3982 EnterRcvOrderlyDisconnect (epref); 3983 closedunexpectedlyerror ("read stream"); 3984 goto error; 3985 } 3986 3987 case T_GODATA: { /* Try again */ 3988 TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA"); 3989 continue; 3990 } 3991 3992 default: { 3993 neterror ("write stream", result); 3994 goto error; 3995 } 3996 } 3997 } 3998 else { 3999 neterror("read stream", result); 4000 goto error; 4001 } 4002 } 4003 4004 readcount -= result; 4005 4006 ix += result; 4007 4008 *bytesToRead = ix; 4009 }/*while*/ 4010 4011 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStream at line %d. Bytes requested = %ld, read = %ld.", __LINE__, *bytesToRead, (unsigned long) result)); 4012 TCPWRITEMSG (); 4013 4014 if (doLeave) 4015 OTLeaveNotifier (epref->ep); 4016 4017 return (true); 4018 4019 error: 4020 4021 if (doLeave) 4022 OTLeaveNotifier (epref->ep); 4023 4024 return (false); 4025 } /*fwsNetEventReadStream*/ 4026 4027 4028 boolean fwsNetEventWriteStream (unsigned long stream, unsigned long bytesToWrite, char * buffer) { 4029 4030 /* 4031 Write to a Stream 4032 4033 5.0.2b3 dmb: if we write fewer bytes than requested, we need to retry, generate error 4034 4035 6.2b9 AR: The above change doesn't really work since scripts have no way to find out 4036 which part of the data needs to be resend. Instead of throwing an error, keep trying. 4037 */ 4038 4039 EndpointRecordRef epref = (EndpointRecordRef) stream; 4040 OTResult result; 4041 long ix = 0; 4042 boolean doLeave = false; 4043 4044 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4045 return (false); 4046 4047 TCPTRACKERIN ("fwsNetEventWriteStream", __LINE__, epref, nil); 4048 4049 if (!CheckEndpointList (epref)) { 4050 intneterror (INTNETERROR_INVALIDSTREAM); 4051 return (false); 4052 } 4053 4054 doLeave = OTEnterNotifier (epref->ep); 4055 4056 if (OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) { 4057 closedunexpectedlyerror ("write stream"); 4058 goto exit; 4059 } 4060 4061 while (bytesToWrite > 0) { 4062 4063 result = OTSnd (epref->ep, (void *) (buffer + ix), bytesToWrite, nil); 4064 4065 if (result <= 0) { 4066 4067 if (kOTFlowErr == result) { 4068 if (!fwsbackgroundtask ()) { 4069 if (doLeave) 4070 OTLeaveNotifier (epref->ep); 4071 return (false); 4072 } 4073 continue; 4074 } 4075 4076 if (kOTLookErr == result) { 4077 4078 OTResult eventcode = OTLook (epref->ep); 4079 4080 switch (eventcode) { 4081 4082 case T_DISCONNECT: { /* Receive and break out */ 4083 EnterRcvDisconnect (epref); 4084 closedunexpectedlyerror ("write stream"); 4085 goto exit; 4086 } 4087 4088 case T_ORDREL: { /* Receive and try again */ 4089 EnterRcvOrderlyDisconnect (epref); 4090 continue; 4091 } 4092 4093 case T_GODATA: { /* Try again */ 4094 TCP_MSG_2 ("OTLook after OTSnd returned T_GODATA"); 4095 continue; 4096 } 4097 4098 default: { 4099 neterror ("write stream", result); 4100 goto exit; 4101 } 4102 } 4103 } 4104 else { 4105 neterror("write stream", result); 4106 goto exit; 4107 } 4108 } 4109 4110 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.", __LINE__, bytesToWrite, result)); 4111 TCPWRITEMSG (); 4112 4113 bytesToWrite -= result; 4114 4115 ix += result; 4116 } 4117 4118 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteStream at line %d. Bytes requested = %ld, written = %ld.", __LINE__, bytesToWrite, (unsigned long) result)); 4119 TCPWRITEMSG (); 4120 4121 if (doLeave) 4122 OTLeaveNotifier (epref->ep); 4123 4124 return (true); 4125 4126 exit: 4127 4128 if (doLeave) 4129 OTLeaveNotifier (epref->ep); 4130 4131 return (false); 4132 } /*fwsNetEventWriteStream*/ 4133 4134 4135 4136 boolean fwsNetEventStatusStream (unsigned long stream, bigstring status, unsigned long * bytesPending) { 4137 4138 /* get the status of a stream */ 4139 4140 EndpointRecordRef epref = (EndpointRecordRef) stream; 4141 ListenRecordRef listenref = (ListenRecordRef) stream; 4142 tysocktypeid typeID = SOCKTYPE_INVALID; 4143 4144 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4145 return (false); 4146 4147 *bytesPending = 0; 4148 4149 if (CheckEndpointList (epref)) { 4150 typeID = epref->typeID; 4151 if (!inmainthread()) 4152 TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, epref, nil); 4153 } 4154 4155 if (CheckListenList (listenref)) { 4156 typeID = listenref->typeID; 4157 if (!inmainthread()) 4158 TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, nil, listenref); 4159 } 4160 4161 if (!epref && !listenref && !inmainthread ()) { 4162 TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, epref, listenref); 4163 } 4164 4165 switch (typeID) { 4166 case SOCKTYPE_INVALID: 4167 intneterror(INTNETERROR_INVALIDSTREAM); 4168 copyctopstring ("INACTIVE", status); 4169 return (false); 4170 4171 case SOCKTYPE_UNKNOWN: 4172 copyctopstring ("UNKNOWN", status); 4173 break; 4174 4175 case SOCKTYPE_OPEN: { 4176 OTResult result; 4177 4178 copyctopstring ("OPEN", status); 4179 4180 result = OTCountDataBytes (epref->ep, (OTByteCount*) bytesPending); 4181 4182 switch (result) { 4183 4184 case kOTNoError: { 4185 if (*bytesPending != 0) 4186 copyctopstring ("DATA", status); 4187 else 4188 copyctopstring ("OPEN", status); 4189 break; 4190 } 4191 4192 case kOTNoDataErr: { 4193 copyctopstring ("OPEN", status); 4194 break; 4195 } 4196 4197 case kOTLookErr: { 4198 4199 OTResult eventcode = OTLook (epref->ep); 4200 4201 switch (eventcode) { 4202 4203 case T_DISCONNECT: { /* Receive and break out */ 4204 //EnterRcvDisconnect (epref); /* Don't actually disconnect here, leave that up to fwsNetEventCloseStream */ 4205 copyctopstring ("INACTIVE", status); 4206 epref->typeID = SOCKTYPE_INACTIVE; 4207 break; 4208 } 4209 4210 case T_ORDREL: { /* Receive and try again */ 4211 EnterRcvOrderlyDisconnect (epref); /* Don't actually disconnect here, leave that up to fwsNetEventCloseStream */ 4212 copyctopstring ("INACTIVE", status); 4213 epref->typeID = SOCKTYPE_INACTIVE; 4214 break; 4215 } 4216 4217 default: { 4218 copyctopstring ("OPEN", status); 4219 break; 4220 } 4221 } 4222 break; 4223 } 4224 4225 case kOTOutStateErr: 4226 if (*bytesPending == 0) 4227 break; 4228 4229 default: 4230 neterror("check status on stream", result); 4231 copyctopstring ("INACTIVE", status); 4232 epref->typeID = SOCKTYPE_INACTIVE; 4233 return (false); 4234 } 4235 4236 if (*bytesPending == 0) 4237 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) { 4238 copyctopstring ("INACTIVE", status); 4239 epref->typeID = SOCKTYPE_INACTIVE; 4240 } 4241 4242 break; 4243 } 4244 4245 case SOCKTYPE_LISTENING: 4246 copyctopstring ("LISTENING", status); 4247 break; 4248 4249 case SOCKTYPE_CLOSED: 4250 copyctopstring ("CLOSED", status); 4251 break; 4252 4253 case SOCKTYPE_LISTENSTOPPED: 4254 copyctopstring ("STOPPED", status); 4255 break; 4256 4257 case SOCKTYPE_INACTIVE: 4258 copyctopstring ("INACTIVE", status); 4259 break; 4260 4261 default: 4262 copyctopstring ("UNKNOWN", status); 4263 break; 4264 } 4265 4266 nullterminate (status); 4267 4268 if (!inmainthread()) { 4269 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventStatusStream at line %d, result is %s with bytes pending %ld.", __LINE__, stringbaseaddress(status), *bytesPending)); 4270 TCPWRITEMSG (); 4271 } 4272 4273 return (true); 4274 } /*fwsNetEventStatusStream*/ 4275 4276 4277 boolean fwsNetEventGetPeerAddress (unsigned long stream, unsigned long * peeraddress, unsigned long * peerport) { 4278 4279 EndpointRecordRef epref = (EndpointRecordRef) stream; 4280 TBind* peerAddr; 4281 OSStatus err; 4282 4283 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4284 return (false); 4285 4286 TCPTRACKERIN ("fwsNetEventGetPeerAddress", __LINE__, epref, nil); 4287 4288 if (!CheckEndpointList (epref)) { 4289 intneterror (INTNETERROR_INVALIDSTREAM); 4290 return (false); 4291 } 4292 //Code change by Timothy Paustian Monday, June 26, 2000 4:07:42 PM 4293 // 4294 #if TARGET_API_MAC_CARBON == 1 4295 peerAddr = OTAllocInContext (epref->ep, T_BIND, T_ADDR, &err, nil); 4296 #else 4297 peerAddr = OTAlloc (epref->ep, T_BIND, T_ADDR, &err); 4298 #endif 4299 4300 if (err != kOTNoError) { 4301 neterror ("get peer address", err); 4302 return (false); 4303 } 4304 4305 OTAtomicClearBit (&epref->completionflags, kGetProtAddressBit); 4306 4307 err = OTGetProtAddress (epref->ep, nil, peerAddr); 4308 4309 if (err != kOTNoError) { 4310 neterror ("get peer address", err); 4311 OTFree (peerAddr, T_BIND); 4312 return (false); 4313 } 4314 4315 while (!OTAtomicTestBit (&epref->completionflags, kGetProtAddressBit)) 4316 YieldToAnyThread (); 4317 4318 //OTAssert ("fwsNetEventGetPeerAddress: size of peer address structure doesn't match InetAddress", sizeof (InetAddress) == peerAddr->addr.len); 4319 4320 //OTAssert ("fwsNetEventGetPeerAddress: size of peer address structure doesn't match InetAddress", AF_INET == ((InetAddress*) peerAddr->addr.buf)->fAddressType); 4321 4322 *peerport = ((InetAddress*) peerAddr->addr.buf)->fPort; 4323 4324 *peeraddress = ((InetAddress*) peerAddr->addr.buf)->fHost; 4325 4326 OTFree (peerAddr, T_BIND); 4327 4328 TCPTRACKEROUT ("fwsNetEventGetPeerAddress", __LINE__, epref, nil); 4329 4330 return (true); 4331 } /*fwsNetEventGetPeerAddress*/ 4332 4333 4334 boolean fwsNetEventReadStreamUntil (unsigned long stream, Handle hbuffer, Handle hpattern, unsigned long timeoutsecs) { 4335 4336 /* 4337 Read data from stream. Don't return until we found the pattern or until we timed out. 4338 */ 4339 4340 EndpointRecordRef epref = (EndpointRecordRef) stream; 4341 long ix = gethandlesize (hbuffer); 4342 long ixstart = ix; 4343 OTFlags junkFlags; 4344 OTResult result; 4345 long timeoutticks; 4346 boolean doLeave = false; 4347 4348 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4349 return (false); 4350 4351 TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, epref, nil); 4352 4353 if (searchhandle (hbuffer, hpattern, 0, ix) != -1L) 4354 return (true); 4355 4356 if (!CheckEndpointList (epref)) { 4357 intneterror (INTNETERROR_INVALIDSTREAM); 4358 return (false); 4359 } 4360 4361 doLeave = OTEnterNotifier (epref->ep); 4362 4363 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) 4364 goto error_closedprematurely; 4365 4366 if (!sethandlesize (hbuffer, ix + kPacketSize)) { 4367 if (doLeave) 4368 OTLeaveNotifier (epref->ep); 4369 return (false); 4370 } 4371 4372 timeoutticks = gettickcount () + (timeoutsecs * 60); 4373 4374 while (true) { 4375 4376 lockhandle (hbuffer); 4377 4378 result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags); 4379 4380 unlockhandle (hbuffer); 4381 4382 if (result < 0) { 4383 4384 if (kOTNoDataErr == result) { 4385 4386 if (gettickcount () > timeoutticks) { 4387 result = kETIMEDOUTErr; 4388 goto exit; 4389 } 4390 4391 if (!fwsbackgroundtask ()) { 4392 if (doLeave) 4393 OTLeaveNotifier (epref->ep); 4394 return (false); 4395 } 4396 4397 continue; 4398 } 4399 4400 if (kOTLookErr == result) { 4401 4402 result = OTLook (epref->ep); 4403 4404 switch (result) { 4405 4406 case T_ORDREL: 4407 EnterRcvOrderlyDisconnect (epref); 4408 goto error_closedprematurely; 4409 4410 case T_DISCONNECT: 4411 EnterRcvDisconnect (epref); 4412 goto error_closedprematurely; 4413 4414 case T_GODATA: 4415 TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA"); 4416 continue; /*ignore it*/ 4417 4418 default: 4419 result = kOTLookErr; 4420 goto exit; 4421 } 4422 } 4423 else 4424 goto exit; 4425 } 4426 4427 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, read %ld bytes.", __LINE__, result)); 4428 TCPWRITEMSG (); 4429 4430 ix += result; 4431 4432 if (searchhandle (hbuffer, hpattern, 0, ix) != -1L) 4433 break; 4434 4435 if (!sethandlesize (hbuffer, ix + kPacketSize)) { /* Make room for another 8k */ 4436 if (doLeave) 4437 OTLeaveNotifier (epref->ep); 4438 return (false); 4439 } 4440 4441 timeoutticks = gettickcount () + (timeoutsecs * 60); 4442 }/*while*/ 4443 4444 if (!sethandlesize (hbuffer, ix)) { 4445 if (doLeave) 4446 OTLeaveNotifier (epref->ep); 4447 return (false); 4448 } 4449 4450 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntil at line %d. Total bytes read = %ld.", __LINE__, ix - ixstart)); 4451 TCPWRITEMSG (); 4452 4453 if (doLeave) 4454 OTLeaveNotifier (epref->ep); 4455 4456 return (true); 4457 4458 exit: 4459 4460 sethandlesize (hbuffer, ix); 4461 4462 neterror ("read stream", result); 4463 4464 if (doLeave) 4465 OTLeaveNotifier (epref->ep); 4466 4467 return (false); 4468 4469 error_closedprematurely: 4470 4471 sethandlesize (hbuffer, ix); 4472 4473 closedunexpectedlyerror ("read stream"); 4474 4475 if (doLeave) 4476 OTLeaveNotifier (epref->ep); 4477 4478 return (false); 4479 } /*fwsNetEventReadStreamUntil*/ 4480 4481 4482 4483 boolean fwsNetEventReadStreamUntilClosed (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) { 4484 4485 /* 4486 Read data from stream until closed. 4487 */ 4488 4489 EndpointRecordRef epref = (EndpointRecordRef) stream; 4490 long ix = gethandlesize (hbuffer); 4491 long ixstart = ix; 4492 OTFlags junkFlags; 4493 OTResult result; 4494 long timeoutticks; 4495 boolean doLeave = false; 4496 4497 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4498 return (false); 4499 4500 TCPTRACKERIN ("fwsNetEventReadStreamUntilClosed", __LINE__, epref, nil); 4501 4502 if (!CheckEndpointList (epref)) { 4503 intneterror (INTNETERROR_INVALIDSTREAM); 4504 return (false); 4505 } 4506 4507 doLeave = OTEnterNotifier (epref->ep); 4508 4509 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) 4510 goto done; /* 08/08/2000 AR: we're done already */ 4511 4512 if (!sethandlesize (hbuffer, ix + kPacketSize)) { 4513 if (doLeave) 4514 OTLeaveNotifier (epref->ep); 4515 return (false); 4516 } 4517 4518 timeoutticks = gettickcount () + (timeoutsecs * 60); 4519 4520 while (true) { 4521 4522 lockhandle (hbuffer); 4523 4524 result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags); 4525 4526 unlockhandle (hbuffer); 4527 4528 if (result < 0) { 4529 4530 if (kOTNoDataErr == result) { 4531 4532 if (gettickcount () > timeoutticks) { 4533 neterror ("read stream", kETIMEDOUTErr); 4534 goto exit; 4535 } 4536 4537 if (!fwsbackgroundtask ()) { 4538 if (doLeave) 4539 OTLeaveNotifier (epref->ep); 4540 return (false); 4541 } 4542 4543 continue; 4544 } 4545 4546 if (kOTLookErr == result) { 4547 4548 result = OTLook (epref->ep); 4549 4550 switch (result) { 4551 4552 case T_ORDREL: 4553 EnterRcvOrderlyDisconnect (epref); 4554 goto done; 4555 4556 case T_DISCONNECT: 4557 EnterRcvDisconnect (epref); 4558 goto done; 4559 4560 case T_GODATA: 4561 TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA"); 4562 continue; /*ignore it*/ 4563 4564 default: 4565 neterror ("read stream", kOTLookErr); 4566 goto exit; 4567 } 4568 } 4569 else { 4570 neterror ("read stream", result); 4571 goto exit; 4572 } 4573 } 4574 4575 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, read %ld bytes.", __LINE__, result)); 4576 TCPWRITEMSG (); 4577 4578 ix += result; 4579 4580 if (!sethandlesize (hbuffer, ix + kPacketSize)) 4581 return (false); /*we have the thread globals, so we can return immediately*/ 4582 4583 timeoutticks = gettickcount () + (timeoutsecs * 60); 4584 }/*while*/ 4585 4586 done: 4587 4588 if (!sethandlesize (hbuffer, ix)) 4589 return (false); 4590 4591 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntilClosed at line %d. Total bytes read = %ld.", __LINE__, ix - ixstart)); 4592 TCPWRITEMSG (); 4593 4594 if (doLeave) 4595 OTLeaveNotifier (epref->ep); 4596 4597 return (true); 4598 4599 exit: 4600 4601 if (!sethandlesize (hbuffer, ix)) 4602 return (false); 4603 4604 if (doLeave) 4605 OTLeaveNotifier (epref->ep); 4606 4607 return (false); 4608 }/*fwsNetEventReadStreamUntilClosed*/ 4609 4610 4611 boolean fwsNetEventReadStreamBytes (unsigned long stream, Handle hbuffer, long ctbytes, unsigned long timeoutsecs) { 4612 4613 /* 4614 Read the specified number of bytes from the stream appending to hbuffer. 4615 */ 4616 4617 EndpointRecordRef epref = (EndpointRecordRef) stream; 4618 long lenbuffer = gethandlesize (hbuffer); 4619 long ix = lenbuffer; 4620 OTResult result; 4621 OTFlags junkFlags; 4622 long timeoutticks; 4623 boolean doLeave = false; 4624 4625 if (ix >= ctbytes) /*6.1b8 AR: don't do anything*/ 4626 return (true); 4627 4628 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4629 return (false); 4630 4631 TCPTRACKERIN ("fwsNetEventReadStreamBytes", __LINE__, epref, nil); 4632 4633 if (!CheckEndpointList (epref)) { 4634 intneterror (INTNETERROR_INVALIDSTREAM); 4635 return (false); 4636 } 4637 4638 doLeave = OTEnterNotifier (epref->ep); 4639 4640 if (!sethandlesize (hbuffer, ctbytes)) { //make enough room in one go 4641 if (doLeave) 4642 OTLeaveNotifier (epref->ep); 4643 return (false); 4644 } 4645 4646 lockhandle (hbuffer); 4647 4648 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) 4649 goto error_closedprematurely; 4650 4651 timeoutticks = gettickcount () + (timeoutsecs * 60); 4652 4653 while (ix < ctbytes) { 4654 4655 result = OTRcv (epref->ep, (void *) &((*hbuffer)[ix]), ctbytes - ix, &junkFlags); 4656 4657 if (result < 0) { 4658 4659 if (kOTNoDataErr == result) { 4660 4661 if (gettickcount () > timeoutticks) { 4662 result = kETIMEDOUTErr; 4663 goto exit; 4664 } 4665 4666 if (!fwsbackgroundtask ()) { 4667 unlockhandle (hbuffer); 4668 if (doLeave) 4669 OTLeaveNotifier (epref->ep); 4670 return (false); 4671 } 4672 4673 continue; 4674 } 4675 4676 if (kOTLookErr == result) { 4677 4678 result = OTLook (epref->ep); 4679 4680 switch (result) { 4681 4682 case T_ORDREL: 4683 EnterRcvOrderlyDisconnect (epref); 4684 goto error_closedprematurely; 4685 4686 case T_DISCONNECT: 4687 EnterRcvDisconnect (epref); 4688 goto error_closedprematurely; 4689 4690 case T_GODATA: 4691 TCP_MSG_2 ("OTLook after OTRcv returned T_GODATA"); 4692 continue; /*ignore it*/ 4693 4694 default: 4695 result = kOTLookErr; 4696 goto exit; 4697 } 4698 } 4699 else 4700 goto exit; 4701 } 4702 4703 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, read %ld bytes.", __LINE__, result)); 4704 TCPWRITEMSG (); 4705 4706 ix += result; 4707 4708 timeoutticks = gettickcount () + (timeoutsecs * 60); 4709 }/*while*/ 4710 4711 unlockhandle (hbuffer); 4712 4713 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamBytes at line %d. Total bytes requested = %ld, bytes read = %ld.", __LINE__, ctbytes, ix)); 4714 TCPWRITEMSG (); 4715 4716 if (doLeave) 4717 OTLeaveNotifier (epref->ep); 4718 4719 return (true); 4720 4721 exit: 4722 4723 unlockhandle (hbuffer); 4724 4725 sethandlesize (hbuffer, ix); /*shrinking, can't fail*/ 4726 4727 neterror ("read stream", result); 4728 4729 if (doLeave) 4730 OTLeaveNotifier (epref->ep); 4731 4732 return (false); 4733 4734 error_closedprematurely: 4735 4736 closedunexpectedlyerror ("read stream"); 4737 4738 unlockhandle (hbuffer); 4739 4740 sethandlesize (hbuffer, ix); /*shrinking, can't fail*/ 4741 4742 if (doLeave) 4743 OTLeaveNotifier (epref->ep); 4744 4745 return (false); 4746 } /*fwsNetEventReadStreamBytes*/ 4747 4748 4749 boolean fwsNetEventWriteHandleToStream (unsigned long stream, Handle hbuffer, unsigned long chunksize, unsigned long timeoutsecs) { 4750 4751 /* Write to stream in chunks */ 4752 4753 EndpointRecordRef epref = (EndpointRecordRef) stream; 4754 unsigned long bytesremaining = gethandlesize (hbuffer); 4755 long ix = 0; 4756 long bytestowrite; 4757 OTResult result; 4758 long timeoutticks; 4759 boolean doLeave = false; 4760 4761 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4762 return (false); 4763 4764 TCPTRACKERIN ("fwsNetEventWriteHandleToStream", __LINE__, epref, nil); 4765 4766 if (!CheckEndpointList (epref)) { 4767 intneterror (INTNETERROR_INVALIDSTREAM); 4768 return (false); 4769 } 4770 4771 doLeave = OTEnterNotifier (epref->ep); 4772 4773 lockhandle (hbuffer); 4774 4775 if (OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) 4776 goto error_closedprematurely; 4777 4778 timeoutticks = gettickcount () + (timeoutsecs * 60); 4779 4780 do { 4781 4782 bytestowrite = (bytesremaining < chunksize) ? bytesremaining : chunksize; 4783 4784 result = OTSnd (epref->ep, &((*hbuffer) [ix]), bytestowrite, nil); 4785 4786 if (result <= 0) { 4787 4788 if (kOTFlowErr == result) { 4789 4790 if (gettickcount () > timeoutticks) { 4791 result = kETIMEDOUTErr; 4792 goto exit; 4793 } 4794 4795 if (!fwsbackgroundtask ()) { 4796 unlockhandle (hbuffer); 4797 if (doLeave) 4798 OTLeaveNotifier (epref->ep); 4799 return (false); 4800 } 4801 4802 continue; 4803 } 4804 4805 if (kOTLookErr == result) { 4806 4807 result = OTLook (epref->ep); 4808 4809 switch (result) { 4810 4811 case T_ORDREL: 4812 EnterRcvOrderlyDisconnect (epref); 4813 goto error_closedprematurely; 4814 4815 case T_DISCONNECT: 4816 EnterRcvDisconnect (epref); 4817 goto error_closedprematurely; 4818 4819 case T_GODATA: 4820 continue; /*ignore it*/ 4821 4822 default: 4823 result = kOTLookErr; 4824 goto exit; 4825 } 4826 } 4827 else 4828 goto exit; 4829 } 4830 4831 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.", __LINE__, bytestowrite, result)); 4832 TCPWRITEMSG (); 4833 4834 bytesremaining -= result; 4835 4836 ix += result; 4837 4838 timeoutticks = gettickcount () + (timeoutsecs * 60); 4839 4840 } while (bytesremaining > 0); 4841 4842 unlockhandle (hbuffer); 4843 4844 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteHandleToStream at line %d. Total bytes written = %ld.", __LINE__, ix)); 4845 TCPWRITEMSG (); 4846 4847 if (doLeave) 4848 OTLeaveNotifier (epref->ep); 4849 4850 return (true); 4851 4852 exit: 4853 4854 unlockhandle (hbuffer); 4855 4856 neterror("write stream", result); 4857 4858 if (doLeave) 4859 OTLeaveNotifier (epref->ep); 4860 4861 return (false); 4862 4863 error_closedprematurely: 4864 4865 unlockhandle (hbuffer); 4866 4867 closedunexpectedlyerror ("write stream"); 4868 4869 if (doLeave) 4870 OTLeaveNotifier (epref->ep); 4871 4872 return (false); 4873 } /*fwsNetEventWriteHandleToStream*/ 4874 4875 4876 static boolean fwstransmitfile (unsigned long stream, ptrfilespec fs) { 4877 4878 char *buffer; 4879 static const long kFileBufferSize = 32767L; 4880 boolean fl = false; 4881 hdlfilenum fnum; 4882 long ctread = 0; 4883 long ix = 0; 4884 4885 /* open file */ 4886 4887 if (!openfile (fs, &fnum, true)) 4888 return (false); 4889 4890 /* allocate buffer */ 4891 4892 buffer = malloc (kFileBufferSize); 4893 4894 if (buffer == nil) { 4895 memoryerror (); 4896 goto exit; 4897 } 4898 4899 while (true) { 4900 4901 /* read from file */ 4902 4903 if (!filesetposition (fnum, ix)) 4904 goto exit; 4905 4906 if (!filereaddata (fnum, kFileBufferSize, &ctread, buffer)) 4907 goto exit; 4908 4909 if (ctread == 0) { 4910 fl = true; 4911 goto exit; 4912 } 4913 4914 ix += ctread; 4915 4916 /* write to stream */ 4917 4918 if(!fwsNetEventWriteStream (stream, ctread, buffer)) 4919 goto exit; 4920 } 4921 4922 exit: 4923 /* free buffer */ 4924 4925 if (buffer != nil) 4926 free (buffer); 4927 4928 /* close file */ 4929 4930 fl = closefile (fnum); 4931 4932 return (fl); 4933 }/*fwstransmitfile*/ 4934 4935 4936 boolean fwsNetEventWriteFileToStream (unsigned long stream, Handle hprefix, Handle hsuffix, ptrfilespec fs) { 4937 4938 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4939 return (false); 4940 4941 TCPTRACKERIN ("fwsNetEventWriteFileToStream", __LINE__, (EndpointRecordRef) stream, nil); 4942 4943 if (hprefix != nil) { 4944 boolean fl; 4945 4946 lockhandle (hprefix); 4947 4948 fl = fwsNetEventWriteStream (stream, gethandlesize (hprefix), *hprefix); 4949 4950 unlockhandle (hprefix); 4951 4952 if (!fl) 4953 return (false); 4954 } 4955 4956 if (!fwstransmitfile (stream, fs)) 4957 return (false); 4958 4959 if (hsuffix != nil) { 4960 boolean fl; 4961 4962 lockhandle (hsuffix); 4963 4964 fl = fwsNetEventWriteStream (stream, gethandlesize (hsuffix), *hsuffix); 4965 4966 unlockhandle (hsuffix); 4967 4968 if (!fl) 4969 return (false); 4970 } 4971 4972 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__)); 4973 TCPWRITEMSG (); 4974 4975 return (true); 4976 } /*fwsNetEventWriteFileToStream*/ 4977 4978 //#endif 4979 4980 4981 boolean fwsNetEventInetdRead (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) { 4982 4983 /* 4984 6.1b2 AR: Wait timeoutsecs seconds for data to come in. After the first packet has been 4985 received, continue reading with a reduced timeout of .5 second. (For historical reasons.) 4986 */ 4987 4988 EndpointRecordRef epref = (EndpointRecordRef) stream; 4989 OTResult result; 4990 OTFlags junkFlags; 4991 long ix = gethandlesize (hbuffer); 4992 long ixstart = ix; 4993 long timeoutticks; 4994 boolean doLeave = false; 4995 4996 if (!fwsNetEventLaunch (NO_HOST_SERVICES)) 4997 return (false); 4998 4999 TCPTRACKERIN ("fwsNetEventInetdRead", __LINE__, epref, nil); 5000 5001 if (!CheckEndpointList (epref)) { 5002 intneterror (INTNETERROR_INVALIDSTREAM); 5003 return (false); 5004 } 5005 5006 doLeave = OTEnterNotifier (epref->ep); 5007 5008 if (OTAtomicTestBit (&epref->completionflags, kRcvdOrderlyDisconnectBit) || OTAtomicTestBit (&epref->completionflags, kRcvdDisconnectBit)) 5009 goto done; 5010 5011 timeoutticks = gettickcount () + (timeoutsecs * 60); 5012 5013 while (true) { 5014 5015 lockhandle (hbuffer); 5016 5017 result = OTRcv (epref->ep, &((*hbuffer) [ix]), kPacketSize, &junkFlags); 5018 5019 unlockhandle (hbuffer); 5020 5021 if (result < 0) { 5022 5023 if (kOTNoDataErr == result) { 5024 5025 if (gettickcount () > timeoutticks) 5026 goto done; /* simply stop reading, don't throw an error */ 5027 5028 YieldToAnyThread (); 5029 5030 continue; 5031 } 5032 5033 if (kOTLookErr == result) { 5034 5035 result = OTLook (epref->ep); 5036 5037 switch (result) { 5038 5039 case T_ORDREL: 5040 EnterRcvOrderlyDisconnect (epref); 5041 goto done; 5042 5043 case T_DISCONNECT: 5044 EnterRcvDisconnect (epref); 5045 goto done; 5046 5047 case T_GODATA: 5048 TCP_MSG_2("OTLook after OTRcv returned T_GODATA"); 5049 continue; /*ignore it*/ 5050 5051 default: 5052 result = kOTLookErr; 5053 goto exit; 5054 } 5055 } 5056 else 5057 goto exit; 5058 } 5059 5060 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, requested reading %ld bytes, read %ld bytes.", __LINE__, kPacketSize, result)); 5061 TCPWRITEMSG (); 5062 5063 ix += result; 5064 5065 if (!sethandlesize (hbuffer, ix + kPacketSize)) { 5066 if (doLeave) 5067 OTLeaveNotifier (epref->ep); 5068 return (false); 5069 } 5070 5071 timeoutticks = gettickcount () + 30; 5072 }/*while*/ 5073 5074 done: 5075 if (!sethandlesize (hbuffer, ix)) 5076 return (false); 5077 5078 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventInetdRead at line %d. Total bytes read = %ld.", __LINE__, ix - ixstart)); 5079 TCPWRITEMSG (); 5080 5081 if (doLeave) 5082 OTLeaveNotifier (epref->ep); 5083 5084 return (true); 5085 5086 exit: 5087 neterror ("read stream", result); 5088 5089 if (doLeave) 5090 OTLeaveNotifier (epref->ep); 5091 5092 return (false); 5093 } /*fwsNetEventInetdRead*/ 5094 5095 5096 boolean fwsNetEventGetStats (unsigned long stream, bigstring bs) { 5097 5098 setemptystring (bs); 5099 5100 if (nil != stream) { 5101 5102 ListenRecordRef listenref = (ListenRecordRef) stream; 5103 5104 if (!CheckListenList (listenref)) { 5105 intneterror (INTNETERROR_INVALIDSTREAM); 5106 return (false); 5107 } 5108 5109 pushlong (listenref->stats.cttotal, bs); 5110 5111 pushchar (',', bs); 5112 5113 pushlong (listenref->stats.ctidle, bs); 5114 5115 pushchar (',', bs); 5116 5117 pushlong (listenref->stats.ctworking, bs); 5118 5119 pushchar (',', bs); 5120 5121 pushlong (listenref->stats.ctwaiting, bs); 5122 5123 pushchar (',', bs); 5124 5125 pushlong (listenref->stats.ctbroken, bs); 5126 } 5127 else { 5128 5129 pushlong (epstats.cttotal, bs); 5130 5131 pushchar (',', bs); 5132 5133 pushlong (epstats.ctidle, bs); 5134 5135 pushchar (',', bs); 5136 5137 pushlong (epstats.ctbroken, bs); 5138 5139 pushchar (',', bs); 5140 5141 pushlong (epstats.ctworking, bs); 5142 } 5143 5144 return (true); 5145 }/*fwsNetEventGetStats*/

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.