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*/
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.