Version:
~ [ 10.0 ] ~
** Warning: Cannot open xref database.
1
2 /* $Id: WinSockNetEvents.c,v 1.4 2005/01/11 22:48:04 andreradke 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 /*************************************************************************
29
30 This file contains the Frontier NetEvents interface for the Windows
31 version. It uses the WinSock 1.1 specification. Extensions should be
32 added for the 2.0 specification at a later date. The primary advantage
33 of the 2.x specification is that more then just the TCP/IP protocol is
34 supported. In fact many protocols are supported including the Apple
35 Share protocol.
36
37
38 Created 7/20/97 Robert Bierman
39
40 General Note: All addresses are in HOST format. We convert to network
41 format internally.
42
43 **************************************************************************/
44
45
46 #include "frontier.h"
47 #include "standard.h"
48
49
50 #ifdef NeverDefine_For_Reference
51 For reference I am listing the error codes from the windows winsock.h file here
52
53 /*
54 * All Windows Sockets error constants are biased by WSABASEERR from
55 * the "normal"
56 */
57 #define WSABASEERR 10000
58 /*
59 * Windows Sockets definitions of regular Microsoft C error constants
60 */
61 #define WSAEINTR (WSABASEERR+4)
62 #define WSAEBADF (WSABASEERR+9)
63 #define WSAEACCES (WSABASEERR+13)
64 #define WSAEFAULT (WSABASEERR+14)
65 #define WSAEINVAL (WSABASEERR+22)
66 #define WSAEMFILE (WSABASEERR+24)
67
68 /*
69 * Windows Sockets definitions of regular Berkeley error constants
70 */
71 #define WSAEWOULDBLOCK (WSABASEERR+35)
72 #define WSAEINPROGRESS (WSABASEERR+36)
73 #define WSAEALREADY (WSABASEERR+37)
74 #define WSAENOTSOCK (WSABASEERR+38)
75 #define WSAEDESTADDRREQ (WSABASEERR+39)
76 #define WSAEMSGSIZE (WSABASEERR+40)
77 #define WSAEPROTOTYPE (WSABASEERR+41)
78 #define WSAENOPROTOOPT (WSABASEERR+42)
79 #define WSAEPROTONOSUPPORT (WSABASEERR+43)
80 #define WSAESOCKTNOSUPPORT (WSABASEERR+44)
81 #define WSAEOPNOTSUPP (WSABASEERR+45)
82 #define WSAEPFNOSUPPORT (WSABASEERR+46)
83 #define WSAEAFNOSUPPORT (WSABASEERR+47)
84 #define WSAEADDRINUSE (WSABASEERR+48)
85 #define WSAEADDRNOTAVAIL (WSABASEERR+49)
86 #define WSAENETDOWN (WSABASEERR+50)
87 #define WSAENETUNREACH (WSABASEERR+51)
88 #define WSAENETRESET (WSABASEERR+52)
89 #define WSAECONNABORTED (WSABASEERR+53)
90 #define WSAECONNRESET (WSABASEERR+54)
91 #define WSAENOBUFS (WSABASEERR+55)
92 #define WSAEISCONN (WSABASEERR+56)
93 #define WSAENOTCONN (WSABASEERR+57)
94 #define WSAESHUTDOWN (WSABASEERR+58)
95 #define WSAETOOMANYREFS (WSABASEERR+59)
96 #define WSAETIMEDOUT (WSABASEERR+60)
97 #define WSAECONNREFUSED (WSABASEERR+61)
98 #define WSAELOOP (WSABASEERR+62)
99 #define WSAENAMETOOLONG (WSABASEERR+63)
100 #define WSAEHOSTDOWN (WSABASEERR+64)
101 #define WSAEHOSTUNREACH (WSABASEERR+65)
102 #define WSAENOTEMPTY (WSABASEERR+66)
103 #define WSAEPROCLIM (WSABASEERR+67)
104 #define WSAEUSERS (WSABASEERR+68)
105 #define WSAEDQUOT (WSABASEERR+69)
106 #define WSAESTALE (WSABASEERR+70)
107 #define WSAEREMOTE (WSABASEERR+71)
108
109 #define WSAEDISCON (WSABASEERR+101)
110
111 /*
112 * Extended Windows Sockets error constant definitions
113 */
114 #define WSASYSNOTREADY (WSABASEERR+91)
115 #define WSAVERNOTSUPPORTED (WSABASEERR+92)
116 #define WSANOTINITIALISED (WSABASEERR+93)
117
118 /*
119 * Error return codes from gethostbyname() and gethostbyaddr()
120 * (when using the resolver). Note that these errors are
121 * retrieved via WSAGetLastError() and must therefore follow
122 * the rules for avoiding clashes with error numbers from
123 * specific implementations or language run-time systems.
124 * For this reason the codes are based at WSABASEERR+1001.
125 * Note also that [WSA]NO_ADDRESS is defined only for
126 * compatibility purposes.
127 */
128
129 #define h_errno WSAGetLastError()
130
131 /* Authoritative Answer: Host not found */
132 #define WSAHOST_NOT_FOUND (WSABASEERR+1001)
133 #define HOST_NOT_FOUND WSAHOST_NOT_FOUND
134
135 /* Non-Authoritative: Host not found, or SERVERFAIL */
136 #define WSATRY_AGAIN (WSABASEERR+1002)
137 #define TRY_AGAIN WSATRY_AGAIN
138
139 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
140 #define WSANO_RECOVERY (WSABASEERR+1003)
141 #define NO_RECOVERY WSANO_RECOVERY
142
143 /* Valid name, no data record of requested type */
144 #define WSANO_DATA (WSABASEERR+1004)
145 #define NO_DATA WSANO_DATA
146
147 /* no address, look for MX record */
148 #define WSANO_ADDRESS WSANO_DATA
149 #define NO_ADDRESS WSANO_ADDRESS
150
151 #endif
152 //This ends the Reference Section
153
154
155 static unsigned char * tcperrorstrings [80] = {
156 "",
157 "\x1b" "Host not found. (DNS error)", /* 1 */
158 "\x37" "Non-authoritative host not found. (Temporary DNS error)", /* 2 */
159 "\x22" "Non-recoverable error. (DNS error)", /* 3 */
160 "\x39" "Valid name, no data record of requested type. (DNS error)", /* 4 */
161 "\x12" "Input/output error", /* 5 */
162 "\x15" "Device not configured", /* 6 */
163 "\x16" "Argument list too long", /* 7 */
164 "\x11" "Exec format error", /* 8 */
165 "\x13" "Bad file descriptor", /* 9 */
166 "\x12" "No child processes", /* 10 */
167 "\x19" "Resource deadlock avoided", /* 11 */
168 "\x16" "Cannot allocate memory", /* 12 */
169 "\x11" "Permission denied", /* 13 */
170 "\x0b" "Bad address", /* 14 */
171 "\x15" "Block device required", /* 15 */
172 "\x0b" "Device busy", /* 16 */
173 "\x0b" "File exists", /* 17 */
174 "\x11" "Cross-device link", /* 18 */
175 "\x21" "Operation not supported by device", /* 19 */
176 "\x0f" "Not a directory", /* 20 */
177 "\x0e" "Is a directory", /* 21 */
178 "\x10" "Invalid argument", /* 22 */
179 "\x1d" "Too many open files in system", /* 23 */
180 "\x15" "Too many open sockets", /* 24 */
181 "\x1e" "Inappropriate ioctl for device", /* 25 */
182 "\x0e" "Text file busy", /* 26 */
183 "\x0e" "File too large", /* 27 */
184 "\x17" "No space left on device", /* 28 */
185 "\x0d" "Illegal seek", /* 29 */
186 "\x15" "Read-only file system", /* 30 */
187 "\x0e" "Too many links", /* 31 */
188 "\x0b" "Broken pipe", /* 32 */
189 "",
190 "",
191
192 /* non-blocking and interrupt i/o */
193 "\x20" "Resource temporarily unavailable", /* 35 */
194
195 /* ipc/network software -- argument errors */
196 "\x23" "A blocking operation is in progress", /* 36 */
197 "\x20" "Operation is already in progress", /* 37 */
198
199 /* ipc/network software -- argument errors */
200 "\x20" "Socket operation on a non-socket", /* 38 */
201 "\x1f" "Destination address is required", /* 39 */
202 "\x10" "Message too long", /* 40 */
203 "\x1e" "Protocol wrong type for socket", /* 41 */
204 "\x16" "Protocol not available", /* 42 */
205 "\x16" "Protocol not supported", /* 43 */
206 "\x19" "Socket type not supported", /* 44 */
207 "\x21" "Operation not supported on socket", /* 45 */
208 "\x1d" "Protocol family not supported", /* 46 */
209 "\x2f" "Address family not supported by protocol family", /* 47 */
210 "\x16" "Address already in use", /* 48 */
211 "\x1e" "Can't assign requested address", /* 49 */
212
213 /* ipc/network software -- operational errors */
214 "\x0f" "Network is down", /* 50 */
215 "\x16" "Network is unreachable", /* 51 */
216 "\x23" "Network dropped connection on reset", /* 52 */
217 "\x20" "Software caused connection abort", /* 53 */
218 "\x18" "Connection reset by peer", /* 54 */
219 "\x19" "No buffer space available", /* 55 */
220 "\x1b" "Socket is already connected", /* 56 */
221 "\x17" "Socket is not connected", /* 57 */
222 "\x20" "Can't send after socket shutdown", /* 58 */
223 "\x21" "Too many references: can't splice", /* 59 */
224 "\x14" "Connection timed out", /* 60 */
225 "\x12" "Connection refused", /* 61 */
226
227 "\x21" "Too many levels of symbolic links", /* 62 */
228 "\x12" "File name too long", /* 63 */
229
230 "\x0c" "Host is down", /* 64 */
231 "\x10" "No route to host", /* 65 */
232 "\x13" "Directory not empty", /* 66 */
233 "\x12" "Too many processes", /* 67 */
234 "\x0e" "Too many users", /* 68 */
235 "\x13" "Disc quota exceeded", /* 69 */
236
237 /* Network File System */
238 "\x15" "Stale NFS file handle", /* 70 */
239 "\x21" "Too many levels of remote in path", /* 71 */
240 "\x11" "RPC struct is bad", /* 72 */
241 "\x11" "RPC version wrong", /* 73 */
242 "\x13" "RPC prog. not avail", /* 74 */
243 "\x15" "Program version wrong", /* 75 */
244 "\x19" "Bad procedure for program", /* 76 */
245 "\x12" "No locks available", /* 77 */
246 "\x18" "Function not implemented", /* 78 */
247 "\x21" "Inappropriate file type or format", /* 79 */
248 }; //tcperrorstrings
249
250
251 #define ACCEPT_CONN_WITHOUT_GLOBALS 1
252
253 #ifdef WIN95VERSION
254 #define ACCEPT_IN_SEPARATE_THREAD 1
255 #endif
256
257 #ifdef MACVERSION
258 #ifdef FRONTIER_GUSI_2
259 #include <compat.h>
260 #include <fcntl.h>
261 #include <inttypes.h>
262 #include <netdb.h>
263 #include <netinet/in.h>
264 #include <arpa/inet.h>
265 #include <sys/ioctl.h>
266 #include <sys/socket.h>
267 #include <sys/stat.h>
268 #include <sys/time.h>
269 #include <sys/types.h>
270 #include <sys/un.h>
271 #include <unistd.h>
272 #include <utime.h>
273
274 #include <pthread.h>
275
276 #define GUSI_SpinHook 'spin'
277
278 typedef void (*GUSIHook)(void);
279
280 void GUSISetHook (OSType code, GUSIHook hook);
281
282 #define ACCEPT_IN_SEPARATE_THREAD 1
283
284 #else
285
286 #include <GUSI.h>
287
288 #undef ACCEPT_IN_SEPARATE_THREAD
289
290 #endif
291
292 #include <sys/errno.h>
293 #include "mac.h"
294 #endif
295
296 #include "error.h"
297 #include "file.h"
298 #include "kb.h"
299 #include "ops.h"
300 #include "memory.h"
301 #include "threads.h"
302 #include "strings.h"
303 #include "lang.h"
304 #include "langinternal.h"
305 #include "process.h"
306 #include "processinternal.h"
307 #include "shell.h"
308 #include "shellhooks.h"
309 #ifdef WIN95VERSION
310 #include "FrontierWinMain.h"
311 #endif
312
313 #include "winsocknetevents.h"
314
315
316 #define NO_HOST_SERVICES NULL
317
318 #ifdef WIN95VERSION
319 #define WSAGetHostError() WSAGetLastError()
320
321 typedef struct hostData {
322
323 void * dummy; // strucure not needed under Windows
324 } hostData;
325
326 #define usleep(A) Sleep(A)
327
328 //#if 0
329 typedef int (WINAPI * tyTransmitFile) (SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
330 static tyTransmitFile adrTransmitFile = nil;
331 //#endif
332 #endif
333
334 #ifdef MACVERSION
335
336 #ifdef FRONTIER_GUSI_2
337 typedef struct hostData {
338
339 void * dummy; // strucure not needed under Windows
340 } hostData;
341 #endif
342
343 extern int h_errno;
344
345 extern long sHostID = 0; //cached value in GUSINetDB.cp
346
347 #define WSAEWOULDBLOCK EAGAIN
348 #define WSAENOTCONN ENOTCONN
349 #define WSAETIMEDOUT ETIMEDOUT
350 #define WSAECONNABORTED ECONNABORTED
351 #define WSAENOTSOCK ENOTSOCK
352 #define WSAEMFILE EMFILE
353 #define WSAGetLastError() (errno == EINTR? userCanceledErr : errno)
354 #define WSAGetHostError() h_errno
355
356 #define wsprintf sprintf
357
358 #define INVALID_SOCKET (SOCKET)(~0)
359 #define SOCKET_ERROR (-1)
360
361 #define SD_READ 0
362 #define SD_SEND 1
363 #define SD_BOTH 2
364
365 #define closesocket(foo) close(foo)
366 #define ioctlsocket(d,request,argp) ioctl(d,request,argp)
367 typedef int SOCKET;
368
369 /* Microsoft Windows Extended data types */
370 #define FAR
371
372 typedef struct sockaddr SOCKADDR;
373 typedef struct sockaddr *PSOCKADDR;
374 typedef struct sockaddr FAR *LPSOCKADDR;
375
376 typedef struct sockaddr_in SOCKADDR_IN;
377 typedef struct sockaddr_in *PSOCKADDR_IN;
378 typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
379
380 typedef struct linger LINGER;
381 typedef struct linger *PLINGER;
382 typedef struct linger FAR *LPLINGER;
383
384 typedef struct in_addr IN_ADDR;
385 typedef struct in_addr *PIN_ADDR;
386 typedef struct in_addr FAR *LPIN_ADDR;
387 #endif
388
389 #define SOCKTYPE_INVALID -1
390 #define SOCKTYPE_UNKNOWN 0
391 #define SOCKTYPE_OPEN 1
392 #define SOCKTYPE_DATA 2
393 #define SOCKTYPE_LISTENING 3
394 #define SOCKTYPE_CLOSED 4
395 #define SOCKTYPE_LISTENSTOPPED 5
396 #define SOCKTYPE_INACTIVE 6
397
398 #define FRONTIER_MAX_STREAM 256
399 #define INTNETERROR_INVALIDSTREAM -1
400
401 typedef short tysocktypeid;
402
403 typedef struct tysockRecord {
404 SOCKET sockID;
405 tysocktypeid typeID;
406 long refcon;
407 bigstring callback;
408 long maxdepth;
409 long listenReference;
410 long currentListenDepth;
411 boolean flNotification;
412 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
413 Handle hcallbacktree;
414 #endif
415 #ifdef ACCEPT_IN_SEPARATE_THREAD
416 long idthread;
417 hdldatabaserecord hdatabase;
418 #endif
419 } sockRecord;
420
421
422 static short frontierWinSockCount = 0;
423 static boolean frontierWinSockLoaded = false;
424 static sockRecord sockstack[FRONTIER_MAX_STREAM];
425
426
427 #ifdef MACVERSION
428 static short sockListenCount = 0;
429 static short sockListenList[FRONTIER_MAX_STREAM];
430 #endif
431
432
433 #ifdef WIN95VERSION
434
435 static CRITICAL_SECTION sockstacksection;
436
437 static boolean sockstacksectioninitialized = false;
438
439 static void _entercriticalsockstacksection (void) {
440
441 if (!sockstacksectioninitialized) {
442
443 InitializeCriticalSection (&sockstacksection);
444
445 sockstacksectioninitialized = true;
446 }
447
448 EnterCriticalSection (&sockstacksection);
449 }
450
451 static void _leavecriticalsockstacksection (void) {
452
453 LeaveCriticalSection (&sockstacksection);
454 }
455
456 #else
457
458 #define _entercriticalsockstacksection()
459
460 #define _leavecriticalsockstacksection()
461
462 #endif
463
464
465 static char * TCPGETTYPE (tysocktypeid typeID) {
466 switch (typeID) {
467 case SOCKTYPE_INVALID:
468 return ("INVALID");
469
470 case SOCKTYPE_UNKNOWN:
471 return ("UNKNOWN");
472
473 case SOCKTYPE_OPEN:
474 return ("OPEN");
475
476 case SOCKTYPE_DATA:
477 return ("DATA");
478
479 case SOCKTYPE_LISTENING:
480 return ("LISTENING");
481
482 case SOCKTYPE_CLOSED:
483 return ("CLOSED");
484
485 case SOCKTYPE_LISTENSTOPPED:
486 return ("LISTEN-STOPPED");
487
488 case SOCKTYPE_INACTIVE:
489 return ("INACTIVE");
490
491 default:
492 break;
493 }
494
495 return ("BAD Type value");
496 } /*TCPGETTYPE*/
497
498
499
500 #define STR_P_ERROR_CLOSED_PREMATURELY "\x45" "Can't read stream because the TCP connection was closed unexpectedly."
501
502 /*
503 To disable the tcp tracker, don't define TCPTRACKER.
504
505 To enable tcp tracker ouput in the about window, define TCPTRACKER == 1.
506
507 To enable tcp tracker error ouput to a file, define TCPTRACKER == 2.
508
509 To enable full tcp tracker output to a file, define TCPTRACKER == 3.
510 */
511
512
513 //#undef TCPTRACKER
514 #define TCPTRACKER 1
515 //#define TCPTRACKER 2
516 //#define TCPTRACKER 3
517
518 #if (TCPTRACKER == 3)
519 #pragma message ("*********************** TCPTRACKER is ON: Full output to tcpfile.txt ***********************")
520
521 static boolean fllogger = true;
522
523 #ifdef WIN95VERSION
524 extern DWORD ixthreadglobalsgrabcount; // Tls index of counter for nest globals grabbing
525 #endif
526
527 static FILE * tcpfile = NULL;
528 static char TCPmsg[400];
529
530 #define TCPprintf(msg) msg
531 #define TCPERRORprintf(msg) msg
532
533 static void TCPWRITEMSG () {
534 unsigned long ticks = gettickcount ();
535 static unsigned long lastticks = 0;
536 #ifdef WIN95VERSION
537 DWORD idthread;
538 static DWORD idlastthread = 0;
539 long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
540 #endif
541 #ifdef MACVERSION
542 long idthread = (long) (**getcurrentthread ()).idthread;
543 static long idlastthread = 0;
544 #endif
545
546 if (fllogger) {
547 #ifdef WIN95VERSION
548 idthread = GetCurrentThreadId();
549 #endif
550
551 if (tcpfile == NULL) {
552 tcpfile = fopen ("tcpfile.txt", "w+");
553 }
554
555 if (idthread != idlastthread) {
556 fprintf (tcpfile, "\n");
557 idlastthread = idthread;
558 }
559
560 #ifdef WIN95VERSION
561 fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
562 #endif
563
564 #ifdef MACVERSION
565 fprintf (tcpfile, "%08X (%04ld) | %04X | %s", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
566 #endif
567
568 lastticks = ticks;
569
570 fflush (tcpfile);
571 }
572 } /*TCPWRITEMSG*/
573
574 #define TCPERRORWRITEMSG TCPWRITEMSG
575
576 void TCPTRACKERIN (char * functionName, int linenumber, unsigned long streamID) {
577 if (fllogger) {
578 if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
579 wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld - INVALID STREAM.\n", functionName, linenumber, streamID);
580 TCPWRITEMSG ();
581 return;
582 }
583
584 #ifdef WIN95VERSION
585 wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Notification is %s, Listen Ref is %08lX, Refcon = %08lX.\n",
586 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
587 sockstack[streamID].currentListenDepth, sockstack[streamID].flNotification ? "ON" : "OFF",
588 sockstack[streamID].listenReference, sockstack[streamID].refcon);
589 #else
590 wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Listen Ref is %08lX, Refcon = %08lX.\n",
591 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
592 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
593 #endif
594
595 TCPWRITEMSG ();
596 }
597 } /*TCPTRACKERIN*/
598
599
600 void TCPTRACKEROUT (char * functionName, int linenumber, unsigned long streamID) {
601 if (fllogger) {
602 if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
603 wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %08lX - INVALID STREAM.\n", functionName, linenumber, streamID);
604 TCPWRITEMSG ();
605 return;
606 }
607
608 #ifdef WIN95VERSION
609 wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Notification is %s, Listen Ref is %08lX, Refcon = %08lX.\n",
610 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
611 sockstack[streamID].currentListenDepth, sockstack[streamID].flNotification ? "ON" : "OFF",
612 sockstack[streamID].listenReference, sockstack[streamID].refcon);
613 #else
614 wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Listen Ref is %08lX, Refcon = %08lX.\n",
615 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
616 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
617 #endif
618
619 TCPWRITEMSG ();
620 }
621 } /*TCPTRACKEROUT*/
622
623 static void TCPTRACKERCLOSE () {
624 if (fllogger) {
625 if (tcpfile != NULL)
626 fclose (tcpfile);
627 }
628 }
629
630
631 #elif (TCPTRACKER == 2)
632 #pragma message ("*********************** TCPTRACKER is ON: Error output to tcpfile.txt **********************")
633
634 static boolean fllogger = true;
635
636 #ifdef WIN95VERSION
637 extern DWORD ixthreadglobalsgrabcount; // Tls index of counter for nest globals grabbing
638 #endif
639
640 static FILE * tcpfile = NULL;
641 static char TCPmsg[400];
642
643 #define TCPprintf(msg)
644 #define TCPWRITEMSG()
645 #define TCPTRACKERIN(functionName, linenumber, streamID)
646 #define TCPTRACKEROUT(functionName, linenumber, streamID)
647
648 #define TCPERRORprintf(msg) msg
649
650 static void TCPERRORWRITEMSG () {
651 unsigned long ticks = gettickcount ();
652 static unsigned long lastticks = 0;
653 #ifdef WIN95VERSION
654 DWORD idthread;
655 static DWORD idlastthread = 0;
656 long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
657 #endif
658 #ifdef MACVERSION
659 long idthread = (long) (**getcurrentthread ()).idthread;
660 static long idlastthread = 0;
661 #endif
662
663 if (fllogger) {
664 #ifdef WIN95VERSION
665 idthread = GetCurrentThreadId();
666 #endif
667
668 if (tcpfile == NULL) {
669 tcpfile = fopen ("tcpfile.txt", "w+");
670 }
671
672 if (idthread != idlastthread) {
673 fprintf (tcpfile, "\n");
674 idlastthread = idthread;
675 }
676
677 #ifdef WIN95VERSION
678 fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
679 #endif
680
681 #ifdef MACVERSION
682 fprintf (tcpfile, "%08X (%04ld) | %04X | %s", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
683 #endif
684
685 lastticks = ticks;
686
687 fflush (tcpfile);
688 }
689 } /*TCPWRITEMSG*/
690
691
692 static void TCPTRACKERCLOSE () {
693 if (fllogger) {
694 if (tcpfile != NULL)
695 fclose (tcpfile);
696 }
697 }
698
699 #elif (TCPTRACKER == 1)
700 #pragma message ("*********************** TCPTRACKER is ON: Full output to About window **********************")
701
702 #include "about.h"
703 #define fllogger (aboutstatsshowing())
704 #define TCPprintf(msg) msg
705 #define TCPERRORprintf(msg) msg
706
707 static char TCPmsg[400];
708
709 static void TCPWRITEMSG () {
710
711 if (fllogger) {
712
713 convertcstring (TCPmsg);
714
715 aboutsetmiscstring (TCPmsg);
716 }
717 } /*TCPWRITEMSG*/
718
719 #define TCPERRORWRITEMSG TCPWRITEMSG
720
721 static void TCPTRACKERIN (char * functionName, int linenumber, unsigned long streamID) {
722 if (fllogger) {
723 if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
724 wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld - INVALID STREAM.\n", functionName, linenumber, streamID);
725 TCPWRITEMSG ();
726 return;
727 }
728
729 wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Listen Ref is %08lX, Refcon = %08lX.\n",
730 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
731 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
732
733 TCPWRITEMSG ();
734 }
735 } /*TCPTRACKERIN*/
736
737
738 static void TCPTRACKEROUT (char * functionName, int linenumber, unsigned long streamID) {
739 if (fllogger) {
740 if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
741 wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %08lX - INVALID STREAM.\n", functionName, linenumber, streamID);
742 TCPWRITEMSG ();
743 return;
744 }
745
746 wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %ld, Socket = %ld, Type is %s, Max Depth is %d, Current Depth is %d, Listen Ref is %08lX, Refcon = %08lX.\n",
747 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
748 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
749
750 TCPWRITEMSG ();
751 }
752 } /*TCPTRACKEROUT*/
753
754 #define TCPTRACKERCLOSE()
755
756 #else
757
758 #define TCPprintf(msg)
759 #define TCPERRORprintf(msg)
760 #define TCPWRITEMSG()
761 #define TCPERRORWRITEMSG()
762 #define TCPTRACKERIN(functionName, linenumber, streamID)
763 #define TCPTRACKEROUT(functionName, linenumber, streamID)
764 #define TCPTRACKERCLOSE()
765
766 #endif
767
768
769 static boolean getsockrecord (SOCKET sock, long *stream) {
770 long i;
771
772 for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
773 if (sockstack[i].sockID == sock) {
774 *stream = i;
775 return (true);
776 }
777 }
778
779 *stream = -1;
780
781 return (false);
782 } /*getsockrecord*/
783
784
785 static void initsockrecord (long i) {
786
787 /*
788 5.0.2b21 dmb: share repeated code
789 */
790
791 sockstack[i].sockID = INVALID_SOCKET;
792 sockstack[i].typeID = SOCKTYPE_UNKNOWN;
793 sockstack[i].maxdepth = 0;
794 sockstack[i].listenReference = 0;
795 sockstack[i].currentListenDepth = 0;
796 sockstack[i].refcon = 0;
797 copystring (emptystring, sockstack[i].callback);
798 sockstack[i].flNotification = false;
799 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
800 sockstack[i].hcallbacktree = nil;
801 #endif
802 #ifdef ACCEPT_IN_SEPARATE_THREAD
803 sockstack[i].idthread = nil;
804 sockstack[i].hdatabase = nil;
805 #endif
806 } /*initsockrecord*/
807
808
809 static boolean addsockrecord (long *stream) {
810
811 /*
812 5.1.5 dmb: reuse closed sockets before inactive ones.
813
814 6.2a12 AR: This is the bottleneck for grabbing a new or used socket record.
815 On Win32, protect the socket stack by declaring a critical section.
816 */
817
818 long i;
819
820 _entercriticalsockstacksection();
821
822 for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
823 if (sockstack[i].typeID == SOCKTYPE_INVALID) {
824 initsockrecord (i);
825 *stream = i;
826 _leavecriticalsockstacksection();
827 return (true);
828 }
829 }
830
831 /* If none are inactive, reuse those that are closed */
832
833 for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
834 if (sockstack[i].typeID == SOCKTYPE_CLOSED) {
835 initsockrecord (i);
836 *stream = i;
837 _leavecriticalsockstacksection();
838 return (true);
839 }
840 }
841
842 /* If we used up all the stack, reuse those that are inactive */
843
844 for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
845 if (sockstack[i].typeID == SOCKTYPE_INACTIVE) {
846 initsockrecord (i);
847 *stream = i;
848 _leavecriticalsockstacksection();
849 return (true);
850 }
851 }
852
853 _leavecriticalsockstacksection();
854
855 *stream = -1;
856
857 return (false);
858 } /*addsockrecord*/
859
860
861 static void clearsockstack () {
862 long i;
863
864 _entercriticalsockstacksection();
865
866 for (i = 0; i < FRONTIER_MAX_STREAM; i++) {
867 sockstack[i].sockID = INVALID_SOCKET;
868 sockstack[i].typeID = SOCKTYPE_INVALID;
869 }
870
871 _leavecriticalsockstacksection();
872
873 #ifdef MACVERSION
874 sockListenCount = 0;
875 #endif
876 } /*clearsockstack*/
877
878
879 static void gettcperrorstring (int errcode, bigstring bs) {
880
881 int ixtcperr = errcode;
882
883 #ifdef WIN95VERSION
884 if (errcode >= WSAHOST_NOT_FOUND && errcode <= WSANO_DATA)
885 ixtcperr -= 1000;
886
887 ixtcperr -= WSABASEERR;
888 #endif
889
890 if (ixtcperr > 0 && ixtcperr < 80) {
891
892 copystring (tcperrorstrings [ixtcperr], bs); //handles nil source
893
894 if (!isemptystring (bs)) {
895
896 pushchar ('.', bs);
897
898 return;
899 }
900 }
901
902 #ifdef MACVERSION
903 getsystemerrorstring (errcode, bs);
904 #endif
905
906 #ifdef WIN95VERSION
907 getwinerrormessage (errcode, bs);
908
909 firstword (bs, '.', bs); //skip the cr
910 #endif
911
912 } /*gettcperrorstring*/
913
914
915 static void plainneterror (bigstring bs) {
916
917 /*
918 6.1b15 AR
919 */
920
921 bigstring errbs;
922
923 copystring (bs, errbs);
924
925 nullterminate (errbs);
926
927 TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s.\n", stringbaseaddress(errbs)));
928 TCPERRORWRITEMSG ();
929
930 langerrormessage (bs);
931 } /*neterror*/
932
933
934 static void neterror (char * cannot, long errcode) {
935
936 bigstring bs;
937 bigstring errbs;
938 char prestring[256];
939
940 wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode);
941 copyctopstring (prestring, errbs);
942
943 gettcperrorstring (errcode, bs);
944
945 //if (equaltextidentifiers (stringbaseaddress(bs), "No information available for error number", (short)strlen("No information available for error number")) != true) {
946 if (!isemptystring (bs)) {
947
948 pushstring ("\x03" " - ", errbs);
949
950 pushstring (bs, errbs);
951 }
952 else {
953 pushchar ('.', errbs);
954 }
955
956 nullterminate (errbs);
957
958 TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s.\n", stringbaseaddress(errbs)));
959 TCPERRORWRITEMSG ();
960
961 langerrormessage (errbs);
962 } /*neterror*/
963
964
965 static void intneterror (long errcode) {
966 bigstring bs;
967
968 if (errcode == INTNETERROR_INVALIDSTREAM)
969 copyctopstring ("Invalid stream", bs);
970 else
971 copyctopstring ("Unknown stream error", bs);
972
973 langerrormessage (bs);
974 } /*intneterror*/
975
976
977 #ifdef MACVERSION
978
979 #ifdef FRONTIER_GUSI_2
980
981 static void fwsGUSI2Spin (boolean flresting) {
982 short mask = osMask|activMask|mDownMask|keyDownMask;
983
984 if (inmainthread ()) {
985
986 if (flresting) {
987 EventRecord ev;
988
989 if (WaitNextEvent (mask, &ev, 1L, nil))
990 shellprocessevent (&ev);
991 }
992 else
993 shellyield (false);
994 }
995 else {
996 /* if (flresting) {
997
998 boolean fl;
999 hdlthreadglobals hthread = getcurrentthreadglobals ();
1000 ThreadID idthread = (ThreadID) (**hthread).idthread;
1001 const long sleepTime = 6L;
1002 //hdlthreadqueue hq;
1003
1004 //if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &hq))
1005 // return (memFullErr);
1006
1007 //(**hq).idthread = idthread;
1008
1009 TCPprintf (wsprintf(TCPmsg, "Going to sleep for %d ticks.\n", sleepTime));
1010 TCPWRITEMSG();
1011
1012 //listlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
1013
1014 fl = processsleep (hthread, sleepTime);
1015
1016 if (!fl) {
1017
1018 //if (listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq))
1019 //disposehandle ((Handle) hq);
1020
1021 fl = langbackgroundtask (true);
1022 }
1023
1024 TCPprintf (wsprintf(TCPmsg, "Awake! at line %d.\n", __LINE__));
1025 TCPWRITEMSG();
1026
1027 // gusiwakethread = 0;
1028 }
1029 else */
1030 langbackgroundtask (true);
1031 }
1032 }/*fwsGUSI2Spin*/
1033
1034 #else
1035
1036 #if __powerc
1037 void RotateCursor (short);
1038 void RotateCursor (short i) {} // for GUSI
1039 #else
1040 void ROTATECURSOR (short);
1041 void ROTATECURSOR (short i) {} // for GUSI
1042 #endif
1043
1044 typedef struct tythreadqueuerecord {
1045
1046 struct tythreadqueuerecord **hnext;
1047
1048 ThreadID idthread;
1049 } tythreadqueuerecord, *ptrthreadqueue, **hdlthreadqueue;
1050
1051
1052 static hdlthreadqueue gusisleepqueue = nil;
1053 static hdlthreadqueue gusiwakequeue = nil;
1054
1055
1056 static int fwsGUSISpin (spin_msg msg, long arg) {
1057
1058 long sleepTime = 6; // 1/10 of a second by default
1059 boolean flresting = true;
1060 short mask = osMask|activMask|mDownMask|keyDownMask; //|highLevelEventMask|updateMask
1061 extern int GUSI_error (int);
1062 boolean fl = true;
1063
1064 if (languserescaped (false))
1065 return GUSI_error (-128);
1066
1067 /*
1068 switch (msg) {
1069 case SP_SLEEP:
1070 case SP_SELECT:
1071 if (arg >= sleepTime) // Only sleep if patience guaranteed
1072 break;
1073 // Otherwise, fall through
1074 case SP_AUTO_SPIN:
1075 sleepTime = 0;
1076 flresting = false;
1077 break;
1078 //case SP_STREAM_WRITE:
1079 // if (arg >= sleepTime)
1080 // sleepTime = 120;
1081 // break;
1082 case SP_MISC:
1083 sleepTime = 0;
1084 break;
1085
1086 default:
1087 break;
1088 }
1089 */
1090
1091 switch (msg) {
1092
1093 case SP_AUTO_SPIN:
1094 return noErr;
1095
1096 case SP_MISC:
1097 if (arg < 0) {
1098 sleepTime = 0;
1099 flresting = false;
1100 }
1101 else
1102 sleepTime = 6;
1103
1104 break;
1105
1106 case SP_NAME:
1107 case SP_ADDR:
1108 case SP_STREAM_READ:
1109 case SP_STREAM_WRITE:
1110 if (arg < 0)
1111 sleepTime = 0;
1112 else
1113 sleepTime = 120;
1114 break;
1115
1116 default:
1117 flresting = false;
1118 }
1119
1120 if (inmainthread ()) {
1121
1122 if (flresting) {
1123 EventRecord ev;
1124
1125 if (WaitNextEvent (mask, &ev, sleepTime, nil))
1126 shellprocessevent (&ev);
1127 }
1128 // else
1129 // fl = shellyield (false);
1130 }
1131
1132 else {
1133 if (flresting) {
1134
1135 hdlthreadglobals hthread = getcurrentthreadglobals ();
1136 ThreadID idthread = (ThreadID) (**hthread).idthread;
1137 hdlthreadqueue hq;
1138
1139 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &hq))
1140 return (memFullErr);
1141
1142 (**hq).idthread = idthread;
1143
1144 TCPprintf (wsprintf(TCPmsg, "Going to sleep for %d ticks.\n", sleepTime));
1145 TCPWRITEMSG();
1146
1147 listlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
1148
1149 fl = processsleep (hthread, sleepTime);
1150
1151 if (!fl) {
1152
1153 if (listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq))
1154 disposehandle ((Handle) hq);
1155
1156 fl = langbackgroundtask (true);
1157 }
1158
1159 TCPprintf (wsprintf(TCPmsg, "Awake! at line %d.\n", __LINE__));
1160 TCPWRITEMSG();
1161
1162 // gusiwakethread = 0;
1163 }
1164 else
1165 fl = langbackgroundtask (true);
1166 }
1167
1168 if (fl)
1169 return noErr;
1170 else
1171 return -128;
1172 } /*fwsGUSISpin*/
1173
1174
1175 //#define GUSISLEEPQUEUESIZE 128
1176 //static ThreadID gusisleepqueue [GUSISLEEPQUEUESIZE];
1177
1178 //static long ixlastcompleted = -1;
1179 //static long ixlastwoken = -1;
1180
1181 static void wakecompletedthreads (void) {
1182
1183 /*
1184 walk through the circular gusisleepqueue and wake any newly-completed threads
1185 */
1186
1187 /*
1188 for ( ; ixlastwoken != ixlastcompleted; ixlastwoken = (ixlastwoken + 1) % GUSISLEEPQUEUESIZE) {
1189
1190 ThreadID id = gusisleepqueue [ixlastwoken];
1191 */
1192 hdlthreadqueue hq, hnext;
1193
1194 for (hq = (**gusiwakequeue).hnext; hq != nil; hq = hnext) {
1195
1196 ThreadID id = (**hq).idthread;
1197 hdlthreadglobals hg = getprocessthread (id);
1198
1199 hnext = (**hq).hnext;
1200
1201 listunlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
1202
1203 disposehandle ((Handle) hq);
1204
1205 if (hg && processwake (hg)) {
1206 TCPprintf (wsprintf(TCPmsg, "Waking thread at line %d. Thread ID: %04X.\n", __LINE__, id));
1207 TCPWRITEMSG();
1208 }
1209 else {
1210 TCPERRORprintf (wsprintf(TCPmsg, "Error waking thread at line %d. Thread ID: %04X.\n", __LINE__, id));
1211 TCPERRORWRITEMSG();
1212 }
1213 }
1214 } /*wakecompletedthreads*/
1215
1216
1217 static OSErr fwsGUSIWakeThread (ThreadID idthread) {
1218
1219 /*
1220 gusisleepqueue [ixlastcompleted] = idthread;
1221
1222 ixlastcompleted = (ixlastcompleted + 1) % GUSISLEEPQUEUESIZE;
1223 */
1224
1225 /*
1226 5.1.5b10 dmb: can't do much in a completion routine. just move thread
1227 from sleepqueue to wakequeue.
1228 */
1229
1230 hdlthreadqueue hq;
1231
1232 for (hq = (**gusisleepqueue).hnext; hq != nil; hq = (**hq).hnext) {
1233
1234 if ((**hq).idthread == idthread) {
1235
1236 listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
1237
1238 listlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
1239
1240 break;
1241 }
1242 }
1243
1244 return (noErr);
1245 } /*fwsGUSIWakeThread*/
1246
1247
1248 static boolean fwsGUSIWakeupHook (hdlprocessthread hthread) {
1249
1250 /*
1251 if this thread is in our sleep queue, wake it up and return false
1252
1253 just to be extra careful, handle the case where the thread is already
1254 in the wake queue
1255 */
1256
1257 hdlthreadqueue hq;
1258 ThreadID idthread = (ThreadID) (**hthread).idthread;
1259
1260 for (hq = (**gusisleepqueue).hnext; hq != nil; hq = (**hq).hnext) {
1261
1262 if ((**hq).idthread == idthread) { //move it to wake queue
1263
1264 listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
1265
1266 listlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
1267
1268 break;
1269 }
1270 }
1271
1272 for (hq = (**gusiwakequeue).hnext; hq != nil; hq = (**hq).hnext) {
1273
1274 if ((**hq).idthread == idthread) { //found it in wake queue, wake it
1275
1276 listunlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
1277
1278 disposehandle ((Handle) hq);
1279
1280 if (processwake (hthread)) {
1281 TCPprintf (wsprintf(TCPmsg, "Hook: waking thread at line %d. Thread ID: %04X.\n", __LINE__, idthread));
1282 TCPWRITEMSG();
1283 }
1284 else {
1285 TCPERRORprintf (wsprintf(TCPmsg, "Hook: error waking thread at line %d. Thread ID: %04X.\n", __LINE__, idthread));
1286 TCPERRORWRITEMSG();
1287 }
1288
1289 return (false); //hooked
1290 }
1291 }
1292
1293 return (true); //not hooked
1294 } /*fwsGUSIWakeupHook*/
1295
1296
1297 #endif
1298 #endif
1299
1300
1301 #ifdef PIKE
1302
1303 /*extern const*/ /*long maxconnections = 5;*/
1304
1305 long maxconnections = longinfinity; /*7.1b5 PBS: no more connection limit*/
1306
1307 #else
1308
1309 /*extern const*/ long maxconnections = longinfinity; /*7.0b37 PBS: reported in system.environment table in Frontier*/
1310 /*7.1b2 RAB: made global variables*/
1311
1312 #endif
1313
1314 /*7.0b37 PBS: Count connections in both Radio and Frontier.*/
1315
1316 extern long ctconnections = 0;
1317
1318
1319 static boolean incrementconnectioncounter (void) {
1320
1321 if (ctconnections >= maxconnections)
1322 return (false);
1323
1324 ctconnections++;
1325
1326 return (true);
1327 } /*incrementconnectioncounter*/
1328
1329 static void decrementconnectioncounter (void) {
1330
1331 ctconnections--;
1332
1333 assert (ctconnections >= 0);
1334
1335 } /*decrementconnectioncounter*/
1336
1337
1338 long fwsNetEventGetConnectionCount (void) {
1339
1340 /*7.0b37 PBS: return current count of TCP connections.
1341 Used by tcp.countConnections verb.
1342 */
1343
1344 return (ctconnections);
1345 } /*fwsNetEventGetConnectionCount*/
1346
1347
1348 static boolean fwsNetEventLaunch (struct hostData *data) {
1349
1350 /*
1351 Initialize the NetEvents system
1352
1353 5.0.2b5 dmb: added hostData parameter and GUSI support to handle threading
1354 */
1355
1356 #ifdef WIN95VERSION
1357 WSADATA wsaData;
1358 WORD VersionRequested;
1359 #endif
1360
1361 if (! frontierWinSockLoaded) {
1362
1363 #ifdef WIN95VERSION
1364 //#if 0
1365 HMODULE hmodule;
1366 //#endif
1367
1368 #if (TCPTRACKER >= 2) //if reporting to file
1369 long l;
1370 if (getProfileLong ("\x0a" "TCPTracker", &l)) {
1371 fllogger = (boolean) l;
1372 }
1373 else {
1374 setProfileLong ("\x0a" "TCPTracker", fllogger); /*this just sets the value in the registry*/
1375 }
1376 #endif
1377
1378 VersionRequested = MAKEWORD(WINSOCK_VERSION_MAJOR, WINSOCK_VERSION_MINOR);
1379
1380 if (WSAStartup (VersionRequested, &wsaData) == SOCKET_ERROR) {
1381 neterror("start WinSock", WSAGetLastError ());
1382 WSACleanup();
1383 return (false);
1384 }
1385
1386 if ((LOBYTE(wsaData.wVersion) != WINSOCK_VERSION_MAJOR) || (HIBYTE(wsaData.wVersion) != WINSOCK_VERSION_MINOR)) {
1387 /* Tell the user that we couldn't find a useable WinSock DLL. */
1388 WSACleanup( );
1389 return(false);
1390 }
1391
1392 /*
1393 The TransmitFile function is only available on Windows NT.
1394 */
1395
1396 //#if 0
1397
1398 hmodule = GetModuleHandle ("wsock32.dll");
1399
1400 if (hmodule != nil)
1401 adrTransmitFile = (tyTransmitFile) GetProcAddress (hmodule, "TransmitFile");
1402
1403 //#endif
1404
1405 #endif
1406
1407 #ifdef MACVERSION
1408 #ifdef FRONTIER_GUSI_2
1409 //GUSISetHook (GUSI_SpinHook, (GUSIHook) fwsGUSI2Spin);
1410 #else
1411 GUSISetup (GUSIwithInternetSockets);
1412
1413 GUSISetHook (GUSI_SpinHook, (GUSIHook) fwsGUSISpin);
1414
1415 GUSISetHook (GUSI_WakeThreadHook, (GUSIHook) fwsGUSIWakeThread);
1416
1417 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &gusisleepqueue))
1418 return (false);
1419
1420 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &gusiwakequeue))
1421 return (false);
1422
1423 shellpushwakeuphook (&fwsGUSIWakeupHook);
1424 #endif
1425
1426 #endif
1427
1428 clearsockstack();
1429 }
1430
1431 #ifdef MACVERSION
1432 #ifndef FRONTIER_GUSI_2
1433 sethostdata (data);
1434 #endif
1435 #endif
1436
1437 ++frontierWinSockCount;
1438 frontierWinSockLoaded = true;
1439
1440 return (true);
1441 } /*fwsNetEventLaunch*/
1442
1443
1444 /*
1445 boolean fwsNetEventIsRunning (void) {
1446
1447 /* Indicate if we are between a fwsNetEventLaunch and a fwsNetEventQuit * /
1448
1449 return (frontierWinSockLoaded);
1450 } /*fwsNetEventIsRunning*/
1451
1452
1453 #ifdef MACVERSION
1454
1455 boolean fwsNetEventQuit (void) {
1456
1457 /*
1458 5.0.2b10: this function is being reborn to close all listeners on the Mac
1459 */
1460
1461 // for (i = 0; i < sockListenCount; i++) {
1462 // listenstream = sockListenList[i];
1463
1464 while (sockListenCount > 0)
1465 fwsNetEventCloseListen (sockListenList [0]);
1466
1467 return (true);
1468 } /*fwsNetEventQuit*/
1469
1470 #endif
1471
1472
1473 boolean fwsNetEventShutDown (void) {
1474
1475 /*
1476 shut down the NetEvents system
1477 This is for Frontier Internal use ONLY
1478 */
1479
1480 frontierWinSockCount = 0;
1481
1482 TCPTRACKERCLOSE();
1483
1484 if (frontierWinSockLoaded) {
1485 #ifdef WIN95VERSION
1486 WSACleanup();
1487 #endif
1488
1489 return (true);
1490 }
1491
1492 return (false);
1493 } /*fwsNetEventShutDown*/
1494
1495
1496 boolean fwsNetEventAddressDecode (unsigned long addr, bigstring IPaddr) {
1497
1498 /* Convert an address (4 byte) into a dotted IP address */
1499
1500 char * sysstring;
1501 struct in_addr in;
1502 struct hostData hostdata;
1503
1504 if (!fwsNetEventLaunch (&hostdata))
1505 return (false);
1506
1507 in.s_addr = htonl(addr);
1508
1509 sysstring = inet_ntoa (in);
1510
1511 setstringlength (IPaddr,0);
1512
1513 if (sysstring == NULL) {
1514
1515 langlongparamerror (cantdecodeaddress, addr);
1516
1517 return (false);
1518 }
1519
1520 copyctopstring (sysstring, IPaddr);
1521
1522 return (true);
1523 } /*fwsNetEventAddressDecode*/
1524
1525
1526 boolean fwsNetEventAddressEncode (bigstring IPaddr, unsigned long * addr) {
1527
1528 /* Convert a dotted IP address into an address (4 byte) */
1529
1530 unsigned long netaddr;
1531 char sysstring[256];
1532 #ifdef MACVERSION
1533 #ifndef FRONTIER_GUSI_2
1534 struct in_addr foo;
1535 #endif
1536 #endif
1537 struct hostData hostdata;
1538
1539 if (!fwsNetEventLaunch (&hostdata))
1540 return (false);
1541
1542 copyptocstring (IPaddr, sysstring);
1543
1544 #ifdef MACVERSION
1545 #ifdef FRONTIER_GUSI_2
1546 netaddr = inet_addr (sysstring);
1547 #else
1548 foo = inet_addr (sysstring);
1549 netaddr = foo.s_addr;
1550 #endif
1551 #endif
1552
1553 #ifdef WIN95VERSION
1554 netaddr = inet_addr (sysstring);
1555 #endif
1556
1557 if (netaddr == INADDR_NONE) {
1558
1559 langparamerror (cantencodeaddress, IPaddr);
1560
1561 return (false);
1562 }
1563
1564 *addr = ntohl (netaddr);
1565
1566 return (true);
1567 } /*fwsNetEventAddressEncode*/
1568
1569
1570 boolean fwsNetEventAddressToName (unsigned long addr, bigstring domainName) {
1571
1572 /*
1573 Convert an address (4 byte) into a domain name
1574
1575 5.1.5 dmb: release thread globals!
1576 */
1577
1578 struct hostent * h;
1579 unsigned long netaddr;
1580 struct hostData hostdata;
1581 long errcode;
1582
1583
1584 if (!fwsNetEventLaunch (&hostdata))
1585 return (false);
1586
1587 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventAddressToName at line %d. Address: %ld.\n", __LINE__, addr));
1588 TCPWRITEMSG();
1589
1590 releasethreadglobalsnopriority();
1591
1592 netaddr = htonl(addr);
1593
1594 h = gethostbyaddr ((char *) &netaddr, 4, PF_INET);
1595
1596 errcode = WSAGetHostError ();
1597
1598 grabthreadglobalsnopriority();
1599
1600 if (h == NULL) {
1601 neterror("convert address", errcode);
1602 return (false);
1603 }
1604
1605 copyctopstring (h->h_name, domainName);
1606
1607 TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventAddressToName at line %d. Domain name: %s.\n", __LINE__, h->h_name));
1608 TCPWRITEMSG();
1609
1610 return (true);
1611 } /*fwsNetEventAddressToName*/
1612
1613
1614 boolean fwsNetEventNameToAddress (bigstring domainName, unsigned long * addr) {
1615
1616 /*
1617 Convert a domain name into an address (4 byte)
1618
1619 5.1.5 dmb: release thread globals!
1620 */
1621
1622 struct hostent * h;
1623 char sysstring[256];
1624 struct hostData hostdata;
1625 long errcode;
1626
1627 if (!fwsNetEventLaunch (&hostdata))
1628 return (false);
1629
1630 copyptocstring (domainName, sysstring);
1631
1632 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventNameToAddress at line %d. Domain name: %s.\n", __LINE__, sysstring));
1633 TCPWRITEMSG();
1634
1635 releasethreadglobalsnopriority();
1636
1637 h = gethostbyname (sysstring);
1638
1639 errcode = WSAGetHostError ();
1640
1641 grabthreadglobalsnopriority();
1642
1643 if (h == NULL) {
1644 neterror("convert name", errcode);
1645 return (false);
1646 }
1647
1648 *addr = ntohl (*((long *)h->h_addr_list[0]));
1649
1650 TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventNameToAddress at line %d. Address: %ld.\n", __LINE__, addr));
1651 TCPWRITEMSG();
1652
1653 return (true);
1654 } /*fwsNetEventNameToAddress*/
1655
1656
1657 boolean fwsNetEventMyAddress (unsigned long * addr) {
1658
1659 /* Get the hosts address */
1660
1661 struct hostData hostdata;
1662
1663 #ifdef MACVERSION
1664
1665 if (!fwsNetEventLaunch (&hostdata))
1666 return (false);
1667
1668 sHostID = 0; //clear cached value
1669
1670 *addr = (unsigned long) gethostid ();
1671
1672 return (true);
1673 #else
1674 struct hostent * h;
1675 char sysstring[256];
1676 long errcode;
1677
1678
1679 if (!fwsNetEventLaunch (&hostdata))
1680 return (false);
1681
1682 if (gethostname (sysstring, 255) == SOCKET_ERROR) {
1683 neterror("get local address", WSAGetHostError ());
1684 return (false);
1685 }
1686
1687 releasethreadglobalsnopriority ();
1688
1689 h = gethostbyname (sysstring);
1690
1691 errcode = WSAGetHostError ();
1692
1693 grabthreadglobalsnopriority ();
1694
1695 if (h == NULL) {
1696 neterror("get local address name", errcode);
1697 return (false);
1698 }
1699
1700 *addr = ntohl (*((long *)h->h_addr_list[0]));
1701
1702 return (true);
1703 #endif
1704 } /*fwsNetEventMyAddress*/
1705
1706
1707
1708 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
1709
1710 static boolean fwsgetcallbackcodetree (bigstring bs, Handle *htree) {
1711
1712 Handle htext;
1713 boolean fl;
1714 unsigned long savelines;
1715 unsigned short savechars;
1716 hdltreenode hmodule = nil;
1717
1718 if (!newtexthandle (bs, &htext))
1719 return (false);
1720
1721 savelines = ctscanlines;
1722
1723 savechars = ctscanchars;
1724
1725 fl = langcompiletext (htext, false, &hmodule); /*always disposes htext*/
1726
1727 ctscanlines = savelines;
1728
1729 ctscanchars = savechars;
1730
1731 if (!fl)
1732 return (false);
1733
1734 fl = langpacktree ((**hmodule).param1, htree); /*make a copy of the sub-tree*/
1735
1736 langdisposetree (hmodule);
1737
1738 return (fl);
1739 } /*fwsgetcallbackcodetree*/
1740
1741
1742 static boolean fwsnewprocess (hdltreenode hcode, bigstring bsname, hdlprocessrecord *hprocess) {
1743
1744 register hdlprocessrecord hp;
1745 hdlerrorstack herrorstack;
1746 hdltablestack htablestack;
1747 tyerrorrecord item;
1748
1749 if (!newclearhandle (sizeof (typrocessrecord), (Handle *) hprocess))
1750 return (false);
1751
1752 hp = *hprocess; /*copy into register*/
1753
1754 if (!newclearhandle (sizeof (tyerrorstack), (Handle *) &herrorstack)) {
1755
1756 disposehandle ((Handle) hp);
1757
1758 return (false);
1759 }
1760
1761 if (!newclearhandle (sizeof (tytablestack), (Handle *) &htablestack)) {
1762
1763 disposehandle ((Handle) hp);
1764
1765 disposehandle ((Handle) herrorstack);
1766
1767 return (false);
1768 }
1769
1770 (**hp).hcode = hcode;
1771
1772 (**hp).floneshot = true;
1773
1774 (**hp).errormessagecallback = &langerrordialog;
1775
1776 (**hp).debugerrormessagecallback = (langerrormessagecallback) &truenoop;
1777
1778 (**hp).htablestack = htablestack;
1779
1780 (**hp).herrorstack = herrorstack;
1781
1782 (**hp).processstartedroutine = (langvoidcallback) &truenoop;
1783
1784 (**hp).processkilledroutine = (langvoidcallback) &truenoop;
1785
1786 item.errorcallback = nil;
1787
1788 item.errorline = 0;
1789
1790 item.errorchar = 0;
1791
1792 item.errorrefcon = 0;
1793
1794 #ifdef flnewfeatures
1795 item.profilebase = 0;
1796 #endif
1797
1798 (**herrorstack).stack [(**herrorstack).toperror++] = item;
1799
1800 copystring (bsname, (**hp).bsname);
1801
1802 return (true);
1803 } /*newprocess*/
1804
1805
1806 static boolean fwsruncallback (long listenstream, long acceptstream, long refcon) {
1807
1808 hdltreenode hcallbackaddress;
1809 hdltreenode hfunctioncall;
1810 hdltreenode hcode;
1811 hdltreenode hparam1;
1812 hdltreenode hparam2;
1813 tyvaluerecord val;
1814 hdlprocessrecord hprocess;
1815 Handle h;
1816
1817 //build code tree
1818
1819 if (!copyhandle (sockstack[listenstream].hcallbacktree, &h))
1820 return (false);
1821
1822 if (!langunpacktree (h, &hcallbackaddress))
1823 return (false);
1824
1825 setlongvalue (acceptstream, &val);
1826
1827 if (!newconstnode (val, &hparam1)) {
1828 langdisposetree (hcallbackaddress);
1829 return (false);
1830 }
1831
1832 setlongvalue (refcon, &val);
1833
1834 if (!newconstnode (val, &hparam2)) {
1835 langdisposetree (hcallbackaddress);
1836 langdisposetree (hparam1);
1837 return (false);
1838 }
1839
1840 pushlastlink (hparam2, hparam1);
1841
1842 if (!pushbinaryoperation (functionop, hcallbackaddress, hparam1, &hfunctioncall))
1843 return (false);
1844
1845 if (!pushbinaryoperation (moduleop, hfunctioncall, nil, &hcode))
1846 return (false);
1847
1848 //create new process
1849
1850 if (!fwsnewprocess (hcode, sockstack[listenstream].callback, &hprocess)) {
1851 langdisposetree (hcode);
1852 return (false);
1853 }
1854
1855 //add new process
1856
1857 return (addprocess (hprocess));
1858 }/*fwsruncallback*/
1859
1860 #endif
1861
1862
1863 static void parsecallbackstring (long stream, long p1, long p2, bigstring bs) {
1864
1865 /*
1866 5.1.5 dmb: common code for all callbacks
1867 */
1868
1869 copystring (sockstack[stream].callback, bs);
1870 pushchar ('(', bs);
1871 pushlong (p1, bs);
1872 pushchar (',', bs);
1873 pushlong (p2, bs);
1874 pushchar (')', bs);
1875
1876 nullterminate(bs); //for debug display
1877 } /*parsecallbackstring*/
1878
1879
1880 static boolean fwsrunstring (bigstring bs) {
1881
1882 /*
1883 5.1.5 dmb: make sure we have thread globals for the compiler and processlist,
1884 then run the string as a new process.
1885
1886 note: we might special case each call and build a code tree by hand, so we
1887 don't need globals. I'm not sure if adding a new process really needs globals.
1888 */
1889
1890 boolean fl;
1891
1892 grabthreadglobalsnopriority ();
1893
1894 fl = processrunstringnoerrorclear (bs);
1895
1896 releasethreadglobalsnopriority ();
1897
1898 return (fl);
1899 } /*fwsrunstring*/
1900
1901
1902 static boolean restartAccepter (SOCKET s, short listenstream) {
1903 boolean fl = true;
1904
1905 #ifdef WIN95VERSION
1906 long err;
1907 #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
1908 bigstring bs;
1909 #endif
1910 unsigned long timewait;
1911
1912 TCPTRACKERIN ("restartAccepter", __LINE__, listenstream);
1913
1914 if (!sockstack[listenstream].flNotification
1915 && sockstack[listenstream].currentListenDepth < sockstack[listenstream].maxdepth) {
1916
1917 /*Turn it on again!*/
1918
1919 if (WSAAsyncSelect (s, shellframewindow, wm_processAccept, FD_ACCEPT) != SOCKET_ERROR)
1920 {
1921 sockstack[listenstream].flNotification = true;
1922 fl = true;
1923 goto exit;
1924 }
1925
1926 /* Our interest in this has failed */
1927
1928 err = WSAGetLastError();
1929
1930 timewait = gettickcount() + (60L * 15L); /*max of 15 seconds*/
1931
1932 while (timewait > gettickcount()) {
1933 if (err == WSAEINPROGRESS) {
1934 /* let's see if we can restart this ourselves */
1935 TCPprintf (wsprintf(TCPmsg, "In restartAccepter at line %d. Attempting restart on listenstream: %d.\n", __LINE__, listenstream));
1936 TCPWRITEMSG();
1937
1938 //threadyield (true);
1939
1940 Sleep (100L); //100 milliseconds -- make sure we don't control the thread globals!
1941
1942 if (WSAAsyncSelect (s, shellframewindow, wm_processAccept, FD_ACCEPT) != SOCKET_ERROR)
1943 {
1944 sockstack[listenstream].flNotification = true;
1945 TCPprintf (wsprintf(TCPmsg, "In restartAccepter at line %d. Got listen restarted on listenstream: %d.\n", __LINE__, listenstream));
1946 TCPWRITEMSG();
1947 fl = true;
1948 goto exit;
1949 }
1950
1951 err = WSAGetLastError();
1952 }
1953 else
1954 break; /*any other error we get out*/
1955 }
1956
1957 sockstack[listenstream].typeID = SOCKTYPE_LISTENSTOPPED;
1958 #ifndef ACCEPT_IN_SEPARATE_THREAD
1959 sockstack[listenstream].hevent = nil;
1960 #endif
1961
1962 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
1963 TCPERRORprintf (wsprintf(TCPmsg, "In restartAccepter at line %d. Error setting future accepts %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, listenstream * -1L));
1964 TCPWRITEMSG();
1965
1966 fl = fwsruncallback (listenstream, err * -1L, listenstream * -1L);
1967 #else
1968 parsecallbackstring (listenstream, err * -1L, listenstream * -1L, bs);
1969
1970 TCPERRORprintf (wsprintf(TCPmsg, "In restartAccepter at line %d. Error setting future accepts %s.\n", __LINE__, stringbaseaddress(bs)));
1971 TCPERRORWRITEMSG();
1972
1973 fl = fwsrunstring (bs);
1974 #endif
1975 }
1976
1977 exit:
1978
1979 TCPTRACKEROUT ("restartAccepter", __LINE__, listenstream);
1980
1981 #endif
1982 return (fl);
1983 } /*restartAccepter*/
1984
1985
1986 static boolean checkAccepter (unsigned long stream) {
1987
1988 if (sockstack[stream].listenReference != 0) {
1989
1990 long listenstream = sockstack[stream].listenReference;
1991
1992 --sockstack[listenstream].currentListenDepth;
1993
1994 #ifdef WIN95VERSION
1995 #ifndef ACCEPT_IN_SEPARATE_THREAD
1996 {
1997 boolean fl;
1998
1999 releasethreadglobalsnopriority ();
2000
2001 fl = restartAccepter (sockstack[listenstream].sockID, listenstream);
2002
2003 grabthreadglobalsnopriority ();
2004
2005 return (fl);
2006 }
2007 #endif
2008 #endif
2009 }
2010
2011 return (true);
2012 } /*checkAccepter*/
2013
2014
2015 #ifdef ACCEPT_IN_SEPARATE_THREAD
2016
2017 static boolean fwsacceptsocket (long listenstream) {
2018
2019 /*
2020 Process an accept pending message on a socket
2021 */
2022
2023 int sasize;
2024 struct sockaddr_in sa;
2025 SOCKET acceptsock;
2026 long err;
2027 boolean fl = false;
2028 long newstream;
2029 long dummy = 0; /*need a pointer to nil for ioctlsocket call*/
2030
2031 TCPTRACKERIN ("fwsacceptsocket", __LINE__, listenstream);
2032
2033 /*Accept connection*/
2034
2035 sasize = sizeof(sa);
2036
2037 acceptsock = accept (sockstack[listenstream].sockID, (struct sockaddr *)&sa, &sasize);
2038
2039 if (acceptsock != INVALID_SOCKET) {
2040
2041 #ifdef PIKE
2042 if (incrementconnectioncounter ()) {
2043 #endif
2044
2045 /*Increment listen depth*/
2046
2047 ++sockstack[listenstream].currentListenDepth;
2048
2049 /*get socket record for accepted socket*/
2050
2051 if (!addsockrecord (&newstream)) {
2052
2053 struct linger l;
2054
2055 l.l_onoff = 1;
2056 l.l_linger = 0;
2057
2058 TCPERRORprintf (wsprintf(TCPmsg, "In fwsacceptsocket at line %d. Error addding new socket record %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), WSAEMFILE * -1L, sockstack[listenstream].refcon));
2059 TCPERRORWRITEMSG();
2060
2061 setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l)); /*abort*/
2062
2063 fl = closesocket (acceptsock);
2064
2065 #ifdef PIKE
2066 decrementconnectioncounter ();
2067 #endif
2068
2069 goto exit;
2070 }
2071
2072 /*Add Socket to list*/
2073 sockstack[newstream].sockID = acceptsock;
2074 sockstack[newstream].typeID = SOCKTYPE_OPEN;
2075 sockstack[newstream].listenReference = listenstream;
2076 sockstack[newstream].refcon = 0;
2077
2078 /*Pass "stream" and "refcon" to callback*/
2079
2080 TCPprintf (wsprintf(TCPmsg, "In fwsacceptsocket at line %d. Accepted new socket %ld: %s (%ld, %ld).\n", __LINE__, acceptsock, stringbaseaddress (sockstack[listenstream].callback), newstream, sockstack[listenstream].refcon));
2081 TCPWRITEMSG();
2082
2083 fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
2084
2085 #ifdef PIKE
2086 }
2087 else {
2088
2089 struct linger l;
2090
2091 l.l_onoff = 1;
2092 l.l_linger = 0;
2093
2094 TCPERRORprintf (wsprintf(TCPmsg, "In fwsacceptsocket at line %d. Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
2095 TCPERRORWRITEMSG();
2096
2097 setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
2098
2099 fl = closesocket (acceptsock);
2100 }
2101 #endif
2102
2103 }
2104 else
2105 {
2106 /*if an error - pass this on to callback*/
2107 err = WSAGetLastError();
2108
2109 TCPERRORprintf (wsprintf(TCPmsg, "In fwsacceptsocket at line %d. Error processing accept message %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
2110 TCPWRITEMSG();
2111
2112 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
2113
2114 }
2115
2116 exit:
2117
2118 TCPprintf (wsprintf(TCPmsg, "Exiting fwsacceptsocket at line %d. Return value is %s.\n", __LINE__, fl?"True":"False"));
2119 TCPWRITEMSG();
2120
2121 return (fl);
2122 } /*fwsacceptsocket*/
2123
2124
2125 static void *fwsacceptingthreadmain (long *param) {
2126
2127 /*
2128 6.2a12 AR: we sit in a loop waiting for new connections.
2129
2130 7.1b29 PBS: fix CPU usage 100% bug on Win98/ME by yielding in this loop.
2131
2132 9.1b3 AR: Increased select timeout from 10 microseconds to 1 second.
2133 When select times out, it returns zero and all we do is check whether
2134 we need to break out of the while loop, so a higher timeout value is
2135 not a problem. This also makes the 7.1b29 bug fix redundant.
2136
2137 Further, we only need to check the current listen depth if we just
2138 accepted another connection.
2139
2140 Also, it's good practice to initialize the timeval struct through
2141 every iteration of the loop.
2142 */
2143
2144 long listenstream = (long) param;
2145 register sockRecord* sockrecptr = &sockstack[listenstream];
2146 register SOCKET sock = sockrecptr->sockID;
2147 Handle hcallback = sockrecptr->hcallbacktree; /*keep a copy in our stack so we can safely dispose it*/
2148 long maxdepth = sockrecptr->maxdepth;
2149 fd_set readset;
2150 struct timeval tv;
2151 int res;
2152
2153 TCPTRACKERIN ("fwsacceptingthreadmain", __LINE__, listenstream);
2154
2155 attachtomainthread (sockrecptr->idthread); /*6.2b7 AR*/
2156
2157 while (sockrecptr->typeID == SOCKTYPE_LISTENING) {
2158
2159 FD_ZERO (&readset);
2160
2161 FD_SET (sock, &readset);
2162
2163 tv.tv_sec = 1L; /* 1 second */
2164 tv.tv_usec = 0L; /* 0 micro-seconds */
2165
2166 res = select (sock+1, &readset, NULL, NULL, &tv);
2167
2168 TCPprintf (wsprintf(TCPmsg, "In fwsacceptingthreadmain at line %d. Select returned %ld.\n", __LINE__, (long) res));
2169 TCPWRITEMSG();
2170
2171 if (sockrecptr->typeID != SOCKTYPE_LISTENING || flshellclosingall) {
2172 break;
2173 }
2174
2175 if (res == 1) {
2176
2177 (void) fwsacceptsocket (listenstream);
2178
2179 while (sockrecptr->currentListenDepth >= maxdepth) {
2180 usleep (10L); /* sleep for 10 milli-seconds */
2181 }
2182 }
2183
2184 /*
2185 #ifdef PIKE
2186 usleep (10L); /+7.1b29 PBS: fix CPU usage 100% bug on Win98/ME by yielding in this loop.+/
2187 #endif
2188 */
2189 }/*while*/
2190
2191 disposehandle (hcallback);
2192
2193 if (sockrecptr->typeID == SOCKTYPE_LISTENSTOPPED) {
2194 /*we have been asked by fwsNetEventCloseListen to take responsibility of cleaning up*/
2195 sockrecptr->sockID = INVALID_SOCKET;
2196 sockrecptr->typeID = SOCKTYPE_CLOSED;
2197 }
2198
2199 TCPTRACKEROUT ("fwsacceptingthreadmain", __LINE__, listenstream);
2200
2201 return (nil);
2202 }/*fwsacceptingthreadmain*/
2203
2204
2205 static boolean fwslaunchacceptingthread (long stream) {
2206
2207 #ifdef WIN95VERSION
2208
2209 HANDLE hthread;
2210
2211 /*create listening thread*/
2212
2213 hthread = CreateThread (nil, nil, (LPTHREAD_START_ROUTINE) &fwsacceptingthreadmain, (LPVOID) stream, CREATE_SUSPENDED, &sockstack[stream].idthread);
2214
2215 if (hthread == NULL) {
2216
2217 neterror("create listen thread", GetLastError ());
2218
2219 return (false);
2220 }
2221
2222 ResumeThread (hthread); /*let the new thread fly*/
2223
2224 #else
2225
2226 pthread_t idthread;
2227 pthread_attr_t attr;
2228
2229 pthread_attr_init (&attr);
2230
2231 pthread_create ((pthread_t *) &sockstack[stream].idthread, &attr, fwsacceptingthreadmain, (void *)stream);
2232
2233 pthread_attr_destroy (&attr);
2234
2235 #endif
2236
2237 return (true);
2238 }/*fwslaunchacceptingthread*/
2239
2240 #endif
2241
2242 void fwsNetEventShutdownDependentListeners (long hdatabase) {
2243
2244 #ifdef ACCEPT_IN_SEPARATE_THREAD
2245 long i;
2246
2247 for (i = 1; i < FRONTIER_MAX_STREAM; i++)
2248 if (sockstack[i].typeID == SOCKTYPE_LISTENING)
2249 if (sockstack[i].hdatabase == (hdldatabaserecord) hdatabase)
2250 sockstack[i].typeID = SOCKTYPE_LISTENSTOPPED; /*make sure the separate thread terminates before the database goes away*/
2251 #endif
2252 }/*fwsNetEventShutdownDependentListeners*/
2253
2254
2255 /* Abort a stream and delete associated data */
2256 boolean fwsNetEventAbortStream (unsigned long stream) {
2257
2258 /*
2259 5.1.5 dmb: release thread globals while we close; don't reset
2260 socket typeID until close is complete
2261
2262 6.2a9 AR: Don't reset socket typeID and sockID until close is complete
2263 so addsockrecord doesn't get to hand it out before we're done.
2264 This bug probably sneaked back in during the 6.1 development cycle.
2265 */
2266
2267 SOCKET sock;
2268 int res, errcode;
2269 struct linger l;
2270 // struct hostData hostdata;
2271
2272 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
2273 return (false);
2274
2275 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
2276 intneterror (INTNETERROR_INVALIDSTREAM);
2277 return (false);
2278 }
2279
2280 TCPTRACKERIN ("fwsNetEventAbortStream", __LINE__, stream);
2281
2282 sock = sockstack[stream].sockID;
2283
2284 l.l_onoff = 1;
2285 l.l_linger = 0;
2286
2287 releasethreadglobalsnopriority();
2288
2289 setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
2290
2291 res = closesocket(sock);
2292
2293 errcode = WSAGetLastError ();
2294
2295 grabthreadglobalsnopriority();
2296
2297 #ifdef PIKE
2298 decrementconnectioncounter();
2299 #endif
2300
2301 checkAccepter (stream);
2302
2303 sockstack[stream].sockID = INVALID_SOCKET;
2304 sockstack[stream].typeID = SOCKTYPE_CLOSED;
2305
2306 if (res == SOCKET_ERROR) {
2307 neterror("abort stream", errcode);
2308 return (false);
2309 }
2310
2311 TCPTRACKEROUT ("fwsNetEventAbortStream", __LINE__, stream);
2312
2313 return (true);
2314 } /*fwsNetEventAbortStream*/
2315
2316
2317 boolean fwsNetEventCloseStream (unsigned long stream) {
2318
2319 /*
2320 Close a stream and delete associated data
2321
2322 do we want or should the user control the SO_LINGER flag for a
2323 graceful verses hard socket closure. for now it is the user.
2324
2325 6.2a9 AR: Don't reset socket typeID and sockID until close is complete
2326 so addsockrecord doesn't get to hand it out before we're done.
2327 This bug probably sneaked back in during the 6.1 development cycle.
2328 */
2329
2330 SOCKET sock;
2331 long err;
2332
2333 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
2334 return (false);
2335
2336 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
2337 intneterror (INTNETERROR_INVALIDSTREAM);
2338 return (false);
2339 }
2340
2341 TCPTRACKERIN ("fwsNetEventCloseStream", __LINE__, stream);
2342
2343 sock = sockstack[stream].sockID;
2344
2345 #ifdef PIKE
2346 decrementconnectioncounter();
2347 #endif
2348
2349 releasethreadglobalsnopriority();
2350
2351 if (shutdown (sock, SD_SEND) == SOCKET_ERROR) {
2352
2353 err = WSAGetLastError ();
2354
2355 goto error;
2356 }
2357
2358 if (closesocket(sock) == SOCKET_ERROR) {
2359
2360 err = WSAGetLastError ();
2361
2362 goto error;
2363 }
2364
2365 grabthreadglobalsnopriority();
2366
2367 checkAccepter (stream);
2368
2369 sockstack[stream].sockID = INVALID_SOCKET;
2370 sockstack[stream].typeID = SOCKTYPE_CLOSED;
2371
2372 TCPprintf (wsprintf(TCPmsg, "Leaving closeStream at line %d. Thread duration: %ld ticks.\n", __LINE__, gettickcount()-(**getcurrentthreadglobals()).timestarted));
2373 TCPWRITEMSG();
2374
2375 return (true);
2376
2377 error:
2378
2379 grabthreadglobalsnopriority ();
2380
2381 sockstack[stream].sockID = INVALID_SOCKET;
2382 sockstack[stream].typeID = SOCKTYPE_CLOSED;
2383
2384 neterror ("close stream", err);
2385
2386 return (false);
2387 } /*fwsNetEventCloseStream*/
2388
2389
2390 boolean fwsNetEventCloseListen (unsigned long stream) {
2391
2392 /*
2393 Close a listen and delete associated data
2394
2395 do we want or should the user control the SO_LINGER flag for a
2396 graceful verses hard socket closure. for now it is the user.
2397
2398 5.1.5b7 dmb: set linger timeout to zero for Mac (now implemented in GUSI)
2399
2400 6.2a9 AR: Don't reset socket typeID and sockID until close is complete
2401 so addsockrecord doesn't get to hand it out before we're done.
2402 */
2403
2404 SOCKET sock;
2405 int res, errcode;
2406 #ifdef MACVERSION
2407 int i,j;
2408 struct linger l;
2409 #endif
2410 // struct hostData hostdata;
2411
2412 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
2413 return (false);
2414
2415 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
2416 intneterror (INTNETERROR_INVALIDSTREAM);
2417 return (false);
2418 }
2419
2420 sock = sockstack[stream].sockID;
2421
2422 /* No more messages */
2423 #ifndef ACCEPT_IN_SEPARATE_THREAD
2424 sockstack[stream].maxdepth = -100; /*never restart select call*/
2425 #endif
2426
2427 TCPTRACKERIN ("fwsNetEventCloseListen", __LINE__, stream);
2428
2429 releasethreadglobalsnopriority();
2430
2431 #ifdef WIN95VERSION
2432 #ifndef ACCEPT_IN_SEPARATE_THREAD
2433 WSAAsyncSelect (sock, shellframewindow, 0, 0);
2434 #endif
2435 #endif
2436
2437 #ifdef MACVERSION
2438 for (i = 0; i < sockListenCount; i++) {
2439 if (sockListenList [i] == stream) {
2440 if (i == (sockListenCount - 1)) {
2441 //easy case - end of list to remove
2442 --sockListenCount;
2443 }
2444 else {
2445 //Move remaining down in the list
2446 for (j = i; j < sockListenCount - 1; j++)
2447 sockListenList[j] = sockListenList[j+1];
2448
2449 --sockListenCount;
2450 }
2451
2452 break; //It can only be in the list once.
2453 }
2454 }
2455
2456 l.l_onoff = 1;
2457 l.l_linger = 0;
2458
2459 setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
2460
2461 #endif
2462
2463 res = closesocket(sock);
2464
2465 errcode = WSAGetLastError ();
2466
2467 grabthreadglobalsnopriority();
2468
2469 #ifdef ACCEPT_IN_SEPARATE_THREAD
2470 sockstack[stream].typeID = SOCKTYPE_LISTENSTOPPED;
2471 #else
2472 sockstack[stream].sockID = INVALID_SOCKET;
2473 sockstack[stream].typeID = SOCKTYPE_CLOSED;
2474 #endif
2475
2476 if (res == SOCKET_ERROR) {
2477 neterror("close listen", errcode);
2478 return (false);
2479 }
2480
2481 TCPTRACKEROUT ("fwsNetEventCloseListen", __LINE__, stream);
2482
2483 return (true);
2484 } /*fwsNetEventCloseListen*/
2485
2486
2487 static short is_ipaddress (char *name) {
2488
2489 short ctfields = 1;
2490 short fieldlen = 0;
2491 char *p = name;
2492
2493 for (p = name; *p; ++p) {
2494
2495 if (*p == '.') {
2496
2497 if (fieldlen == 0) //leading dot, or consequtive dots
2498 return (false);
2499
2500 ++ctfields;
2501
2502 fieldlen = 0;
2503 }
2504 else {
2505 if (!isdigit (*p))
2506 return (false);
2507
2508 if (++fieldlen > 3) // four consecutive digits
2509 return (false);
2510 }
2511 }
2512
2513 return (ctfields == 4);
2514 } /*is_ipaddress*/
2515
2516
2517 static boolean fwsOpenStream (struct sockaddr_in *sa, unsigned long * stream) {
2518
2519 /*
2520 5.0.2b4 dmb: the common code between openAddrStream and openNameStream, so we
2521 don't have to convert one to the other to open a stream of either type
2522
2523 6.1d13 AR: Release thread globals.
2524
2525 6.2b1 AR: For Pike, decrement connection counter if connection attempt fails.
2526 */
2527
2528 SOCKET sock;
2529 int errcode;
2530 long streamref;
2531
2532 if (!addsockrecord (&streamref)) {
2533 neterror ("open stream", WSAEMFILE); /*Too many open sockets*/
2534 return (false);
2535 }
2536
2537 #ifdef PIKE
2538 if (!incrementconnectioncounter ()) {
2539
2540 plainneterror ("\x54" "Can't open stream because no more than five TCP connections may be open at any time.");
2541
2542 return (false);
2543 }
2544 #endif
2545
2546 releasethreadglobalsnopriority ();
2547
2548 sock = socket(PF_INET, SOCK_STREAM, 0);
2549
2550 if (sock == INVALID_SOCKET) {
2551 errcode = WSAGetLastError ();
2552 goto exit;
2553 }
2554
2555 if (connect (sock, (struct sockaddr *) sa, sizeof(*sa)) == SOCKET_ERROR) {
2556 errcode = WSAGetLastError ();
2557 closesocket (sock);
2558 goto exit;
2559 }
2560
2561 sockstack[streamref].typeID = SOCKTYPE_OPEN;
2562
2563 sockstack[streamref].sockID = sock;
2564
2565 *stream = streamref;
2566
2567 grabthreadglobalsnopriority ();
2568
2569 return (true);
2570
2571 exit:
2572
2573 sockstack[streamref].typeID = SOCKTYPE_INVALID;
2574
2575 grabthreadglobalsnopriority ();
2576
2577 neterror ("open stream", errcode);
2578
2579 #ifdef PIKE
2580 decrementconnectioncounter ();
2581 #endif
2582
2583 return (false);
2584 } /*fwsOpenStream*/
2585
2586
2587 boolean fwsNetEventOpenAddrStream (unsigned long addr, unsigned long port, unsigned long * stream) {
2588
2589 /*
2590 Open a stream and create associated data
2591
2592 5.1.6 dmb: don't use a hostent; construct the sockaddr from the address, avoiding DNS
2593 */
2594
2595 unsigned long netaddr;
2596 struct hostData hostdata;
2597 struct sockaddr_in sa;
2598
2599 if (!fwsNetEventLaunch (&hostdata))
2600 return (false);
2601
2602 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenAddrStream at line %d. Address: %ld.\n", __LINE__, addr));
2603 TCPWRITEMSG();
2604
2605 netaddr = htonl(addr);
2606
2607 #ifdef MACVERSION
2608 sHostID = 0; //clear cached value
2609 #endif
2610
2611 memset (&sa, 0, sizeof(sa));
2612
2613 memcpy (&(sa.sin_addr), &netaddr, sizeof (netaddr));
2614
2615 sa.sin_family = AF_INET;
2616
2617 sa.sin_port = htons ((unsigned short) port);
2618
2619 return (fwsOpenStream (&sa, stream));
2620 } /*fwsNetEventOpenAddrStream*/
2621
2622
2623 boolean fwsNetEventOpenNameStream (bigstring name, unsigned long port, unsigned long * stream) {
2624
2625 /*
2626 Open a stream and create associated data
2627
2628 5.1.6 dmb: if passed an IP address, encode address and use that instead (avoid dns)
2629 */
2630
2631 char sysstring[256];
2632 struct hostent * hp;
2633 struct hostData hostdata;
2634 unsigned long addr;
2635 struct sockaddr_in sa;
2636 long errcode;
2637
2638 if (!fwsNetEventLaunch (&hostdata))
2639 return (false);
2640
2641 copyptocstring (name, sysstring);
2642
2643 #ifdef MACVERSION
2644 sHostID = 0; //clear cached value
2645 #endif
2646
2647 TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenNameStream at line %d. Domain name: %s.\n", __LINE__, sysstring));
2648 TCPWRITEMSG();
2649
2650 if (is_ipaddress (sysstring)) {
2651
2652 if (!fwsNetEventAddressEncode (name, &addr))
2653 return (false);
2654
2655 return (fwsNetEventOpenAddrStream (addr, port, stream));
2656 }
2657
2658 releasethreadglobalsnopriority ();
2659
2660 hp = gethostbyname (sysstring);
2661
2662 errcode = WSAGetHostError ();
2663
2664 grabthreadglobalsnopriority ();
2665
2666 if (hp == NULL) {
2667 neterror("open named stream", errcode);
2668 return (false);
2669 }
2670
2671 memset (&sa, 0, sizeof(sa));
2672
2673 memcpy (&(sa.sin_addr), hp->h_addr_list[0], hp->h_length);
2674
2675 sa.sin_family = hp->h_addrtype;
2676
2677 sa.sin_port = htons ((unsigned short) port);
2678
2679 return (fwsOpenStream (&sa, stream));
2680 } /*fwsNetEventOpenNameStream*/
2681
2682
2683 boolean fwsNetEventReadStream (unsigned long stream, unsigned long * bytesToRead, char * buffer) {
2684
2685 /* Read from a stream */
2686
2687 SOCKET sock;
2688 int res, errcode;
2689 // struct hostData hostdata;
2690
2691 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
2692 return (false);
2693
2694 TCPTRACKERIN ("fwsNetEventReadStream", __LINE__, stream);
2695
2696 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
2697 intneterror (INTNETERROR_INVALIDSTREAM);
2698 return (false);
2699 }
2700
2701 sock = sockstack[stream].sockID;
2702
2703 releasethreadglobalsnopriority();
2704
2705 res = recv (sock, buffer, *bytesToRead, 0);
2706
2707 errcode = WSAGetLastError ();
2708
2709 grabthreadglobalsnopriority();
2710
2711 if (res == SOCKET_ERROR) {
2712 neterror("read stream", errcode);
2713 return (false);
2714 }
2715
2716 TCPprintf (if (*bytesToRead > 0) {bigstring bs; texttostring(buffer, *bytesToRead, bs); firstword (bs, '\r', bs); convertpstring (bs); wsprintf (TCPmsg, "In ReadStream, read: %s\n", bs); TCPWRITEMSG ();})
2717 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStream at line %d. Bytes requested = %ld, read = %ld.\n", __LINE__, *bytesToRead, (unsigned long) res));
2718 TCPWRITEMSG ();
2719
2720 // if (res == (int) bytesToRead)
2721 // return (true);
2722 //
2723 // return (false);
2724
2725 *bytesToRead = res;
2726
2727 return (true);
2728 } /*fwsNetEventReadStream*/
2729
2730
2731 boolean fwsNetEventWriteStream (unsigned long stream, unsigned long bytesToWrite, char * buffer) {
2732
2733 /*
2734 Write to a Stream
2735
2736 5.0.2b3 dmb: if we write fewer bytes than requested, we need to retry, generate error
2737 */
2738
2739 SOCKET sock;
2740 int res, errcode;
2741 // int len = sizeof (res);
2742
2743 // struct hostData hostdata;
2744
2745 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
2746 return (false);
2747
2748 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
2749 intneterror (INTNETERROR_INVALIDSTREAM);
2750 return (false);
2751 }
2752
2753 TCPTRACKERIN ("fwsNetEventWriteStream", __LINE__, stream);
2754
2755 sock = sockstack[stream].sockID;
2756
2757 //if (getsockopt (sock, SOL_SOCKET, SO_SNDBUF, &res, &len) != 0)
2758 // ;
2759
2760 releasethreadglobalsnopriority();
2761
2762 res = send (sock, buffer, bytesToWrite, 0);
2763
2764 errcode = WSAGetLastError ();
2765
2766 grabthreadglobalsnopriority();
2767
2768 if (res == SOCKET_ERROR) {
2769 neterror("write stream", errcode);
2770 return (false);
2771 }
2772
2773 if (res < (int) bytesToWrite) {
2774 neterror("write stream", WSAEWOULDBLOCK);
2775 return (false);
2776 }
2777
2778 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteStream at line %d. Bytes requested = %ld, written = %ld.\n", __LINE__, bytesToWrite, (unsigned long) res));
2779 TCPWRITEMSG ();
2780
2781 return (true);
2782 } /*fwsNetEventWriteStream*/
2783
2784
2785 #ifdef MACVERSION
2786 /*
2787 static unsigned long selects = 0;
2788 static unsigned long accepts = 0;
2789 static unsigned long selecting = 0;
2790 static unsigned long accepting = 0;
2791 static unsigned long avgselect = 0;
2792 static unsigned long avgaccept = 0;
2793 */
2794 static unsigned long maxlistendepth = 0;
2795
2796 #ifdef FRONTIER_GUSI_2
2797
2798 boolean fwsNetEventCheckAndAcceptSocket () { return (true); }
2799
2800 #else
2801
2802 boolean fwsNetEventCheckAndAcceptSocket () {
2803 int i;
2804 int res;
2805 SOCKET sock;
2806 fd_set readset;
2807 struct timeval tv;
2808 int sasize;
2809 struct sockaddr_in sa;
2810 SOCKET acceptsock;
2811 long listenstream, newstream;
2812 long err;
2813 boolean fl = true;
2814 #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
2815 bigstring bs;
2816 #endif
2817
2818 if (!frontierWinSockLoaded)
2819 return (false);
2820
2821 #ifndef FRONTIER_GUSI_2
2822 wakecompletedthreads ();
2823 #endif
2824
2825 // unsigned long ticks;
2826
2827 //We could set all the sockets at one time, but I think that is harder to manage.
2828 //Let's just loop through each listen socket and see if it is ready.
2829
2830 for (i = 0; i < sockListenCount; i++) {
2831 listenstream = sockListenList[i];
2832
2833 if (sockstack[listenstream].currentListenDepth <= (sockstack[listenstream].maxdepth)) {
2834 sock = sockstack[listenstream].sockID;
2835
2836 tv.tv_sec = 0;
2837 tv.tv_usec = 0;
2838
2839 FD_ZERO (&readset);
2840
2841 FD_SET(sock, &readset);
2842
2843 /* now check for data */
2844
2845 // ticks = gettickcount ();
2846
2847 res = select (sock+1, &readset, NULL, NULL, &tv);
2848
2849 // selecting += gettickcount () - ticks;
2850 // avgselect = selecting / ++selects;
2851
2852 if (res == 1) { /* we have a live one...*/
2853
2854 /*Grab socket record for child socket*/
2855
2856 if (!addsockrecord (&newstream)) {
2857 /* if an error - pass this on to callback */
2858 long err = WSAEMFILE;
2859
2860 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
2861 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Error %ld addding new socket record %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
2862 TCPWRITEMSG();
2863
2864 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
2865 #else
2866 parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);;
2867
2868 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Error addding new socket record %s.\n", __LINE__, stringbaseaddress(bs)));
2869 TCPERRORWRITEMSG();
2870
2871 fl = fwsrunstring (bs);
2872 #endif
2873
2874 continue;
2875 }
2876
2877 /*Accept connection*/
2878
2879 sasize = sizeof(sa);
2880
2881 // ticks = gettickcount ();
2882
2883 acceptsock = accept (sock, (struct sockaddr *)&sa, &sasize);
2884
2885 // accepting += gettickcount () - ticks;
2886 // avgaccept = accepting / ++accepts;
2887
2888 if (acceptsock != INVALID_SOCKET) {
2889 #ifdef PIKE
2890 if (incrementconnectioncounter ()) {
2891 #endif
2892 /*sucessful connection - assign this */
2893 ++sockstack[listenstream].currentListenDepth;
2894
2895 maxlistendepth = max (maxlistendepth, sockstack[listenstream].currentListenDepth);
2896
2897 /*Add Socket to list*/
2898 sockstack[newstream].refcon = 0;
2899 sockstack[newstream].sockID = acceptsock;
2900 sockstack[newstream].typeID = SOCKTYPE_OPEN;
2901 sockstack[newstream].listenReference = listenstream;
2902
2903 /*Pass "stream" and "refcon" to callback*/
2904
2905 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
2906 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Accepted new socket %ld, callback %s (%ld, %ld).\n", __LINE__, acceptsock, stringbaseaddress (sockstack[listenstream].callback), newstream, sockstack[listenstream].refcon));
2907 TCPWRITEMSG();
2908
2909 fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
2910 #else
2911 parsecallbackstring (listenstream, newstream, sockstack[listenstream].refcon, bs);
2912
2913 TCPprintf (sprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Accepted new socket %ld, stream %ld callback message %s.\n", __LINE__, (unsigned long) acceptsock, (unsigned long) newstream, stringbaseaddress(bs)));
2914 TCPWRITEMSG();
2915
2916 fl = fwsrunstring (bs);
2917 #endif
2918
2919 --i; // back up so we'll check this socket again
2920 #ifdef PIKE
2921 }
2922 else {
2923
2924 struct linger l;
2925
2926 l.l_onoff = 1;
2927 l.l_linger = 0;
2928
2929 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
2930 TCPERRORWRITEMSG();
2931
2932 setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
2933
2934 fl = closesocket (acceptsock);
2935
2936 sockstack[newstream].typeID = SOCKTYPE_INVALID;
2937 }
2938 #endif
2939 }
2940 else
2941 {
2942 /* if an error - pass this on to callback */
2943 err = WSAGetLastError();
2944
2945 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
2946 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Error processing accept message %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
2947 TCPWRITEMSG();
2948
2949 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
2950 #else
2951 parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
2952
2953 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d. Error processing accept message %s.\n", __LINE__, stringbaseaddress(bs)));
2954 TCPERRORWRITEMSG();
2955
2956 fl = fwsrunstring (bs);
2957 #endif
2958
2959 if (err == ENOTCONN) {
2960
2961 // 6.0b2 dmb: this code isn't right. the listens keep succeeding,
2962 // chewing up resources until they're gone; accepts still fail
2963 /*
2964 if (listen (sock, 5) == SOCKET_ERROR) {
2965
2966 neterror("setup listen stream", WSAGetLastError ());
2967
2968 fwsNetEventCloseListen (listenstream);
2969 //closesocket (sock);
2970 }
2971 */
2972 }
2973 sockstack[newstream].typeID = SOCKTYPE_INVALID;
2974 }
2975 }
2976 else if (res == SOCKET_ERROR) {
2977 //The select on that socket had an error - What to do??
2978 }
2979 }
2980 }
2981
2982 return (fl);
2983 } /*fwsNetEventCheckAndAcceptSocket*/
2984 #endif
2985 #endif
2986
2987 #ifdef WIN95VERSION
2988 boolean fwsNetEventAcceptSocket (WPARAM wParam, LPARAM lParam) {
2989
2990 /*
2991 Process an accept pending message on a socket
2992
2993 5.1.2 dmb: release thread globals on all errors
2994 */
2995
2996 #ifdef ACCEPT_IN_SEPARATE_THREAD
2997
2998 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. THIS FUNCTION IS NOT SUPPOSED TO BE CALLED!\n", __LINE__));
2999 TCPWRITEMSG();
3000
3001 return (false);
3002
3003 #else
3004
3005 int sasize;
3006 struct sockaddr_in sa;
3007 SOCKET s, acceptsock;
3008 long err;
3009 boolean fl = false;
3010 long listenstream, newstream;
3011 long dummy = 0; /*need a pointer to nil for ioctlsocket call*/
3012 #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
3013 bigstring bs;
3014 #endif
3015
3016 s = (SOCKET) wParam;
3017
3018 /*get listen stream*/
3019 if (!getsockrecord (s, &listenstream))
3020 goto exit;
3021
3022 TCPTRACKERIN ("fwsNetEventAcceptSocket", __LINE__, listenstream);
3023
3024 if (listenstream < 0)
3025 goto exit;
3026
3027 if (sockstack[listenstream].typeID != SOCKTYPE_LISTENING) {
3028 /*something has happened to close this listen*/
3029 goto exit;
3030 }
3031
3032 /*Check for error*/
3033
3034 err = WSAGETSELECTERROR(lParam);
3035
3036 if (err != 0) {
3037 /* if an error - pass this on to callback */
3038 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3039 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error in accept message %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
3040 TCPWRITEMSG();
3041
3042 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
3043 #else
3044 parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
3045
3046 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error in accept message %s.\n", __LINE__, stringbaseaddress(bs)));
3047 TCPERRORWRITEMSG();
3048
3049 fl = fwsrunstring (bs);
3050 #endif
3051
3052 goto exit;
3053 }
3054
3055 /*get socket record for accepted socket*/
3056
3057 if (!addsockrecord (&newstream)) {
3058 /* if an error - pass this on to callback */
3059 long err = WSAEMFILE;
3060
3061 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3062 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error addding new socket record %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
3063 TCPWRITEMSG();
3064
3065 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
3066 #else
3067 parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
3068
3069 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error addding new socket record %s.\n", __LINE__, stringbaseaddress(bs)));
3070 TCPERRORWRITEMSG();
3071
3072 fl = fwsrunstring (bs);
3073 #endif
3074
3075 goto exit;
3076 }
3077
3078 /*We do not want any more connection messages - at least if we've reached maximum listen depth*/
3079
3080 if (!(sockstack[listenstream].currentListenDepth + 1 < sockstack[listenstream].maxdepth)) {
3081
3082 sockstack[listenstream].flNotification = false;
3083
3084 WSAAsyncSelect(s, shellframewindow, 0, 0);
3085 }
3086
3087 /*Accept connection*/
3088
3089 sasize = sizeof(sa);
3090
3091 acceptsock = accept (s, (struct sockaddr *)&sa, &sasize);
3092
3093 if (acceptsock != INVALID_SOCKET) {
3094
3095 #ifdef PIKE
3096 if (incrementconnectioncounter ()) {
3097 #endif
3098 /*Switch child socket to blocking mode*/
3099 if (WSAAsyncSelect(acceptsock, shellframewindow, 0, 0) == SOCKET_ERROR) {
3100 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. WSAAsyncSelect call failed: %ld.\n", __LINE__, WSAGetLastError ()));
3101 TCPERRORWRITEMSG();
3102 }
3103
3104 if (ioctlsocket (acceptsock, FIONBIO, &dummy) == SOCKET_ERROR) {
3105 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. ioctlsocket call failed: %ld.\n", __LINE__, WSAGetLastError ()));
3106 TCPERRORWRITEMSG();
3107 }
3108
3109 /*Increment listen depth*/
3110 ++sockstack[listenstream].currentListenDepth;
3111
3112 /*Add Socket to list*/
3113 sockstack[newstream].sockID = acceptsock;
3114 sockstack[newstream].typeID = SOCKTYPE_OPEN;
3115 sockstack[newstream].listenReference = listenstream;
3116 sockstack[newstream].refcon = 0;
3117
3118 /*Pass "stream" and "refcon" to callback*/
3119
3120 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3121 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Accepted new socket %ld: %s (%ld, %ld).\n", __LINE__, acceptsock, stringbaseaddress (sockstack[listenstream].callback), newstream, sockstack[listenstream].refcon));
3122 TCPWRITEMSG();
3123
3124 fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
3125 #else
3126 parsecallbackstring (listenstream, newstream, sockstack[listenstream].refcon, bs);
3127
3128 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Accepted new socket %ld, stream %ld callback message %s.\n", __LINE__, (unsigned long) acceptsock, (unsigned long) newstream, stringbaseaddress(bs)));
3129 TCPWRITEMSG();
3130
3131 fl = fwsrunstring (bs);
3132 #endif
3133
3134 #ifdef PIKE
3135 }
3136 else {
3137
3138 struct linger l;
3139
3140 l.l_onoff = 1;
3141 l.l_linger = 0;
3142
3143 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
3144 TCPERRORWRITEMSG();
3145
3146 setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
3147
3148 fl = closesocket (acceptsock);
3149
3150 sockstack[newstream].typeID = SOCKTYPE_INVALID;
3151 }
3152 #endif
3153
3154 }
3155 else
3156 {
3157 /*if an error - pass this on to callback*/
3158 err = WSAGetLastError();
3159
3160 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3161 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error processing accept message %s (%ld, %ld).\n", __LINE__, stringbaseaddress (sockstack[listenstream].callback), err * -1L, sockstack[listenstream].refcon));
3162 TCPWRITEMSG();
3163
3164 fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
3165 #else
3166 parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
3167
3168 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. Error processing accept message %s.\n", __LINE__, stringbaseaddress(bs)));
3169 TCPERRORWRITEMSG();
3170
3171 fl = fwsrunstring (bs);
3172 #endif
3173
3174 sockstack[newstream].typeID = SOCKTYPE_INVALID;
3175 }
3176
3177 restartAccepter (s, listenstream);
3178
3179 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventAcceptSocket at line %d. Return value is %s.\n", __LINE__, fl?"True":"False"));
3180 TCPWRITEMSG();
3181
3182 exit:
3183
3184 return (fl);
3185 #endif
3186 } /*fwsNetEventAcceptSocket*/
3187 #endif
3188
3189
3190 boolean fwsNetEventListenStream (unsigned long port, long depth, bigstring callback, unsigned long refcon, unsigned long * stream, unsigned long ipaddr, long hdatabase) {
3191
3192 /* Set up a listner on a port */
3193
3194 SOCKET sock;
3195 SOCKADDR_IN addr;
3196 int errcode;
3197 long streamref;
3198 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3199 Handle hcallbacktree = nil;
3200 #endif
3201
3202 nullterminate (callback);
3203 TCPprintf(wsprintf(TCPmsg, "Entering fwsNetEventListenStream at line %d. Port = %ld, Depth = %ld, Refcon = %ld, Callback = %s.\n", __LINE__, port, depth, refcon, stringbaseaddress(callback)));
3204 TCPWRITEMSG ();
3205
3206 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3207 return (false);
3208
3209 if (!addsockrecord (&streamref)) {
3210 neterror ("initialize listen stream", WSAEMFILE); /*Too many open sockets*/
3211 return (false);
3212 }
3213
3214 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
3215 if (!fwsgetcallbackcodetree (callback, &hcallbacktree))
3216 return (false);
3217 #endif
3218
3219 releasethreadglobalsnopriority();
3220
3221 sock = socket(PF_INET, SOCK_STREAM, 0);
3222
3223 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventListenStream at line %d. socket call result is sock = %ld.\n", __LINE__, (long)sock));
3224 TCPWRITEMSG ();
3225
3226 if (sock == INVALID_SOCKET) {
3227 errcode = WSAGetLastError ();
3228 grabthreadglobalsnopriority();
3229 neterror("create listen stream", errcode);
3230 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
3231 disposehandle (hcallbacktree);
3232 return (false);
3233 }
3234
3235 addr.sin_family = AF_INET;
3236 addr.sin_addr.s_addr = htonl(ipaddr);
3237 addr.sin_port = htons((unsigned short) port);
3238
3239 if (bind(sock, (LPSOCKADDR)&addr, sizeof (addr)) == SOCKET_ERROR) {
3240 errcode = WSAGetLastError ();
3241 grabthreadglobalsnopriority();
3242 neterror("bind listen stream", errcode);
3243 closesocket (sock);
3244 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
3245 disposehandle (hcallbacktree);
3246 return (false);
3247 }
3248
3249 if (listen (sock, SOMAXCONN) == SOCKET_ERROR) {
3250 errcode = WSAGetLastError ();
3251 grabthreadglobalsnopriority();
3252 neterror("setup listen stream", errcode);
3253 closesocket (sock);
3254 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
3255 disposehandle (hcallbacktree);
3256 return (false);
3257 }
3258
3259 grabthreadglobalsnopriority();
3260
3261 sockstack[streamref].refcon = refcon;
3262
3263 sockstack[streamref].sockID = sock;
3264
3265 sockstack[streamref].typeID = SOCKTYPE_LISTENING;
3266
3267 copystring (callback, sockstack[streamref].callback);
3268
3269 sockstack[streamref].maxdepth = depth;
3270
3271 sockstack[streamref].listenReference = 0; //6.2a14 AR: was refcon, but probably doesn't make a difference (yet!)
3272
3273 sockstack[streamref].currentListenDepth = 0;
3274
3275 sockstack[streamref].hcallbacktree = hcallbacktree;
3276
3277
3278 *stream = streamref;
3279
3280 #ifdef MACVERSION
3281 sockListenList[sockListenCount++] = *stream;
3282 #endif
3283
3284 #ifdef ACCEPT_IN_SEPARATE_THREAD
3285 sockstack[streamref].hdatabase = (hdldatabaserecord) hdatabase; /*hdldatabaserecord of the db that contains the daemon script*/
3286
3287 if (!fwslaunchacceptingthread (streamref)) {
3288 closesocket (sock);
3289 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
3290 disposehandle (hcallbacktree);
3291 return (false);
3292 }
3293 #else
3294 #ifdef WIN95VERSION
3295 releasethreadglobalsnopriority();
3296
3297 if (WSAAsyncSelect (sock, shellframewindow, wm_processAccept, FD_ACCEPT) == SOCKET_ERROR) {
3298 /* Our interest in this has failed */
3299 errcode = WSAGetLastError ();
3300 grabthreadglobalsnopriority();
3301 neterror("setup listen stream", errcode);
3302 closesocket (sock);
3303 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
3304 disposehandle (hcallbacktree);
3305 return (false);
3306 }
3307
3308 sockstack[stream].flNotification = true;
3309
3310 grabthreadglobalsnopriority();
3311 #endif
3312 #endif
3313
3314 TCPTRACKEROUT ("fwsNetEventListenStream", __LINE__, *stream);
3315 return (true);
3316
3317 } /*fwsNetEventListenStream*/
3318
3319
3320 boolean fwsNetEventStatusStream (unsigned long stream, bigstring status, unsigned long * bytesPending) {
3321
3322 /* get the status of a stream */
3323
3324 int res;
3325 SOCKET sock;
3326 fd_set readset;
3327 struct timeval tv;
3328 // struct hostData hostdata;
3329
3330 //#if (TCPTRACKER == 1)
3331 if (!inmainthread())
3332 TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, stream);
3333 //#endif
3334
3335 *bytesPending = 0;
3336
3337 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3338 return (false);
3339
3340 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3341 intneterror (INTNETERROR_INVALIDSTREAM);
3342 return (false);
3343 }
3344
3345 sock = sockstack[stream].sockID;
3346
3347 switch (sockstack[stream].typeID) {
3348 case SOCKTYPE_INVALID:
3349 intneterror(INTNETERROR_INVALIDSTREAM);
3350 copyctopstring ("INACTIVE", status);
3351 return (false);
3352
3353 case SOCKTYPE_UNKNOWN:
3354 copyctopstring ("UNKNOWN", status);
3355 break;
3356
3357 case SOCKTYPE_OPEN:
3358 copyctopstring ("OPEN", status);
3359
3360 tv.tv_sec = 0;
3361 tv.tv_usec = 0;
3362
3363 FD_ZERO (&readset);
3364
3365 FD_SET(sock, &readset);
3366
3367 /* now check for data */
3368
3369 res = select (sock+1, &readset, NULL, NULL, &tv);
3370
3371 if (res == SOCKET_ERROR) {
3372 neterror("check status on stream", WSAGetLastError ());
3373 copyctopstring ("INACTIVE", status);
3374 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3375 return (false);
3376 }
3377
3378 if (res == 1) { /*this means that the socket we sent has data */
3379 res = ioctlsocket (sock, FIONREAD, bytesPending);
3380
3381 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventStatusStream at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, *bytesPending));
3382 TCPWRITEMSG ();
3383
3384 if (res == SOCKET_ERROR) {
3385 neterror("check status on stream", WSAGetLastError ());
3386 copyctopstring ("INACTIVE", status);
3387 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3388 return (false);
3389 }
3390
3391 if (*bytesPending == 0)
3392 {
3393 copyctopstring ("INACTIVE", status);
3394
3395 /* this condition means that the virtual socket has been closed */
3396
3397 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3398 }
3399 else
3400 copyctopstring ("DATA", status);
3401 }
3402
3403 break;
3404
3405 case SOCKTYPE_LISTENING:
3406 copyctopstring ("LISTENING", status);
3407 break;
3408
3409 case SOCKTYPE_CLOSED:
3410 copyctopstring ("CLOSED", status);
3411 break;
3412
3413 case SOCKTYPE_LISTENSTOPPED:
3414 copyctopstring ("STOPPED", status);
3415 break;
3416
3417 case SOCKTYPE_INACTIVE:
3418 copyctopstring ("INACTIVE", status);
3419 break;
3420
3421 default:
3422 copyctopstring ("UNKNOWN", status);
3423 break;
3424 }
3425
3426 nullterminate (status);
3427
3428 //#if (TCPTRACKER == 1)
3429 if (!inmainthread()) {
3430 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventStatusStream at line %d, result is %s with bytes pending %ld.\n", __LINE__, stringbaseaddress(status), *bytesPending));
3431 TCPWRITEMSG ();
3432 }
3433 //#endif
3434
3435 return (true);
3436 } /*fwsNetEventStatusStream*/
3437
3438
3439 boolean fwsNetEventGetPeerAddress (unsigned long stream, unsigned long * peeraddress, unsigned long * peerport) {
3440 SOCKADDR_IN sockAddr;
3441 SOCKET sock;
3442 int nSockAddrLen;
3443 int res;
3444
3445 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3446 intneterror (INTNETERROR_INVALIDSTREAM);
3447 return (false);
3448 }
3449
3450 TCPTRACKERIN ("fwsNetEventGetPeerAddress", __LINE__, stream);
3451
3452 sock = sockstack[stream].sockID;
3453
3454 memset(&sockAddr, 0, sizeof(sockAddr));
3455
3456 nSockAddrLen = sizeof(sockAddr);
3457
3458 res = getpeername(sock, (SOCKADDR*)&sockAddr, &nSockAddrLen);
3459
3460 if (res == SOCKET_ERROR) {
3461 neterror("get peer address", WSAGetLastError());
3462 return (false);
3463 }
3464
3465 *peerport = (unsigned long) ntohs(sockAddr.sin_port);
3466 *peeraddress = ntohl(sockAddr.sin_addr.s_addr);
3467
3468 TCPTRACKEROUT ("fwsNetEventGetPeerAddress", __LINE__, stream);
3469
3470 return (true);
3471 } /*fwsNetEventGetPeerAddress*/
3472
3473
3474 boolean fwsNetEventReadStreamUntil (unsigned long stream, Handle hbuffer, Handle hpattern, unsigned long timeoutsecs) {
3475
3476 /*
3477 6.1d1 AR: Read from a stream appending to hbuffer until hpattern is found.
3478
3479 6.1d13 AR: Only grab globals when growing the handle (for proper out of memory errors).
3480
3481 6.1b9 AR: Check the whole buffer for the pattern -- not only the part we read.
3482 */
3483
3484 SOCKET sock;
3485 fd_set readset;
3486 struct timeval tv;
3487 int res, errcode;
3488 long ix = gethandlesize (hbuffer);
3489 long ixstart = ix;
3490 unsigned long bytes;
3491
3492 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3493 return (false);
3494
3495 TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, stream);
3496
3497 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3498 intneterror (INTNETERROR_INVALIDSTREAM);
3499 return (false);
3500 }
3501
3502 sock = sockstack[stream].sockID;
3503
3504 if (sock == INVALID_SOCKET) {
3505 neterror ("read stream", WSAENOTSOCK);
3506 return (false);
3507 }
3508
3509 releasethreadglobalsnopriority();
3510
3511 tv.tv_sec = timeoutsecs;
3512 tv.tv_usec = 0;
3513
3514 FD_ZERO (&readset);
3515
3516 FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
3517 doing this just once should be totally safe.*/
3518
3519 while (searchhandle (hbuffer, hpattern, 0, ix) == -1L) {
3520
3521 res = select (sock+1, &readset, NULL, NULL, &tv);
3522
3523 switch (res) {
3524
3525 case 1: /*this means that the socket has data */
3526 res = ioctlsocket (sock, FIONREAD, &bytes);
3527
3528 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
3529 TCPWRITEMSG ();
3530
3531 if (res == SOCKET_ERROR) {
3532 errcode = WSAGetLastError ();
3533 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3534 goto exit;
3535 }
3536
3537 if (bytes == 0) { /*closed prematurely*/
3538 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3539 goto error_closedprematurely;
3540 }
3541
3542 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
3543
3544 if (!sethandlesize (hbuffer, ix + bytes))
3545 return (false); /*we have the thread globals, so we can return immediately*/
3546
3547 releasethreadglobalsnopriority();
3548
3549 lockhandle (hbuffer);
3550
3551 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
3552
3553 unlockhandle (hbuffer);
3554
3555 if (res == SOCKET_ERROR) {
3556 errcode = WSAGetLastError ();
3557 goto exit;
3558 }
3559
3560 ix += res;
3561
3562 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
3563 TCPWRITEMSG ();
3564
3565 break;
3566
3567 case 0: /*select timed out*/
3568 errcode = WSAETIMEDOUT;
3569 goto exit;
3570
3571 case SOCKET_ERROR:
3572 errcode = WSAGetLastError ();
3573 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3574 goto exit;
3575
3576 default:
3577 errcode = -1; /* should never happen*/
3578 goto exit;
3579 }
3580 }
3581
3582 grabthreadglobalsnopriority();
3583
3584 if (!sethandlesize (hbuffer, ix))
3585 return (false);
3586
3587 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntil at line %d. Total bytes read = %ld.\n", __LINE__, ix - ixstart));
3588 TCPWRITEMSG ();
3589
3590 return (true);
3591
3592 exit:
3593 grabthreadglobalsnopriority();
3594
3595 if (!sethandlesize (hbuffer, ix))
3596 return (false);
3597
3598 neterror ("read stream", errcode);
3599
3600 return (false);
3601
3602 error_closedprematurely:
3603 grabthreadglobalsnopriority();
3604
3605 if (!sethandlesize (hbuffer, ix))
3606 return (false);
3607
3608 plainneterror (STR_P_ERROR_CLOSED_PREMATURELY);
3609
3610 return (false);
3611 } /*fwsNetEventReadStreamUntil*/
3612
3613
3614
3615 boolean fwsNetEventReadStreamUntilClosed (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
3616
3617 /*
3618 6.1b15 AR: Branched from fwsNetEventReadStreamUntil. Don't look for a pattern, just read until closed.
3619 */
3620
3621 SOCKET sock;
3622 fd_set readset;
3623 struct timeval tv;
3624 int res, errcode;
3625 long ix = gethandlesize (hbuffer);
3626 long ixstart = ix;
3627 unsigned long bytes;
3628
3629 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3630 return (false);
3631
3632 TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, stream);
3633
3634 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3635 intneterror (INTNETERROR_INVALIDSTREAM);
3636 return (false);
3637 }
3638
3639 sock = sockstack[stream].sockID;
3640
3641 if (sock == INVALID_SOCKET) {
3642 neterror ("read stream", WSAENOTSOCK);
3643 return (false);
3644 }
3645
3646 releasethreadglobalsnopriority();
3647
3648 tv.tv_sec = timeoutsecs;
3649 tv.tv_usec = 0;
3650
3651 FD_ZERO (&readset);
3652
3653 FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
3654 doing this just once should be totally safe.*/
3655
3656 while (true) {
3657
3658 res = select (sock+1, &readset, NULL, NULL, &tv);
3659
3660 switch (res) {
3661
3662 case 1: /*this means that the socket has data */
3663 res = ioctlsocket (sock, FIONREAD, &bytes);
3664
3665 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
3666 TCPWRITEMSG ();
3667
3668 if (res == SOCKET_ERROR) {
3669 errcode = WSAGetLastError ();
3670 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3671 goto exit;
3672 }
3673
3674 if (bytes == 0) { /*we're done*/
3675 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3676 goto done;
3677 }
3678
3679 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
3680
3681 if (!sethandlesize (hbuffer, ix + bytes))
3682 return (false); /*we have the thread globals, so we can return immediately*/
3683
3684 releasethreadglobalsnopriority();
3685
3686 lockhandle (hbuffer);
3687
3688 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
3689
3690 unlockhandle (hbuffer);
3691
3692 if (res == SOCKET_ERROR) {
3693 errcode = WSAGetLastError ();
3694 goto exit;
3695 }
3696
3697 ix += res;
3698
3699 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
3700 TCPWRITEMSG ();
3701
3702 break;
3703
3704 case 0: /*select timed out*/
3705 errcode = WSAETIMEDOUT;
3706 goto exit;
3707
3708 case SOCKET_ERROR:
3709 errcode = WSAGetLastError ();
3710 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3711 goto exit;
3712
3713 default:
3714 errcode = -1; /* should never happen*/
3715 goto exit;
3716 }
3717 }
3718
3719 done:
3720 grabthreadglobalsnopriority();
3721
3722 if (!sethandlesize (hbuffer, ix))
3723 return (false);
3724
3725 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntilClosed at line %d. Total bytes read = %ld.\n", __LINE__, ix - ixstart));
3726 TCPWRITEMSG ();
3727
3728 return (true);
3729
3730 exit:
3731 grabthreadglobalsnopriority();
3732
3733 if (!sethandlesize (hbuffer, ix))
3734 return (false);
3735
3736 neterror ("read stream", errcode);
3737
3738 return (false);
3739 }/*fwsNetEventReadStreamUntilClosed*/
3740
3741
3742 boolean fwsNetEventReadStreamBytes (unsigned long stream, Handle hbuffer, long ctbytes, unsigned long timeoutsecs) {
3743
3744 /*
3745 6.1d1 AR: Read the specified number of bytes from the stream appending to hbuffer.
3746
3747 6.1b9 AR: ctbytes applies to the whole buffer -- not only the part we read.
3748 */
3749
3750 SOCKET sock;
3751 fd_set readset;
3752 struct timeval tv;
3753 int res;
3754 long lenbuffer = gethandlesize (hbuffer);
3755 long ix = lenbuffer;
3756 long bytes;
3757 long errcode;
3758
3759 if (ctbytes <= lenbuffer) /*6.1b8 AR: don't do anything*/
3760 return (true);
3761
3762 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3763 return (false);
3764
3765 TCPTRACKERIN ("fwsNetEventReadStreamBytes", __LINE__, stream);
3766
3767 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3768 intneterror (INTNETERROR_INVALIDSTREAM);
3769 return (false);
3770 }
3771
3772 if (!sethandlesize (hbuffer, ctbytes)) //make enough room in one go
3773 return (false);
3774
3775 sock = sockstack[stream].sockID;
3776
3777 if (sock == INVALID_SOCKET) {
3778 neterror ("read stream", WSAENOTSOCK);
3779 return (false);
3780 }
3781
3782 releasethreadglobalsnopriority(); //from now on, don't touch lang globals before
3783 //having called grabthreadglobalsnopriority
3784 tv.tv_sec = timeoutsecs;
3785 tv.tv_usec = 0;
3786
3787 FD_ZERO (&readset);
3788
3789 FD_SET (sock, &readset);
3790
3791 lockhandle (hbuffer);
3792
3793 while (ix < ctbytes) {
3794
3795 res = select (sock+1, &readset, NULL, NULL, &tv);
3796
3797 switch (res) {
3798
3799 case 1: /*this means that the socket has data */
3800 res = ioctlsocket (sock, FIONREAD, &bytes);
3801
3802 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
3803 TCPWRITEMSG ();
3804
3805 if (res == SOCKET_ERROR) {
3806 errcode = WSAGetLastError ();
3807 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3808 goto exit;
3809 }
3810
3811 if (bytes == 0) { /*closed prematurely*/
3812 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3813 goto error_closedprematurely;
3814 }
3815
3816 if (bytes > (ctbytes - ix)) /* Don't read more than ctbytes */
3817 bytes = ctbytes - ix;
3818
3819 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
3820
3821 if (res == SOCKET_ERROR) { /* might be WSAEMSGSIZE if we read less data than is available? */
3822 errcode = WSAGetLastError ();
3823 goto exit;
3824 }
3825
3826 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
3827 TCPWRITEMSG ();
3828
3829 ix += res;
3830
3831 break;
3832
3833 case 0: /*select timed out*/
3834 errcode = WSAETIMEDOUT;
3835 goto exit;
3836
3837 case SOCKET_ERROR:
3838 errcode = WSAGetLastError ();
3839 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3840 goto exit;
3841
3842 default:
3843 errcode = -1;
3844 //assert (false);
3845 goto exit;
3846 }
3847 }
3848
3849 grabthreadglobalsnopriority();
3850
3851 unlockhandle (hbuffer);
3852
3853 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamBytes at line %d. Total bytes requested = %ld, bytes read = %ld.\n", __LINE__, ctbytes, ix));
3854 TCPWRITEMSG ();
3855
3856 return (true);
3857
3858 exit:
3859 grabthreadglobalsnopriority();
3860
3861 neterror("read stream", errcode);
3862
3863 unlockhandle (hbuffer);
3864
3865 sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
3866
3867 return (false);
3868
3869 error_closedprematurely:
3870 grabthreadglobalsnopriority();
3871
3872 plainneterror (STR_P_ERROR_CLOSED_PREMATURELY);
3873
3874 unlockhandle (hbuffer);
3875
3876 sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
3877
3878 return (false);
3879 } /*fwsNetEventReadStreamBytes*/
3880
3881
3882 boolean fwsNetEventWriteHandleToStream (unsigned long stream, Handle hbuffer, unsigned long chunksize, unsigned long timeoutsecs) {
3883
3884 /* Write to stream in chunks */
3885
3886 SOCKET sock;
3887 fd_set writeset;
3888 struct timeval tv;
3889 int res;
3890 long ix = 0;
3891 unsigned long bytesremaining = gethandlesize (hbuffer);
3892 long bytestowrite;
3893 long errcode;
3894
3895 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
3896 return (false);
3897
3898 TCPTRACKERIN ("fwsNetEventWriteHandleToStream", __LINE__, stream);
3899
3900 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
3901 intneterror (INTNETERROR_INVALIDSTREAM);
3902 return (false);
3903 }
3904
3905 sock = sockstack[stream].sockID;
3906
3907 if (sock == INVALID_SOCKET) {
3908 neterror ("write stream", WSAENOTSOCK);
3909 return (false);
3910 }
3911
3912 tv.tv_sec = timeoutsecs;
3913 tv.tv_usec = 0;
3914
3915 FD_ZERO (&writeset);
3916
3917 FD_SET (sock, &writeset);
3918
3919 lockhandle (hbuffer);
3920
3921 releasethreadglobalsnopriority(); //from now on, don't touch lang globals before
3922 //having called grabthreadglobalsnopriority
3923 do {
3924
3925 res = select (sock+1, NULL, &writeset, NULL, &tv);
3926
3927 switch (res) {
3928
3929 case 1: /*this means that we can write to the socket */
3930 bytestowrite = (bytesremaining < chunksize) ? bytesremaining : chunksize;
3931
3932 res = send (sock, &((*hbuffer) [ix]), bytestowrite, 0);
3933
3934 if (res == SOCKET_ERROR) {
3935
3936 errcode = WSAGetLastError ();
3937
3938 #ifdef WIN95VERSION
3939 if (errcode == WSAEWOULDBLOCK) { /*work around winsock bug on win95/win98*/
3940
3941 unsigned long timewait = gettickcount() + (60L * 15L); /*max of 15 seconds*/
3942
3943 while (timewait > gettickcount ()) {
3944
3945 Sleep (100L); /*wait six ticks (100 milliseconds) and try again*/
3946
3947 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d. Attempting to re-send on stream: %d.\n", __LINE__, stream));
3948 TCPWRITEMSG();
3949
3950 res = send (sock, &((*hbuffer) [ix]), bytestowrite, 0);
3951
3952 if (res == SOCKET_ERROR) {
3953 errcode = WSAGetLastError ();
3954
3955 if (errcode != WSAEWOULDBLOCK) {
3956
3957 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d. Error re-sending on stream: %d.\n", __LINE__, stream));
3958 TCPERRORWRITEMSG();
3959
3960 goto exit; /*terminate attempts to send data and throw a script error*/
3961 }
3962 }
3963 else
3964 goto continue_send;
3965 }/*while*/
3966 }
3967
3968 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d. Gave up re-sending on stream: %d.\n", __LINE__, stream));
3969 TCPERRORWRITEMSG();
3970 #endif
3971
3972 goto exit; /*unconditionally throw a script error*/
3973 }
3974
3975 continue_send:
3976
3977 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.\n", __LINE__, bytestowrite, res));
3978 TCPWRITEMSG ();
3979
3980 bytesremaining -= res;
3981
3982 ix += res;
3983
3984 break;
3985
3986 case 0: /*select timed out*/
3987 errcode = WSAETIMEDOUT;
3988 goto exit;
3989
3990 case SOCKET_ERROR:
3991 errcode = WSAGetLastError ();
3992 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
3993 goto exit;
3994
3995 default: /*should never happen*/
3996 errcode = -1;
3997 //assert (false);
3998 goto exit;
3999 }
4000 } while (bytesremaining > 0);
4001
4002 grabthreadglobalsnopriority();
4003
4004 unlockhandle (hbuffer);
4005
4006 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteHandleToStream at line %d. Total bytes written = %ld.\n", __LINE__, ix));
4007 TCPWRITEMSG ();
4008
4009 return (true);
4010
4011 exit:
4012 grabthreadglobalsnopriority();
4013
4014 neterror("write stream", errcode);
4015
4016 unlockhandle (hbuffer);
4017
4018 return (false);
4019 } /*fwsNetEventWriteHandleToStream*/
4020
4021
4022 //#if 0
4023
4024 static boolean fwstransmitfile (unsigned long stream, ptrfilespec fs) {
4025
4026 char *buffer;
4027 static const long kFileBufferSize = 32767L;
4028 boolean fl = false;
4029 hdlfilenum fnum;
4030 long ctread = 0;
4031 long ix = 0;
4032
4033 /* open file */
4034
4035 if (!openfile (fs, &fnum, true))
4036 return (false);
4037
4038 /* allocate buffer */
4039
4040 buffer = malloc (kFileBufferSize);
4041
4042 if (buffer == nil) {
4043 memoryerror ();
4044 goto exit;
4045 }
4046
4047 while (true) {
4048
4049 /* read from file */
4050
4051 if (!filesetposition (fnum, ix))
4052 goto exit;
4053
4054 if (!filereaddata (fnum, kFileBufferSize, &ctread, buffer))
4055 goto exit;
4056
4057 if (ctread == 0) {
4058 fl = true;
4059 goto exit;
4060 }
4061
4062 ix += ctread;
4063
4064 /* write to stream */
4065
4066 if(!fwsNetEventWriteStream (stream, ctread, buffer))
4067 goto exit;
4068 }
4069
4070 exit:
4071 /* free buffer */
4072
4073 if (buffer != nil)
4074 free (buffer);
4075
4076 /* close file */
4077
4078 fl = closefile (fnum);
4079
4080 return (fl);
4081 }/*fwstransmitfile*/
4082
4083
4084 boolean fwsNetEventWriteFileToStream (unsigned long stream, Handle hprefix, Handle hsuffix, ptrfilespec fs) {
4085
4086 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
4087 return (false);
4088
4089 TCPTRACKERIN ("fwsNetEventWriteFileToStream", __LINE__, stream);
4090
4091 #ifdef WIN95VERSION
4092
4093 if (adrTransmitFile != nil) {
4094
4095 SOCKET sock;
4096 boolean fl;
4097 long errcode = 0;
4098 TRANSMIT_FILE_BUFFERS transmitbuffers;
4099 HANDLE hfile = INVALID_HANDLE_VALUE;
4100 char fn[300];
4101
4102 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
4103 intneterror (INTNETERROR_INVALIDSTREAM);
4104 return (false);
4105 }
4106
4107 sock = sockstack[stream].sockID;
4108
4109 /* open file */
4110
4111 copyptocstring (fsname (fs), fn);
4112
4113 hfile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ,
4114 NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
4115
4116 if (hfile == INVALID_HANDLE_VALUE) {
4117
4118 oserror (GetLastError ());
4119
4120 return (false);
4121 }
4122
4123 /* set up transmit buffers */
4124
4125 if (hprefix != nil) {
4126
4127 lockhandle (hprefix);
4128
4129 transmitbuffers.HeadLength = gethandlesize (hprefix);
4130
4131 transmitbuffers.Head = (void *) *hprefix;
4132 }
4133 else {
4134 transmitbuffers.HeadLength = nil;
4135
4136 transmitbuffers.Head = nil;
4137 }
4138
4139
4140 if (hsuffix != nil) {
4141
4142 lockhandle (hsuffix);
4143
4144 transmitbuffers.TailLength = gethandlesize (hsuffix);
4145
4146 transmitbuffers.Tail = (void *) *hsuffix;
4147 }
4148 else {
4149 transmitbuffers.TailLength = nil;
4150
4151 transmitbuffers.Tail = nil;
4152 }
4153
4154 /* kernel call */
4155
4156 releasethreadglobalsnopriority ();
4157
4158 fl = adrTransmitFile (sock, hfile, nil, nil, nil, &transmitbuffers, TF_WRITE_BEHIND);
4159
4160 if (!fl)
4161 errcode = GetLastError ();
4162
4163 grabthreadglobalsnopriority ();
4164
4165 /* clean up */
4166
4167 if (hprefix != nil)
4168 unlockhandle (hprefix);
4169
4170 if (hsuffix != nil)
4171 unlockhandle (hsuffix);
4172
4173 if (!fl) {
4174
4175 neterror ("write file to stream", errcode);
4176
4177 return (false);
4178 }
4179
4180 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__));
4181 TCPWRITEMSG ();
4182
4183 return (true);
4184 }
4185
4186 #endif /*WIN95VERSION*/
4187
4188 if (hprefix != nil) {
4189 boolean fl;
4190
4191 lockhandle (hprefix);
4192
4193 fl = fwsNetEventWriteStream (stream, gethandlesize (hprefix), *hprefix);
4194
4195 unlockhandle (hprefix);
4196
4197 if (!fl)
4198 return (false);
4199 }
4200
4201 if (!fwstransmitfile (stream, fs))
4202 return (false);
4203
4204 if (hsuffix != nil) {
4205 boolean fl;
4206
4207 lockhandle (hsuffix);
4208
4209 fl = fwsNetEventWriteStream (stream, gethandlesize (hsuffix), *hsuffix);
4210
4211 unlockhandle (hsuffix);
4212
4213 if (!fl)
4214 return (false);
4215 }
4216
4217 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__));
4218 TCPWRITEMSG ();
4219
4220 return (true);
4221 } /*fwsNetEventWriteFileToStream*/
4222
4223 //#endif
4224
4225 /*
4226 loop { //wait for data to read
4227 status = tcp.statusStream (stream, @bytespending);
4228 if (bytespending > 0) and (status == "DATA") {
4229 paramTable.request = paramTable.request + tcp.readStream (stream, bytespending);
4230 tcTimeout = clock.ticks () + 30}; //Now give only 1/2 second to get more data
4231 if status == "CLOSED" {
4232 break};
4233 if status == "INACTIVE" {
4234 break};
4235 if clock.ticks () > tcTimeout {
4236 break};
4237 if status == "OPEN" {
4238 sys.systemTask (); //yield a little within this thread for the system
4239 thread.sleepfor (1)}}} //yield this thread for a second to allow normal Frontier processing
4240 */
4241
4242
4243 boolean fwsNetEventInetdRead (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
4244
4245 /*
4246 6.1b2 AR: Wait timeoutsecs seconds for data to come in. After the first packed has been
4247 received, continue reading with a reduced timeout of 1 second. (For historical reasons.)
4248 */
4249
4250 SOCKET sock;
4251 fd_set readset;
4252 struct timeval tv;
4253 int res, errcode;
4254 long ix = gethandlesize (hbuffer);
4255 long ixstart = ix;
4256 unsigned long bytes;
4257
4258 if (!fwsNetEventLaunch (NO_HOST_SERVICES))
4259 return (false);
4260
4261 TCPTRACKERIN ("fwsNetEventInetdRead", __LINE__, stream);
4262
4263 if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
4264 intneterror (INTNETERROR_INVALIDSTREAM);
4265 return (false);
4266 }
4267
4268 sock = sockstack[stream].sockID;
4269
4270 if (sock == INVALID_SOCKET) {
4271 neterror ("read stream", WSAENOTSOCK);
4272 return (false);
4273 }
4274
4275 releasethreadglobalsnopriority();
4276
4277 tv.tv_sec = timeoutsecs;
4278 tv.tv_usec = 0;
4279
4280 FD_ZERO (&readset);
4281
4282 FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
4283 doing this just once should be totally safe.*/
4284 while (true) {
4285
4286 res = select (sock+1, &readset, NULL, NULL, &tv);
4287
4288 switch (res) {
4289
4290 case 1: /*this means that the socket has data */
4291 res = ioctlsocket (sock, FIONREAD, &bytes);
4292
4293 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
4294 TCPWRITEMSG ();
4295
4296 if (res == SOCKET_ERROR) {
4297 errcode = WSAGetLastError ();
4298 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
4299 goto exit;
4300 }
4301
4302 if (bytes == 0) { /*closed prematurely*/
4303 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
4304 goto done; /*not an error in this case*/
4305 }
4306
4307 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
4308
4309 if (!sethandlesize (hbuffer, ix + bytes))
4310 return (false); /*we have the thread globals, so we can return immediately*/
4311
4312 releasethreadglobalsnopriority();
4313
4314 lockhandle (hbuffer);
4315
4316 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
4317
4318 unlockhandle (hbuffer);
4319
4320 if (res == SOCKET_ERROR) {
4321 errcode = WSAGetLastError ();
4322 goto exit;
4323 }
4324
4325 ix += res;
4326
4327 tv.tv_sec = 1; /*reduce timeout to one second after the first packet has been received*/
4328
4329 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
4330 TCPWRITEMSG ();
4331
4332 break;
4333
4334 case 0: /*select timed out*/
4335 goto done; /*not an error in this case*/
4336
4337 case SOCKET_ERROR:
4338 errcode = WSAGetLastError ();
4339 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
4340 goto exit;
4341
4342 default:
4343 errcode = -1; /* should never happen*/
4344 goto exit;
4345 }
4346 }/*while*/
4347
4348 done:
4349 grabthreadglobalsnopriority();
4350
4351 if (!sethandlesize (hbuffer, ix))
4352 return (false);
4353
4354 TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventInetdRead at line %d. Total bytes read = %ld.\n", __LINE__, ix - ixstart));
4355 TCPWRITEMSG ();
4356
4357 return (true);
4358
4359 exit:
4360 grabthreadglobalsnopriority();
4361
4362 neterror ("read stream", errcode);
4363
4364 return (false);
4365 } /*fwsNetEventInetdRead*/
4366
4367
4368 boolean fwsNetEventGetStats (unsigned long stream, bigstring bs) {
4369
4370 unsigned long ctopen = 0;
4371 unsigned long ctdata = 0;
4372 unsigned long ctclosed = 0;
4373 unsigned long ctinactive = 0;
4374 unsigned long i;
4375
4376 setemptystring (bs);
4377
4378 for (i = 1; i <= FRONTIER_MAX_STREAM; i++) {
4379
4380 if (sockstack[i].listenReference == (long) stream) {
4381
4382 switch (sockstack[i].typeID) {
4383
4384 case SOCKTYPE_OPEN:
4385 ctopen++;
4386 break;
4387
4388 case SOCKTYPE_DATA:
4389 ctdata++;
4390 break;
4391
4392 case SOCKTYPE_CLOSED:
4393 ctclosed++;
4394 break;
4395
4396 case SOCKTYPE_INACTIVE:
4397 ctinactive++;
4398 break;
4399 }/*switch*/
4400 }
4401 }/*for*/
4402
4403 pushlong (ctopen, bs);
4404
4405 pushchar (',', bs);
4406
4407 pushlong (ctdata, bs);
4408
4409 pushchar (',', bs);
4410
4411 pushlong (ctclosed, bs);
4412
4413 pushchar (',', bs);
4414
4415 pushlong (ctinactive, bs);
4416
4417 return (true);
4418 }/*fwsNetEventGetStats*/
4419
4420
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.