WinSockNetEvents.c

Go to the documentation of this file.
00001 
00002 /*  $Id: WinSockNetEvents.c 1254 2006-04-12 20:27:14Z sethdill $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 /*************************************************************************
00029 
00030 This file contains the Frontier NetEvents interface for the Windows
00031 version.  It uses the WinSock 1.1 specification.  Extensions should be 
00032 added for the 2.0 specification at a later date.  The primary advantage
00033 of the 2.x specification is that more then just the TCP/IP protocol is
00034 supported.  In fact many protocols are supported including the Apple
00035 Share protocol.
00036 
00037 
00038 Created 7/20/97 Robert Bierman
00039 
00040   General Note:  All addresses are in HOST format.  We convert to network
00041   format internally.
00042 
00043 **************************************************************************/
00044 
00045 
00046 #include "frontier.h"
00047 #include "standard.h"
00048 
00049 
00050 #ifdef NeverDefine_For_Reference
00051 For reference I am listing the error codes from the windows winsock.h file here
00052 
00053 /*
00054  * All Windows Sockets error constants are biased by WSABASEERR from
00055  * the "normal"
00056  */
00057 #define WSABASEERR              10000
00058 /*
00059  * Windows Sockets definitions of regular Microsoft C error constants
00060  */
00061 #define WSAEINTR                (WSABASEERR+4)
00062 #define WSAEBADF                (WSABASEERR+9)
00063 #define WSAEACCES               (WSABASEERR+13)
00064 #define WSAEFAULT               (WSABASEERR+14)
00065 #define WSAEINVAL               (WSABASEERR+22)
00066 #define WSAEMFILE               (WSABASEERR+24)
00067 
00068 /*
00069  * Windows Sockets definitions of regular Berkeley error constants
00070  */
00071 #define WSAEWOULDBLOCK          (WSABASEERR+35)
00072 #define WSAEINPROGRESS          (WSABASEERR+36)
00073 #define WSAEALREADY             (WSABASEERR+37)
00074 #define WSAENOTSOCK             (WSABASEERR+38)
00075 #define WSAEDESTADDRREQ         (WSABASEERR+39)
00076 #define WSAEMSGSIZE             (WSABASEERR+40)
00077 #define WSAEPROTOTYPE           (WSABASEERR+41)
00078 #define WSAENOPROTOOPT          (WSABASEERR+42)
00079 #define WSAEPROTONOSUPPORT      (WSABASEERR+43)
00080 #define WSAESOCKTNOSUPPORT      (WSABASEERR+44)
00081 #define WSAEOPNOTSUPP           (WSABASEERR+45)
00082 #define WSAEPFNOSUPPORT         (WSABASEERR+46)
00083 #define WSAEAFNOSUPPORT         (WSABASEERR+47)
00084 #define WSAEADDRINUSE           (WSABASEERR+48)
00085 #define WSAEADDRNOTAVAIL        (WSABASEERR+49)
00086 #define WSAENETDOWN             (WSABASEERR+50)
00087 #define WSAENETUNREACH          (WSABASEERR+51)
00088 #define WSAENETRESET            (WSABASEERR+52)
00089 #define WSAECONNABORTED         (WSABASEERR+53)
00090 #define WSAECONNRESET           (WSABASEERR+54)
00091 #define WSAENOBUFS              (WSABASEERR+55)
00092 #define WSAEISCONN              (WSABASEERR+56)
00093 #define WSAENOTCONN             (WSABASEERR+57)
00094 #define WSAESHUTDOWN            (WSABASEERR+58)
00095 #define WSAETOOMANYREFS         (WSABASEERR+59)
00096 #define WSAETIMEDOUT            (WSABASEERR+60)
00097 #define WSAECONNREFUSED         (WSABASEERR+61)
00098 #define WSAELOOP                (WSABASEERR+62)
00099 #define WSAENAMETOOLONG         (WSABASEERR+63)
00100 #define WSAEHOSTDOWN            (WSABASEERR+64)
00101 #define WSAEHOSTUNREACH         (WSABASEERR+65)
00102 #define WSAENOTEMPTY            (WSABASEERR+66)
00103 #define WSAEPROCLIM             (WSABASEERR+67)
00104 #define WSAEUSERS               (WSABASEERR+68)
00105 #define WSAEDQUOT               (WSABASEERR+69)
00106 #define WSAESTALE               (WSABASEERR+70)
00107 #define WSAEREMOTE              (WSABASEERR+71)
00108 
00109 #define WSAEDISCON              (WSABASEERR+101)
00110 
00111 /*
00112  * Extended Windows Sockets error constant definitions
00113  */
00114 #define WSASYSNOTREADY          (WSABASEERR+91)
00115 #define WSAVERNOTSUPPORTED      (WSABASEERR+92)
00116 #define WSANOTINITIALISED       (WSABASEERR+93)
00117 
00118 /*
00119  * Error return codes from gethostbyname() and gethostbyaddr()
00120  * (when using the resolver). Note that these errors are
00121  * retrieved via WSAGetLastError() and must therefore follow
00122  * the rules for avoiding clashes with error numbers from
00123  * specific implementations or language run-time systems.
00124  * For this reason the codes are based at WSABASEERR+1001.
00125  * Note also that [WSA]NO_ADDRESS is defined only for
00126  * compatibility purposes.
00127  */
00128 
00129 #define h_errno         WSAGetLastError()
00130 
00131 /* Authoritative Answer: Host not found */
00132 #define WSAHOST_NOT_FOUND       (WSABASEERR+1001)
00133 #define HOST_NOT_FOUND          WSAHOST_NOT_FOUND
00134 
00135 /* Non-Authoritative: Host not found, or SERVERFAIL */
00136 #define WSATRY_AGAIN            (WSABASEERR+1002)
00137 #define TRY_AGAIN               WSATRY_AGAIN
00138 
00139 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
00140 #define WSANO_RECOVERY          (WSABASEERR+1003)
00141 #define NO_RECOVERY             WSANO_RECOVERY
00142 
00143 /* Valid name, no data record of requested type */
00144 #define WSANO_DATA              (WSABASEERR+1004)
00145 #define NO_DATA                 WSANO_DATA
00146 
00147 /* no address, look for MX record */
00148 #define WSANO_ADDRESS           WSANO_DATA
00149 #define NO_ADDRESS              WSANO_ADDRESS
00150 
00151 #endif
00152 //This ends the Reference Section
00153 
00154 
00155 static unsigned char * tcperrorstrings [80] = {
00156     BIGSTRING (""),
00157     BIGSTRING ("\x1b" "Host not found. (DNS error)"),                   /* 1 */
00158     BIGSTRING ("\x37" "Non-authoritative host not found. (Temporary DNS error)"),   /* 2 */
00159     BIGSTRING ("\x22" "Non-recoverable error. (DNS error)"),                        /* 3 */
00160     BIGSTRING ("\x39" "Valid name, no data record of requested type. (DNS error)"), /* 4 */
00161     BIGSTRING ("\x12" "Input/output error"),                /* 5 */
00162     BIGSTRING ("\x15" "Device not configured"),         /* 6 */
00163     BIGSTRING ("\x16" "Argument list too long"),            /* 7 */
00164     BIGSTRING ("\x11" "Exec format error"),             /* 8 */
00165     BIGSTRING ("\x13" "Bad file descriptor"),           /* 9 */
00166     BIGSTRING ("\x12" "No child processes"),                /* 10 */
00167     BIGSTRING ("\x19" "Resource deadlock avoided"),     /* 11 */
00168     BIGSTRING ("\x16" "Cannot allocate memory"),            /* 12 */
00169     BIGSTRING ("\x11" "Permission denied"),             /* 13 */
00170     BIGSTRING ("\x0b" "Bad address"),                   /* 14 */
00171     BIGSTRING ("\x15" "Block device required"),         /* 15 */
00172     BIGSTRING ("\x0b" "Device busy"),                   /* 16 */
00173     BIGSTRING ("\x0b" "File exists"),                   /* 17 */
00174     BIGSTRING ("\x11" "Cross-device link"),             /* 18 */
00175     BIGSTRING ("\x21" "Operation not supported by device"), /* 19 */
00176     BIGSTRING ("\x0f" "Not a directory"),               /* 20 */
00177     BIGSTRING ("\x0e" "Is a directory"),                    /* 21 */
00178     BIGSTRING ("\x10" "Invalid argument"),              /* 22 */
00179     BIGSTRING ("\x1d" "Too many open files in system"), /* 23 */
00180     BIGSTRING ("\x15" "Too many open sockets"),         /* 24 */
00181     BIGSTRING ("\x1e" "Inappropriate ioctl for device"),    /* 25 */
00182     BIGSTRING ("\x0e" "Text file busy"),                    /* 26 */
00183     BIGSTRING ("\x0e" "File too large"),                    /* 27 */
00184     BIGSTRING ("\x17" "No space left on device"),       /* 28 */
00185     BIGSTRING ("\x0d" "Illegal seek"),                  /* 29 */
00186     BIGSTRING ("\x15" "Read-only file system"),         /* 30 */
00187     BIGSTRING ("\x0e" "Too many links"),                    /* 31 */
00188     BIGSTRING ("\x0b" "Broken pipe"),                   /* 32 */
00189     BIGSTRING (""),
00190     BIGSTRING (""),
00191 
00192 /* non-blocking and interrupt i/o */
00193     BIGSTRING ("\x20" "Resource temporarily unavailable"),  /* 35 */
00194 
00195 /* ipc/network software -- argument errors */
00196     BIGSTRING ("\x23" "A blocking operation is in progress"),           /* 36 */
00197     BIGSTRING ("\x20" "Operation is already in progress"),      /* 37 */
00198 
00199 /* ipc/network software -- argument errors */
00200     BIGSTRING ("\x20" "Socket operation on a non-socket"),  /* 38 */
00201     BIGSTRING ("\x1f" "Destination address is required"),       /* 39 */
00202     BIGSTRING ("\x10" "Message too long"),                  /* 40 */
00203     BIGSTRING ("\x1e" "Protocol wrong type for socket"),    /* 41 */
00204     BIGSTRING ("\x16" "Protocol not available"),            /* 42 */
00205     BIGSTRING ("\x16" "Protocol not supported"),            /* 43 */
00206     BIGSTRING ("\x19" "Socket type not supported"),         /* 44 */
00207     BIGSTRING ("\x21" "Operation not supported on socket"), /* 45 */
00208     BIGSTRING ("\x1d" "Protocol family not supported"),     /* 46 */
00209     BIGSTRING ("\x2f" "Address family not supported by protocol family"),   /* 47 */
00210     BIGSTRING ("\x16" "Address already in use"),            /* 48 */
00211     BIGSTRING ("\x1e" "Can't assign requested address"),    /* 49 */
00212 
00213 /* ipc/network software -- operational errors */
00214     BIGSTRING ("\x0f" "Network is down"),                   /* 50 */
00215     BIGSTRING ("\x16" "Network is unreachable"),            /* 51 */
00216     BIGSTRING ("\x23" "Network dropped connection on reset"),   /* 52 */
00217     BIGSTRING ("\x20" "Software caused connection abort"),  /* 53 */
00218     BIGSTRING ("\x18" "Connection reset by peer"),          /* 54 */
00219     BIGSTRING ("\x19" "No buffer space available"),         /* 55 */
00220     BIGSTRING ("\x1b" "Socket is already connected"),       /* 56 */
00221     BIGSTRING ("\x17" "Socket is not connected"),           /* 57 */
00222     BIGSTRING ("\x20" "Can't send after socket shutdown"),  /* 58 */
00223     BIGSTRING ("\x21" "Too many references: can't splice"), /* 59 */
00224     BIGSTRING ("\x14" "Connection timed out"),              /* 60 */
00225     BIGSTRING ("\x12" "Connection refused"),                /* 61 */
00226 
00227     BIGSTRING ("\x21" "Too many levels of symbolic links"), /* 62 */
00228     BIGSTRING ("\x12" "File name too long"),                /* 63 */
00229 
00230     BIGSTRING ("\x0c" "Host is down"),                      /* 64 */
00231     BIGSTRING ("\x10" "No route to host"),                  /* 65 */
00232     BIGSTRING ("\x13" "Directory not empty"),               /* 66 */
00233     BIGSTRING ("\x12" "Too many processes"),                /* 67 */
00234     BIGSTRING ("\x0e" "Too many users"),                    /* 68 */
00235     BIGSTRING ("\x13" "Disc quota exceeded"),               /* 69 */
00236 
00237 /* Network File System */
00238     BIGSTRING ("\x15" "Stale NFS file handle"),             /* 70 */
00239     BIGSTRING ("\x21" "Too many levels of remote in path"), /* 71 */
00240     BIGSTRING ("\x11" "RPC struct is bad"),                 /* 72 */
00241     BIGSTRING ("\x11" "RPC version wrong"),                 /* 73 */
00242     BIGSTRING ("\x13" "RPC prog. not avail"),               /* 74 */
00243     BIGSTRING ("\x15" "Program version wrong"),             /* 75 */
00244     BIGSTRING ("\x19" "Bad procedure for program"),         /* 76 */
00245     BIGSTRING ("\x12" "No locks available"),                /* 77 */
00246     BIGSTRING ("\x18" "Function not implemented"),          /* 78 */
00247     BIGSTRING ("\x45" "Can't read stream because the TCP connection was closed unexpectedly."), /* 79 */
00248     }; //tcperrorstrings
00249 
00250 
00251 #define ACCEPT_CONN_WITHOUT_GLOBALS     1
00252 
00253 #ifdef WIN95VERSION
00254 #define ACCEPT_IN_SEPARATE_THREAD       1
00255 #endif
00256 
00257 #ifdef MACVERSION
00258     #ifdef FRONTIER_GUSI_2
00259         #include <compat.h>
00260         #include <fcntl.h>
00261         #include <inttypes.h>
00262         #include <netdb.h>
00263         #include <netinet/in.h>
00264         #include <arpa/inet.h>
00265         #include <sys/ioctl.h>
00266         #include <sys/socket.h>
00267         #include <sys/stat.h>
00268         #include <sys/time.h>
00269         #include <sys/types.h>
00270         #include <sys/un.h>
00271         #include <unistd.h>
00272         #include <utime.h>
00273         
00274         #include <pthread.h>
00275 
00276         #define GUSI_SpinHook   'spin'
00277 
00278         typedef void (*GUSIHook)(void);
00279         
00280         void GUSISetHook (OSType code, GUSIHook hook);
00281 
00282         #define ACCEPT_IN_SEPARATE_THREAD       1
00283 
00284     #else
00285 
00286         #include <GUSI.h>
00287         
00288         #undef ACCEPT_IN_SEPARATE_THREAD
00289 
00290     #endif
00291 
00292     #include <sys/errno.h>
00293     #include "mac.h"
00294 #endif
00295 
00296 #include "error.h"
00297 #include "file.h"
00298 #include "kb.h"
00299 #include "ops.h"
00300 #include "memory.h"
00301 #include "threads.h"
00302 #include "strings.h"
00303 #include "lang.h"
00304 #include "langinternal.h"
00305 #include "process.h"
00306 #include "processinternal.h"
00307 #include "shell.h"
00308 #include "shellhooks.h"
00309 #ifdef WIN95VERSION
00310     #include "FrontierWinMain.h"
00311 #endif
00312 
00313 #include "winsocknetevents.h"
00314 
00315 
00316 #define NO_HOST_SERVICES NULL
00317 
00318 #ifdef WIN95VERSION
00319     #define WSAGetHostError() WSAGetLastError()
00320     
00321     typedef struct hostData {
00322         
00323         void * dummy; // strucure not needed under Windows
00324         } hostData;
00325 
00326     #define usleep(A) Sleep(A)
00327 
00328     //#if 0
00329         typedef int (WINAPI * tyTransmitFile) (SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
00330         static tyTransmitFile adrTransmitFile = nil;
00331     //#endif
00332 #endif
00333 
00334 #ifdef MACVERSION
00335 
00336     #ifdef FRONTIER_GUSI_2
00337     typedef struct hostData {
00338         
00339         void * dummy; // strucure not needed under Windows
00340         } hostData;
00341     #endif
00342     
00343     extern int h_errno;
00344     
00345     extern long sHostID = 0; //cached value in GUSINetDB.cp
00346     
00347     #define WSAEWOULDBLOCK EAGAIN
00348     #define WSAENOTCONN ENOTCONN
00349     #define WSAETIMEDOUT ETIMEDOUT
00350     #define WSAECONNABORTED ECONNABORTED
00351     #define WSAENOTSOCK ENOTSOCK
00352     #define WSAEMFILE EMFILE
00353     #define WSAGetLastError() (errno == EINTR? userCanceledErr : errno)
00354     #define WSAGetHostError() h_errno
00355 
00356     #define wsprintf sprintf
00357 
00358     #define INVALID_SOCKET  (SOCKET)(~0)
00359     #define SOCKET_ERROR            (-1)
00360 
00361     #define SD_READ     0
00362     #define SD_SEND     1
00363     #define SD_BOTH     2
00364 
00365     #define closesocket(foo) close(foo)
00366     #define ioctlsocket(d,request,argp) ioctl(d,request,argp)
00367     typedef int SOCKET;
00368 
00369     /* Microsoft Windows Extended data types */
00370     #define FAR
00371 
00372     typedef struct sockaddr SOCKADDR;
00373     typedef struct sockaddr *PSOCKADDR;
00374     typedef struct sockaddr FAR *LPSOCKADDR;
00375 
00376     typedef struct sockaddr_in SOCKADDR_IN;
00377     typedef struct sockaddr_in *PSOCKADDR_IN;
00378     typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
00379 
00380     typedef struct linger LINGER;
00381     typedef struct linger *PLINGER;
00382     typedef struct linger FAR *LPLINGER;
00383 
00384     typedef struct in_addr IN_ADDR;
00385     typedef struct in_addr *PIN_ADDR;
00386     typedef struct in_addr FAR *LPIN_ADDR;
00387 #endif
00388 
00389 #define SOCKTYPE_INVALID -1
00390 #define SOCKTYPE_UNKNOWN 0
00391 #define SOCKTYPE_OPEN 1
00392 #define SOCKTYPE_DATA 2
00393 #define SOCKTYPE_LISTENING 3
00394 #define SOCKTYPE_CLOSED 4
00395 #define SOCKTYPE_LISTENSTOPPED 5
00396 #define SOCKTYPE_INACTIVE 6
00397 
00398 #define FRONTIER_MAX_STREAM 256
00399 #define INTNETERROR_INVALIDSTREAM -1
00400 
00401 typedef short tysocktypeid;
00402 
00403 typedef struct tysockRecord {
00404     SOCKET          sockID;
00405     tysocktypeid    typeID;
00406     long            refcon;
00407     bigstring       callback;
00408     long            maxdepth;
00409     long            listenReference;
00410     long            currentListenDepth;
00411     boolean         flNotification;
00412     #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
00413         Handle          hcallbacktree;
00414     #endif
00415     #ifdef ACCEPT_IN_SEPARATE_THREAD
00416         long                idthread;
00417         hdldatabaserecord   hdatabase;
00418     #endif
00419     } sockRecord;
00420 
00421 
00422 static short frontierWinSockCount = 0;
00423 static boolean frontierWinSockLoaded = false;
00424 static sockRecord sockstack[FRONTIER_MAX_STREAM];
00425 
00426 
00427 #ifdef MACVERSION
00428     static short sockListenCount = 0;
00429     static short sockListenList[FRONTIER_MAX_STREAM];
00430 #endif
00431 
00432 
00433 #ifdef WIN95VERSION
00434     
00435 static CRITICAL_SECTION sockstacksection;
00436 
00437 static boolean sockstacksectioninitialized = false;
00438 
00439 static void _entercriticalsockstacksection (void) {
00440 
00441     if (!sockstacksectioninitialized) {
00442 
00443         InitializeCriticalSection (&sockstacksection);
00444 
00445         sockstacksectioninitialized = true;
00446         }
00447     
00448     EnterCriticalSection (&sockstacksection);
00449     }
00450 
00451 static void _leavecriticalsockstacksection (void) {
00452 
00453     LeaveCriticalSection (&sockstacksection);
00454     }
00455 
00456 #else
00457 
00458 #define _entercriticalsockstacksection()
00459 
00460 #define _leavecriticalsockstacksection()
00461 
00462 #endif
00463 
00464 
00465 static char * TCPGETTYPE (tysocktypeid typeID) {
00466     switch (typeID) {
00467         case SOCKTYPE_INVALID:
00468             return ("INVALID");
00469 
00470         case SOCKTYPE_UNKNOWN:
00471             return ("UNKNOWN");
00472 
00473         case SOCKTYPE_OPEN:
00474             return ("OPEN");
00475 
00476         case SOCKTYPE_DATA:
00477             return ("DATA");
00478 
00479         case SOCKTYPE_LISTENING:
00480             return ("LISTENING");
00481 
00482         case SOCKTYPE_CLOSED:
00483             return ("CLOSED");
00484 
00485         case SOCKTYPE_LISTENSTOPPED:
00486             return ("LISTEN-STOPPED");
00487 
00488         case SOCKTYPE_INACTIVE:
00489             return ("INACTIVE");
00490 
00491         default:
00492             break;
00493         }
00494 
00495     return ("BAD Type value");
00496     } /*TCPGETTYPE*/
00497 
00498 
00499 
00500 #define STR_P_ERROR_CLOSED_PREMATURELY  BIGSTRING ("\x45" "Can't read stream because the TCP connection was closed unexpectedly.")
00501 
00502 /*
00503     To disable the tcp tracker, don't define TCPTRACKER.
00504 
00505     To enable tcp tracker ouput in the about window, define TCPTRACKER == 1.
00506 
00507     To enable tcp tracker error ouput to a file, define TCPTRACKER == 2.
00508 
00509     To enable full tcp tracker output to a file, define TCPTRACKER == 3.
00510 */
00511 
00512 
00513 //#undef TCPTRACKER
00514 #define TCPTRACKER 1
00515 //#define TCPTRACKER 2
00516 //#define TCPTRACKER 3
00517 
00518 #if (TCPTRACKER == 3)
00519 #pragma message ("*********************** TCPTRACKER is ON: Full output to tcpfile.txt ***********************")
00520 
00521 static boolean fllogger = true;
00522 
00523 #ifdef WIN95VERSION
00524 extern  DWORD ixthreadglobalsgrabcount;         // Tls index of counter for nest globals grabbing
00525 #endif
00526 
00527 static FILE * tcpfile = NULL;
00528 static char TCPmsg[400];
00529 
00530 #define TCPprintf(msg) msg
00531 #define TCPERRORprintf(msg) msg
00532 
00533 static void TCPWRITEMSG () {
00534     unsigned long ticks = gettickcount ();
00535     static unsigned long lastticks = 0;
00536     #ifdef WIN95VERSION
00537         DWORD idthread;
00538         static DWORD idlastthread = 0;
00539         long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00540     #endif
00541     #ifdef MACVERSION
00542         long idthread = (long) (**getcurrentthread ()).idthread;
00543         static long idlastthread = 0;
00544     #endif
00545     
00546     if (fllogger) {
00547     #ifdef WIN95VERSION
00548         idthread = GetCurrentThreadId();
00549     #endif
00550 
00551         if (tcpfile == NULL) {
00552             tcpfile = fopen ("tcpfile.txt", "w+");
00553             }
00554 
00555         if (idthread != idlastthread) {
00556             fprintf (tcpfile, "\n");
00557             idlastthread = idthread;
00558             }
00559 
00560     #ifdef WIN95VERSION
00561         fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
00562     #endif
00563 
00564     #ifdef MACVERSION
00565         fprintf (tcpfile, "%08X (%04ld) | %04X | %s", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
00566     #endif
00567 
00568         lastticks = ticks;
00569 
00570         fflush (tcpfile);
00571         }
00572     } /*TCPWRITEMSG*/
00573 
00574 #define TCPERRORWRITEMSG TCPWRITEMSG
00575 
00576 void TCPTRACKERIN (char * functionName, int linenumber, unsigned long streamID) {
00577     if (fllogger) {
00578         if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
00579             wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld - INVALID STREAM.\n", functionName, linenumber, streamID);
00580             TCPWRITEMSG ();
00581             return;
00582             }
00583 
00584         #ifdef WIN95VERSION
00585             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",
00586                 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00587                 sockstack[streamID].currentListenDepth, sockstack[streamID].flNotification ? "ON" : "OFF",
00588                 sockstack[streamID].listenReference, sockstack[streamID].refcon);
00589         #else
00590             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",
00591                 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00592                 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
00593         #endif
00594 
00595         TCPWRITEMSG ();
00596         }
00597     } /*TCPTRACKERIN*/
00598 
00599 
00600 void TCPTRACKEROUT (char * functionName, int linenumber, unsigned long streamID) {
00601     if (fllogger) {
00602         if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
00603             wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %08lX - INVALID STREAM.\n", functionName, linenumber, streamID);
00604             TCPWRITEMSG ();
00605             return;
00606             }
00607 
00608         #ifdef WIN95VERSION
00609             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",
00610                 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00611                 sockstack[streamID].currentListenDepth, sockstack[streamID].flNotification ? "ON" : "OFF",
00612                 sockstack[streamID].listenReference, sockstack[streamID].refcon);
00613         #else
00614             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",
00615                 functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00616                 sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
00617         #endif
00618 
00619         TCPWRITEMSG ();
00620         }
00621     } /*TCPTRACKEROUT*/
00622 
00623 static void TCPTRACKERCLOSE () {
00624     if (fllogger) {
00625         if (tcpfile != NULL)
00626             fclose (tcpfile);
00627         }
00628     }
00629 
00630 
00631 #elif (TCPTRACKER == 2)
00632 #pragma message ("*********************** TCPTRACKER is ON: Error output to tcpfile.txt **********************")
00633 
00634 static boolean fllogger = true;
00635 
00636 #ifdef WIN95VERSION
00637 extern  DWORD ixthreadglobalsgrabcount;         // Tls index of counter for nest globals grabbing
00638 #endif
00639 
00640 static FILE * tcpfile = NULL;
00641 static char TCPmsg[400];
00642 
00643 #define TCPprintf(msg)
00644 #define TCPWRITEMSG()
00645 #define TCPTRACKERIN(functionName, linenumber, streamID)
00646 #define TCPTRACKEROUT(functionName, linenumber, streamID)
00647 
00648 #define TCPERRORprintf(msg) msg
00649 
00650 static void TCPERRORWRITEMSG () {
00651     unsigned long ticks = gettickcount ();
00652     static unsigned long lastticks = 0;
00653     #ifdef WIN95VERSION
00654         DWORD idthread;
00655         static DWORD idlastthread = 0;
00656         long grabcount = (long) TlsGetValue (ixthreadglobalsgrabcount);
00657     #endif
00658     #ifdef MACVERSION
00659         long idthread = (long) (**getcurrentthread ()).idthread;
00660         static long idlastthread = 0;
00661     #endif
00662     
00663     if (fllogger) {
00664     #ifdef WIN95VERSION
00665         idthread = GetCurrentThreadId();
00666     #endif
00667 
00668         if (tcpfile == NULL) {
00669             tcpfile = fopen ("tcpfile.txt", "w+");
00670             }
00671 
00672         if (idthread != idlastthread) {
00673             fprintf (tcpfile, "\n");
00674             idlastthread = idthread;
00675             }
00676 
00677     #ifdef WIN95VERSION
00678         fprintf (tcpfile, "%08X (%04ld) | %04X (%02ld) | %s", (unsigned long) ticks, (ticks - lastticks), idthread, grabcount, TCPmsg);
00679     #endif
00680 
00681     #ifdef MACVERSION
00682         fprintf (tcpfile, "%08X (%04ld) | %04X | %s", (unsigned long) ticks, (ticks - lastticks), idthread, TCPmsg);
00683     #endif
00684 
00685         lastticks = ticks;
00686 
00687         fflush (tcpfile);
00688         }
00689     } /*TCPWRITEMSG*/
00690 
00691 
00692 static void TCPTRACKERCLOSE () {
00693     if (fllogger) {
00694         if (tcpfile != NULL)
00695             fclose (tcpfile);
00696         }
00697     }
00698 
00699 #elif (TCPTRACKER == 1)
00700 #pragma message ("*********************** TCPTRACKER is ON: Full output to About window **********************")
00701 
00702 #include "about.h"
00703 #define fllogger (aboutstatsshowing())
00704 #define TCPprintf(msg) msg
00705 #define TCPERRORprintf(msg) msg
00706 
00707 static char TCPmsg[400];
00708 
00709 static void TCPWRITEMSG () {
00710     
00711     if (fllogger) {
00712         
00713         convertcstring (TCPmsg);
00714         
00715         aboutsetmiscstring (TCPmsg);
00716         }
00717     } /*TCPWRITEMSG*/
00718 
00719 #define TCPERRORWRITEMSG TCPWRITEMSG
00720 
00721 static void TCPTRACKERIN (char * functionName, int linenumber, unsigned long streamID) {
00722     if (fllogger) {
00723         if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
00724             wsprintf (TCPmsg, "Entering %s at line %d, Stream = %ld - INVALID STREAM.\n", functionName, linenumber, streamID);
00725             TCPWRITEMSG ();
00726             return;
00727             }
00728 
00729         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",
00730             functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00731             sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
00732 
00733         TCPWRITEMSG ();
00734         }
00735     } /*TCPTRACKERIN*/
00736 
00737 
00738 static void TCPTRACKEROUT (char * functionName, int linenumber, unsigned long streamID) {
00739     if (fllogger) {
00740         if ((streamID < 1) || (streamID >= FRONTIER_MAX_STREAM)) {
00741             wsprintf (TCPmsg, "Exiting %s at line %d, Stream = %08lX - INVALID STREAM.\n", functionName, linenumber, streamID);
00742             TCPWRITEMSG ();
00743             return;
00744             }
00745 
00746         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",
00747             functionName, linenumber, streamID, sockstack[streamID].sockID, TCPGETTYPE (sockstack[streamID].typeID), sockstack[streamID].maxdepth,
00748             sockstack[streamID].currentListenDepth, sockstack[streamID].listenReference, sockstack[streamID].refcon);
00749 
00750         TCPWRITEMSG ();
00751         }
00752     } /*TCPTRACKEROUT*/
00753 
00754 #define TCPTRACKERCLOSE()
00755 
00756 #else
00757 
00758 #define TCPprintf(msg)
00759 #define TCPERRORprintf(msg)
00760 #define TCPWRITEMSG()
00761 #define TCPERRORWRITEMSG()
00762 #define TCPTRACKERIN(functionName, linenumber, streamID)
00763 #define TCPTRACKEROUT(functionName, linenumber, streamID)
00764 #define TCPTRACKERCLOSE()
00765 
00766 #endif
00767 
00768 
00769 static boolean getsockrecord (SOCKET sock, long *stream) {
00770     long i;
00771 
00772     for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
00773         if (sockstack[i].sockID == sock) {
00774             *stream = i;
00775             return (true);
00776             }
00777         }
00778 
00779     *stream = -1;
00780 
00781     return (false);
00782     } /*getsockrecord*/
00783 
00784 
00785 static void initsockrecord (long i) {
00786 
00787     /*
00788     5.0.2b21 dmb: share repeated code
00789     */
00790     
00791     sockstack[i].sockID = INVALID_SOCKET;
00792     sockstack[i].typeID = SOCKTYPE_UNKNOWN;
00793     sockstack[i].maxdepth = 0;
00794     sockstack[i].listenReference = 0;
00795     sockstack[i].currentListenDepth = 0;
00796     sockstack[i].refcon = 0;
00797     copystring (emptystring, sockstack[i].callback);
00798     sockstack[i].flNotification = false;
00799     #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
00800         sockstack[i].hcallbacktree = nil;
00801     #endif
00802     #ifdef ACCEPT_IN_SEPARATE_THREAD
00803         sockstack[i].idthread = nil;
00804         sockstack[i].hdatabase = nil;
00805     #endif
00806     } /*initsockrecord*/
00807 
00808 
00809 static boolean addsockrecord (long *stream) {
00810     
00811     /*
00812     5.1.5 dmb: reuse closed sockets before inactive ones.
00813 
00814     6.2a12 AR: This is the bottleneck for grabbing a new or used socket record.
00815     On Win32, protect the socket stack by declaring a critical section.
00816     */
00817 
00818     long i;
00819 
00820     _entercriticalsockstacksection();
00821 
00822     for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
00823         if (sockstack[i].typeID == SOCKTYPE_INVALID) {
00824             initsockrecord (i);
00825             *stream = i;
00826             _leavecriticalsockstacksection();
00827             return (true);
00828             }
00829         }
00830     
00831     /* If none are inactive, reuse those that are closed */
00832     
00833     for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
00834         if (sockstack[i].typeID == SOCKTYPE_CLOSED) {
00835             initsockrecord (i);
00836             *stream = i;
00837             _leavecriticalsockstacksection();
00838             return (true);
00839             }
00840         }
00841 
00842     /* If we used up all the stack, reuse those that are inactive */
00843 
00844     for (i = 1; i < FRONTIER_MAX_STREAM; i++) {
00845         if (sockstack[i].typeID == SOCKTYPE_INACTIVE) {
00846             initsockrecord (i);
00847             *stream = i;
00848             _leavecriticalsockstacksection();
00849             return (true);
00850             }
00851         }
00852 
00853     _leavecriticalsockstacksection();
00854 
00855     *stream = -1;
00856 
00857     return (false);
00858     } /*addsockrecord*/
00859 
00860 
00861 static void clearsockstack () {
00862     long i;
00863 
00864     _entercriticalsockstacksection();
00865 
00866     for (i = 0; i < FRONTIER_MAX_STREAM; i++) {
00867         sockstack[i].sockID = INVALID_SOCKET;
00868         sockstack[i].typeID = SOCKTYPE_INVALID;
00869         }
00870 
00871     _leavecriticalsockstacksection();
00872 
00873     #ifdef MACVERSION
00874         sockListenCount = 0;
00875     #endif
00876     } /*clearsockstack*/
00877 
00878 
00879 static void gettcperrorstring (int errcode, bigstring bs) {
00880 
00881     int ixtcperr = errcode;
00882     
00883     #ifdef WIN95VERSION
00884         if (errcode >= WSAHOST_NOT_FOUND && errcode <= WSANO_DATA)
00885             ixtcperr -= 1000;
00886         
00887         ixtcperr -= WSABASEERR;
00888     #endif
00889     
00890     if (ixtcperr > 0 && ixtcperr < 80) {
00891         
00892         copystring (tcperrorstrings [ixtcperr], bs); //handles nil source
00893         
00894         if (!isemptystring (bs)) {
00895             
00896             pushchar ('.', bs);
00897 
00898             return;
00899             }
00900         }
00901     
00902     #ifdef MACVERSION
00903         getsystemerrorstring (errcode, bs);
00904     #endif
00905     
00906     #ifdef WIN95VERSION
00907         getwinerrormessage (errcode, bs);
00908         
00909         firstword (bs, '.', bs); //skip the cr  
00910     #endif
00911     
00912     } /*gettcperrorstring*/
00913 
00914 
00915 static void plainneterror (bigstring bs) {
00916 
00917     /*
00918     6.1b15 AR
00919     */
00920 
00921     bigstring errbs;
00922     
00923     copystring (bs, errbs);
00924 
00925     nullterminate (errbs);
00926     
00927     TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s.\n", stringbaseaddress(errbs)));
00928     TCPERRORWRITEMSG ();
00929     
00930     langerrormessage (bs);
00931     } /*neterror*/
00932 
00933 
00934 static void neterror (char * cannot, long errcode) {
00935 
00936     bigstring bs;
00937     bigstring errbs;
00938     char prestring[256];
00939 
00940     wsprintf (prestring, "Can't %s because TCP/IP error code %ld", cannot, (long)errcode);
00941     copyctopstring (prestring, errbs);
00942 
00943     gettcperrorstring (errcode, bs);
00944 
00945     //if (equaltextidentifiers (stringbaseaddress(bs), "No information available for error number", (short)strlen("No information available for error number")) != true) {
00946     if (!isemptystring (bs)) {
00947         
00948         pushstring (BIGSTRING ("\x03" " - "), errbs);
00949         
00950         pushstring (bs, errbs);
00951         }
00952     else {
00953         pushchar ('.', errbs);
00954         }
00955     
00956     nullterminate (errbs);
00957     
00958     TCPERRORprintf (wsprintf(TCPmsg, "NET ERROR - %s.\n", stringbaseaddress(errbs)));
00959     TCPERRORWRITEMSG ();
00960     
00961     langerrormessage (errbs);
00962     } /*neterror*/
00963 
00964 
00965 static void intneterror (long errcode) {
00966     bigstring bs;
00967 
00968     if (errcode == INTNETERROR_INVALIDSTREAM)
00969         copyctopstring ("Invalid stream", bs);
00970     else
00971         copyctopstring ("Unknown stream error", bs);
00972 
00973     langerrormessage (bs);
00974     } /*intneterror*/
00975 
00976 
00977 #ifdef MACVERSION
00978 
00979     #ifdef FRONTIER_GUSI_2
00980     
00981     static void fwsGUSI2Spin (boolean flresting) {
00982         short   mask = osMask|activMask|mDownMask|keyDownMask;
00983 
00984         if (inmainthread ()) {
00985                 
00986             if (flresting) {    
00987                 EventRecord     ev;
00988                 
00989                 if (WaitNextEvent (mask, &ev, 1L, nil))
00990                     shellprocessevent (&ev);
00991                 }
00992             else
00993                 shellyield (false);
00994             }
00995         else {
00996 /*          if (flresting) {
00997 
00998                 boolean fl;         
00999                 hdlthreadglobals hthread = getcurrentthreadglobals ();
01000                 ThreadID idthread = (ThreadID) (**hthread).idthread;
01001                 const long sleepTime = 6L;
01002                 //hdlthreadqueue hq;
01003                 
01004                 //if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &hq))
01005                 //  return (memFullErr);
01006                 
01007                 //(**hq).idthread = idthread;
01008                 
01009                 TCPprintf (wsprintf(TCPmsg, "Going to sleep for %d ticks.\n", sleepTime));
01010                 TCPWRITEMSG();
01011                 
01012                 //listlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
01013                 
01014                 fl = processsleep (hthread, sleepTime); 
01015                 
01016                 if (!fl) {
01017                     
01018                     //if (listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq))
01019                         //disposehandle ((Handle) hq);
01020                     
01021                     fl = langbackgroundtask (true);
01022                     }
01023                 
01024                 TCPprintf (wsprintf(TCPmsg, "Awake! at line %d.\n", __LINE__));
01025                 TCPWRITEMSG();
01026                 
01027             //  gusiwakethread = 0;
01028                 }
01029             else */
01030                 langbackgroundtask (true);
01031             }
01032         }/*fwsGUSI2Spin*/
01033 
01034     #else
01035     
01036     #if __powerc
01037         void RotateCursor (short);
01038         void RotateCursor (short i) {} // for GUSI
01039     #else
01040         void ROTATECURSOR (short);
01041         void ROTATECURSOR (short i) {} // for GUSI
01042     #endif
01043     
01044     typedef struct tythreadqueuerecord {
01045         
01046         struct tythreadqueuerecord **hnext;
01047         
01048         ThreadID idthread;
01049         } tythreadqueuerecord, *ptrthreadqueue, **hdlthreadqueue;
01050 
01051 
01052     static hdlthreadqueue gusisleepqueue = nil;
01053     static hdlthreadqueue gusiwakequeue = nil;
01054 
01055     
01056     static int fwsGUSISpin (spin_msg msg, long arg) {
01057     
01058         long            sleepTime = 6;  // 1/10 of a second by default
01059         boolean         flresting = true;
01060         short           mask = osMask|activMask|mDownMask|keyDownMask; //|highLevelEventMask|updateMask
01061         extern int GUSI_error (int);
01062         boolean         fl = true;
01063 
01064         if (languserescaped (false))
01065             return GUSI_error (-128);
01066 
01067         /*
01068         switch (msg) {
01069             case SP_SLEEP:
01070             case SP_SELECT:
01071                 if (arg >= sleepTime)               // Only sleep if patience guaranteed
01072                     break;
01073                 // Otherwise, fall through  
01074             case SP_AUTO_SPIN:
01075                 sleepTime = 0;
01076                 flresting = false;
01077                 break;
01078             //case SP_STREAM_WRITE:
01079             //  if (arg >= sleepTime)
01080             //      sleepTime = 120;
01081             //  break;
01082             case SP_MISC:
01083                 sleepTime = 0;
01084                 break;
01085             
01086             default:
01087                 break;
01088         }
01089         */
01090         
01091         switch (msg) {
01092             
01093             case SP_AUTO_SPIN:
01094                 return noErr;
01095             
01096             case SP_MISC:
01097                 if (arg < 0) {
01098                     sleepTime = 0;
01099                     flresting = false;
01100                     }
01101                 else
01102                     sleepTime = 6;
01103                 
01104                 break;
01105             
01106             case SP_NAME:
01107             case SP_ADDR:
01108             case SP_STREAM_READ:
01109             case SP_STREAM_WRITE:
01110                 if (arg < 0)
01111                     sleepTime = 0;
01112                 else
01113                     sleepTime = 120;
01114                 break;
01115             
01116             default:
01117                 flresting = false;
01118             }
01119         
01120         if (inmainthread ()) {
01121             
01122             if (flresting) {    
01123                 EventRecord     ev;
01124                 
01125                 if (WaitNextEvent (mask, &ev, sleepTime, nil))
01126                     shellprocessevent (&ev);
01127                 }
01128         //  else
01129         //      fl = shellyield (false);
01130             }
01131         
01132         else {
01133             if (flresting) {
01134             
01135                 hdlthreadglobals hthread = getcurrentthreadglobals ();
01136                 ThreadID idthread = (ThreadID) (**hthread).idthread;
01137                 hdlthreadqueue hq;
01138                 
01139                 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &hq))
01140                     return (memFullErr);
01141                 
01142                 (**hq).idthread = idthread;
01143                 
01144                 TCPprintf (wsprintf(TCPmsg, "Going to sleep for %d ticks.\n", sleepTime));
01145                 TCPWRITEMSG();
01146                 
01147                 listlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
01148                 
01149                 fl = processsleep (hthread, sleepTime); 
01150                 
01151                 if (!fl) {
01152                     
01153                     if (listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq))
01154                         disposehandle ((Handle) hq);
01155                     
01156                     fl = langbackgroundtask (true);
01157                     }
01158                 
01159                 TCPprintf (wsprintf(TCPmsg, "Awake! at line %d.\n", __LINE__));
01160                 TCPWRITEMSG();
01161                 
01162             //  gusiwakethread = 0;
01163                 }
01164             else
01165                 fl = langbackgroundtask (true);
01166             }
01167         
01168         if (fl)
01169             return noErr;
01170         else
01171             return -128;
01172     } /*fwsGUSISpin*/
01173 
01174 
01175 //#define GUSISLEEPQUEUESIZE 128
01176 //static ThreadID gusisleepqueue [GUSISLEEPQUEUESIZE];
01177 
01178 //static long ixlastcompleted = -1;
01179 //static long ixlastwoken = -1;
01180 
01181 static void wakecompletedthreads (void) {
01182     
01183     /*
01184     walk through the circular gusisleepqueue and wake any newly-completed threads
01185     */
01186     
01187     /*
01188     for ( ; ixlastwoken != ixlastcompleted; ixlastwoken = (ixlastwoken + 1) % GUSISLEEPQUEUESIZE) {
01189         
01190         ThreadID id = gusisleepqueue [ixlastwoken];
01191     */
01192     hdlthreadqueue hq, hnext;
01193     
01194     for (hq = (**gusiwakequeue).hnext; hq != nil; hq = hnext) {
01195         
01196         ThreadID id = (**hq).idthread;
01197         hdlthreadglobals hg = getprocessthread (id);
01198         
01199         hnext = (**hq).hnext;
01200         
01201         listunlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
01202         
01203         disposehandle ((Handle) hq);
01204         
01205         if (hg && processwake (hg)) {
01206             TCPprintf (wsprintf(TCPmsg, "Waking thread at line %d.  Thread ID: %04X.\n", __LINE__, id));
01207             TCPWRITEMSG();
01208             }
01209         else {
01210             TCPERRORprintf (wsprintf(TCPmsg, "Error waking thread at line %d.  Thread ID: %04X.\n", __LINE__, id));
01211             TCPERRORWRITEMSG();
01212             }
01213         }
01214     } /*wakecompletedthreads*/
01215 
01216 
01217 static OSErr fwsGUSIWakeThread (ThreadID idthread) {
01218     
01219     /*
01220     gusisleepqueue [ixlastcompleted] = idthread;
01221     
01222     ixlastcompleted = (ixlastcompleted + 1) % GUSISLEEPQUEUESIZE;
01223     */
01224     
01225     /*
01226     5.1.5b10 dmb: can't do much in a completion routine. just move thread 
01227     from sleepqueue to wakequeue.
01228     */
01229     
01230     hdlthreadqueue hq;
01231     
01232     for (hq = (**gusisleepqueue).hnext; hq != nil; hq = (**hq).hnext) {
01233         
01234         if ((**hq).idthread == idthread) {
01235             
01236             listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
01237             
01238             listlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
01239             
01240             break;
01241             }
01242         }
01243     
01244     return (noErr);
01245     } /*fwsGUSIWakeThread*/
01246 
01247 
01248 static boolean fwsGUSIWakeupHook (hdlprocessthread hthread) {
01249     
01250     /*
01251     if this thread is in our sleep queue, wake it up and return false
01252     
01253     just to be extra careful, handle the case where the thread is already
01254     in the wake queue
01255     */
01256     
01257     hdlthreadqueue hq;
01258     ThreadID idthread = (ThreadID) (**hthread).idthread;
01259     
01260     for (hq = (**gusisleepqueue).hnext; hq != nil; hq = (**hq).hnext) {
01261         
01262         if ((**hq).idthread == idthread) { //move it to wake queue
01263             
01264             listunlink ((hdllinkedlist) gusisleepqueue, (hdllinkedlist) hq);
01265             
01266             listlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
01267             
01268             break;
01269             }
01270         }
01271     
01272     for (hq = (**gusiwakequeue).hnext; hq != nil; hq = (**hq).hnext) {
01273         
01274         if ((**hq).idthread == idthread) { //found it in wake queue, wake it
01275             
01276             listunlink ((hdllinkedlist) gusiwakequeue, (hdllinkedlist) hq);
01277             
01278             disposehandle ((Handle) hq);
01279             
01280             if (processwake (hthread)) {
01281                 TCPprintf (wsprintf(TCPmsg, "Hook: waking thread at line %d.  Thread ID: %04X.\n", __LINE__, idthread));
01282                 TCPWRITEMSG();
01283                 }
01284             else {
01285                 TCPERRORprintf (wsprintf(TCPmsg, "Hook: error waking thread at line %d.  Thread ID: %04X.\n", __LINE__, idthread));
01286                 TCPERRORWRITEMSG();
01287                 }
01288             
01289             return (false); //hooked
01290             }
01291         }
01292     
01293     return (true); //not hooked
01294     } /*fwsGUSIWakeupHook*/
01295 
01296 
01297 #endif
01298 #endif
01299 
01300 
01301 #ifdef PIKE
01302 
01303     /*extern const*/ /*long maxconnections = 5;*/
01304 
01305     long maxconnections = longinfinity; /*7.1b5 PBS: no more connection limit*/
01306 
01307 #else
01308 
01309     /*extern const*/ long maxconnections = longinfinity; /*7.0b37 PBS: reported in system.environment table in Frontier*/
01310                                                             /*7.1b2 RAB: made global variables*/
01311 
01312 #endif
01313 
01314 /*7.0b37 PBS: Count connections in both Radio and Frontier.*/
01315 
01316 extern long ctconnections = 0;
01317 
01318 
01319 static boolean incrementconnectioncounter (void) {
01320 
01321     if (ctconnections >= maxconnections)
01322         return (false);
01323 
01324     ctconnections++;
01325 
01326     return (true);  
01327     } /*incrementconnectioncounter*/
01328 
01329 static void decrementconnectioncounter (void) {
01330     
01331     ctconnections--;
01332 
01333     assert (ctconnections >= 0);
01334 
01335     } /*decrementconnectioncounter*/
01336 
01337 
01338 long fwsNetEventGetConnectionCount (void) {
01339 
01340     /*7.0b37 PBS: return current count of TCP connections.
01341     Used by tcp.countConnections verb.
01342     */
01343 
01344     return (ctconnections);
01345     } /*fwsNetEventGetConnectionCount*/
01346 
01347 
01348 static boolean fwsNetEventLaunch (struct hostData *data) {
01349 
01350     /*
01351     Initialize the NetEvents system
01352     
01353     5.0.2b5 dmb: added hostData parameter and GUSI support to handle threading
01354     */
01355 
01356     #ifdef WIN95VERSION
01357         WSADATA wsaData; 
01358         WORD VersionRequested;
01359     #endif
01360 
01361     if (! frontierWinSockLoaded) {
01362 
01363         #ifdef WIN95VERSION
01364             //#if 0
01365                 HMODULE hmodule;
01366             //#endif
01367             
01368             #if (TCPTRACKER >= 2) //if reporting to file
01369                 long l;
01370                 if (getProfileLong (BIGSTRING ("\x0a" "TCPTracker"), &l)) {
01371                     fllogger = (boolean) l;
01372                     }
01373                 else {
01374                     setProfileLong (BIGSTRING ("\x0a" "TCPTracker"), fllogger);     /*this just sets the value in the registry*/
01375                     }
01376             #endif
01377 
01378             VersionRequested = MAKEWORD(WINSOCK_VERSION_MAJOR, WINSOCK_VERSION_MINOR);
01379 
01380             if (WSAStartup (VersionRequested, &wsaData) == SOCKET_ERROR) { 
01381                 neterror("start WinSock", WSAGetLastError ()); 
01382                 WSACleanup(); 
01383                 return (false); 
01384                 }
01385 
01386             if ((LOBYTE(wsaData.wVersion) != WINSOCK_VERSION_MAJOR) || (HIBYTE(wsaData.wVersion) != WINSOCK_VERSION_MINOR)) {
01387                 /* Tell the user that we couldn't find a useable WinSock DLL. */
01388                 WSACleanup( );
01389                 return(false); 
01390                 }
01391 
01392             /*
01393             The TransmitFile function is only available on Windows NT. 
01394             */
01395             
01396             //#if 0
01397             
01398                 hmodule = GetModuleHandle ("wsock32.dll");
01399 
01400                 if (hmodule != nil)
01401                     adrTransmitFile = (tyTransmitFile) GetProcAddress (hmodule, "TransmitFile");
01402             
01403             //#endif
01404             
01405         #endif
01406         
01407         #ifdef MACVERSION
01408             #ifdef FRONTIER_GUSI_2
01409                 //GUSISetHook (GUSI_SpinHook, (GUSIHook) fwsGUSI2Spin);
01410             #else
01411                 GUSISetup (GUSIwithInternetSockets);
01412                 
01413                 GUSISetHook (GUSI_SpinHook, (GUSIHook) fwsGUSISpin);
01414                 
01415                 GUSISetHook (GUSI_WakeThreadHook, (GUSIHook) fwsGUSIWakeThread);
01416             
01417                 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &gusisleepqueue))
01418                     return (false);
01419                 
01420                 if (!newclearhandle (sizeof (tythreadqueuerecord), (Handle *) &gusiwakequeue))
01421                     return (false);
01422                 
01423                 shellpushwakeuphook (&fwsGUSIWakeupHook);
01424             #endif
01425 
01426         #endif
01427 
01428         clearsockstack();
01429         }
01430     
01431     #ifdef MACVERSION
01432         #ifndef FRONTIER_GUSI_2
01433             sethostdata (data);
01434         #endif
01435     #endif
01436     
01437     ++frontierWinSockCount;
01438     frontierWinSockLoaded = true;
01439 
01440     return (true);
01441     } /*fwsNetEventLaunch*/
01442 
01443 
01444 /*
01445 boolean fwsNetEventIsRunning (void) {
01446 
01447     /* Indicate if we are between a fwsNetEventLaunch and a fwsNetEventQuit * /
01448 
01449     return (frontierWinSockLoaded);
01450     } /*fwsNetEventIsRunning*/
01451 
01452 
01453 #ifdef MACVERSION
01454 
01455 boolean fwsNetEventQuit (void) {
01456 
01457     /*
01458     5.0.2b10: this function is being reborn to close all listeners on the Mac
01459     */
01460     
01461     //  for (i = 0; i < sockListenCount; i++) {
01462     //      listenstream = sockListenList[i];
01463     
01464     while (sockListenCount > 0)
01465         fwsNetEventCloseListen (sockListenList [0]);
01466     
01467     return (true);
01468     } /*fwsNetEventQuit*/
01469 
01470 #endif
01471 
01472 
01473 boolean fwsNetEventShutDown (void) {
01474 
01475     /*
01476     shut down the NetEvents system
01477     This is for Frontier Internal use ONLY
01478     */
01479 
01480     frontierWinSockCount = 0;
01481 
01482     TCPTRACKERCLOSE();
01483 
01484     if (frontierWinSockLoaded) {
01485         #ifdef WIN95VERSION
01486             WSACleanup();
01487         #endif
01488 
01489         return (true);
01490         }
01491 
01492     return (false);
01493     } /*fwsNetEventShutDown*/
01494 
01495 
01496 boolean fwsNetEventAddressDecode (unsigned long addr, bigstring IPaddr) {
01497     
01498     /* Convert an address (4 byte) into a dotted IP address */
01499     
01500     char * sysstring;
01501     struct in_addr in;
01502     struct hostData hostdata;
01503 
01504     if (!fwsNetEventLaunch (&hostdata))
01505         return (false);
01506     
01507     in.s_addr = htonl(addr);
01508 
01509     sysstring = inet_ntoa (in);
01510 
01511     setstringlength (IPaddr,0);
01512     
01513     if (sysstring == NULL) {
01514         
01515         langlongparamerror (cantdecodeaddress, addr);
01516         
01517         return (false);
01518         }
01519 
01520     copyctopstring (sysstring, IPaddr);
01521 
01522     return (true);
01523     } /*fwsNetEventAddressDecode*/
01524 
01525 
01526 boolean fwsNetEventAddressEncode (bigstring IPaddr, unsigned long  * addr) {
01527     
01528     /* Convert a dotted IP address into an address (4 byte) */
01529     
01530     unsigned long netaddr;
01531     char sysstring[256];
01532     #ifdef MACVERSION
01533         #ifndef FRONTIER_GUSI_2
01534             struct in_addr foo;
01535         #endif
01536     #endif
01537     struct hostData hostdata;
01538 
01539     if (!fwsNetEventLaunch (&hostdata))
01540         return (false);
01541 
01542     copyptocstring (IPaddr, sysstring);
01543 
01544     #ifdef MACVERSION
01545         #ifdef FRONTIER_GUSI_2
01546             netaddr = inet_addr (sysstring);
01547         #else
01548             foo = inet_addr (sysstring);
01549             netaddr = foo.s_addr;
01550         #endif
01551     #endif
01552 
01553     #ifdef WIN95VERSION
01554         netaddr = inet_addr (sysstring);
01555     #endif
01556 
01557     if (netaddr == INADDR_NONE) {
01558         
01559         langparamerror (cantencodeaddress, IPaddr);
01560         
01561         return (false);
01562         }
01563 
01564     *addr = ntohl (netaddr);
01565 
01566     return (true);
01567     } /*fwsNetEventAddressEncode*/
01568 
01569 
01570 boolean fwsNetEventAddressToName (unsigned long addr, bigstring domainName) {
01571 
01572     /*
01573     Convert an address (4 byte) into a domain name
01574     
01575     5.1.5 dmb: release thread globals!
01576     */
01577     
01578     struct hostent * h;
01579     unsigned long netaddr;
01580     struct hostData hostdata;
01581     long errcode;
01582     
01583 
01584     if (!fwsNetEventLaunch (&hostdata))
01585         return (false);
01586 
01587     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventAddressToName at line %d.  Address: %ld.\n", __LINE__, addr));
01588     TCPWRITEMSG();
01589 
01590     releasethreadglobalsnopriority();
01591 
01592     netaddr = htonl(addr);
01593 
01594     h = gethostbyaddr ((char *) &netaddr, 4, PF_INET);
01595 
01596     errcode = WSAGetHostError ();
01597 
01598     grabthreadglobalsnopriority();
01599 
01600     if (h == NULL) {
01601         neterror("convert address", errcode);
01602         return (false);
01603         }
01604 
01605     copyctopstring (h->h_name, domainName);
01606 
01607     TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventAddressToName at line %d.  Domain name: %s.\n", __LINE__, h->h_name));
01608     TCPWRITEMSG();
01609 
01610     return (true);
01611     } /*fwsNetEventAddressToName*/
01612 
01613 
01614 boolean fwsNetEventNameToAddress (bigstring domainName, unsigned long * addr) {
01615     
01616     /*
01617     Convert a domain name into an address (4 byte)
01618     
01619     5.1.5 dmb: release thread globals!
01620     */
01621     
01622     struct hostent * h;
01623     char sysstring[256];
01624     struct hostData hostdata;
01625     long errcode;
01626     
01627     if (!fwsNetEventLaunch (&hostdata))
01628         return (false);
01629 
01630     copyptocstring (domainName, sysstring);
01631 
01632     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventNameToAddress at line %d.  Domain name: %s.\n", __LINE__, sysstring));
01633     TCPWRITEMSG();
01634 
01635     releasethreadglobalsnopriority();
01636 
01637     h = gethostbyname (sysstring);
01638 
01639     errcode = WSAGetHostError ();
01640 
01641     grabthreadglobalsnopriority();
01642     
01643     if (h == NULL) {
01644         neterror("convert name", errcode);
01645         return (false);
01646         }
01647     
01648     *addr = ntohl (*((long *)h->h_addr_list[0]));
01649     
01650     TCPprintf (wsprintf(TCPmsg, "Leaving fwsNetEventNameToAddress at line %d.  Address: %ld.\n", __LINE__, addr));
01651     TCPWRITEMSG();
01652     
01653     return (true);
01654     } /*fwsNetEventNameToAddress*/
01655 
01656 
01657 boolean fwsNetEventMyAddress (unsigned long * addr) {
01658     
01659     /* Get the hosts address */
01660 
01661     struct hostData hostdata;
01662     
01663     #ifdef MACVERSION
01664         
01665         if (!fwsNetEventLaunch (&hostdata))
01666             return (false);
01667         
01668         sHostID = 0; //clear cached value
01669         
01670         *addr = (unsigned long) gethostid ();
01671         
01672         return (true);
01673     #else
01674         struct hostent * h;
01675         char sysstring[256];
01676         long errcode;
01677 
01678 
01679         if (!fwsNetEventLaunch (&hostdata))
01680             return (false);
01681         
01682         if (gethostname (sysstring, 255) == SOCKET_ERROR) {
01683             neterror("get local address", WSAGetHostError ());
01684             return (false);
01685             }
01686 
01687         releasethreadglobalsnopriority ();
01688 
01689         h = gethostbyname (sysstring);
01690 
01691         errcode = WSAGetHostError ();
01692 
01693         grabthreadglobalsnopriority ();
01694 
01695         if (h == NULL) {
01696             neterror("get local address name", errcode);
01697             return (false);
01698             }
01699 
01700         *addr = ntohl (*((long *)h->h_addr_list[0]));
01701 
01702         return (true);
01703     #endif
01704     } /*fwsNetEventMyAddress*/
01705 
01706 
01707 
01708 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
01709 
01710 static boolean fwsgetcallbackcodetree (bigstring bs, Handle *htree) {
01711         
01712     Handle htext;
01713     boolean fl;
01714     unsigned long savelines;
01715     unsigned short savechars;
01716     hdltreenode hmodule = nil;
01717     
01718     if (!newtexthandle (bs, &htext))
01719         return (false);
01720     
01721     savelines = ctscanlines;
01722     
01723     savechars = ctscanchars;
01724     
01725     fl = langcompiletext (htext, false, &hmodule); /*always disposes htext*/
01726         
01727     ctscanlines = savelines;
01728     
01729     ctscanchars = savechars;
01730     
01731     if (!fl)
01732         return (false); 
01733     
01734     fl = langpacktree ((**hmodule).param1, htree); /*make a copy of the sub-tree*/
01735 
01736     langdisposetree (hmodule);
01737     
01738     return (fl);
01739     } /*fwsgetcallbackcodetree*/
01740 
01741 
01742 static boolean fwsnewprocess (hdltreenode hcode, bigstring bsname, hdlprocessrecord *hprocess) {
01743         
01744     register hdlprocessrecord hp;
01745     hdlerrorstack herrorstack;
01746     hdltablestack htablestack;
01747     tyerrorrecord item;
01748     
01749     if (!newclearhandle (sizeof (typrocessrecord), (Handle *) hprocess))
01750         return (false);
01751     
01752     hp = *hprocess; /*copy into register*/
01753     
01754     if (!newclearhandle (sizeof (tyerrorstack), (Handle *) &herrorstack)) {
01755         
01756         disposehandle ((Handle) hp);
01757         
01758         return (false);
01759         }
01760     
01761     if (!newclearhandle (sizeof (tytablestack), (Handle *) &htablestack)) {
01762         
01763         disposehandle ((Handle) hp);
01764         
01765         disposehandle ((Handle) herrorstack);
01766         
01767         return (false);
01768         }
01769     
01770     (**hp).hcode = hcode;
01771     
01772     (**hp).floneshot = true;
01773     
01774     (**hp).errormessagecallback = &langerrordialog;
01775 
01776     (**hp).debugerrormessagecallback = (langerrormessagecallback) &truenoop;
01777     
01778     (**hp).htablestack = htablestack;
01779     
01780     (**hp).herrorstack = herrorstack;
01781     
01782     (**hp).processstartedroutine = (langvoidcallback) &truenoop;
01783     
01784     (**hp).processkilledroutine = (langvoidcallback) &truenoop;
01785         
01786     item.errorcallback = nil;
01787     
01788     item.errorline = 0;
01789     
01790     item.errorchar = 0; 
01791     
01792     item.errorrefcon = 0;
01793 
01794 #ifdef flnewfeatures
01795     item.profilebase = 0;       
01796 #endif
01797     
01798     (**herrorstack).stack [(**herrorstack).toperror++] = item;
01799 
01800     copystring (bsname, (**hp).bsname);
01801 
01802     return (true);
01803     } /*newprocess*/
01804     
01805 
01806 static boolean fwsruncallback (long listenstream, long acceptstream, long refcon) {
01807 
01808     hdltreenode hcallbackaddress;
01809     hdltreenode hfunctioncall;
01810     hdltreenode hcode;
01811     hdltreenode hparam1;
01812     hdltreenode hparam2;
01813     tyvaluerecord val;
01814     hdlprocessrecord hprocess;
01815     Handle h;
01816     
01817     //build code tree
01818     
01819     if (!copyhandle (sockstack[listenstream].hcallbacktree, &h))
01820         return (false);
01821         
01822     if (!langunpacktree (h, &hcallbackaddress))
01823         return (false);
01824     
01825     setlongvalue (acceptstream, &val);
01826     
01827     if (!newconstnode (val, &hparam1)) {
01828         langdisposetree (hcallbackaddress);
01829         return (false);
01830         }
01831     
01832     setlongvalue (refcon, &val);
01833     
01834     if (!newconstnode (val, &hparam2)) {
01835         langdisposetree (hcallbackaddress);
01836         langdisposetree (hparam1);
01837         return (false);
01838         }
01839     
01840     pushlastlink (hparam2, hparam1);
01841     
01842     if (!pushbinaryoperation (functionop, hcallbackaddress, hparam1, &hfunctioncall))
01843         return (false);
01844         
01845     if (!pushbinaryoperation (moduleop, hfunctioncall, nil, &hcode))
01846         return (false);
01847 
01848     //create new process
01849     
01850     if (!fwsnewprocess (hcode, sockstack[listenstream].callback, &hprocess)) {
01851         langdisposetree (hcode);
01852         return (false);
01853         }
01854 
01855     //add new process
01856 
01857     return (addprocess (hprocess));
01858     }/*fwsruncallback*/
01859 
01860 #endif
01861 
01862 
01863 static void parsecallbackstring (long stream, long p1, long p2, bigstring bs) {
01864 
01865     /*
01866     5.1.5 dmb: common code for all callbacks
01867     */
01868 
01869     copystring (sockstack[stream].callback, bs);
01870     pushchar ('(', bs);
01871     pushlong (p1, bs);
01872     pushchar (',', bs);
01873     pushlong (p2, bs);
01874     pushchar (')', bs);
01875 
01876     nullterminate(bs); //for debug display
01877     } /*parsecallbackstring*/
01878 
01879 
01880 static boolean fwsrunstring (bigstring bs) {
01881     
01882     /*
01883     5.1.5 dmb: make sure we have thread globals for the compiler and processlist, 
01884     then run the string as a new process.
01885 
01886     note: we might special case each call and build a code tree by hand, so we
01887     don't need globals. I'm not sure if adding a new process really needs globals.
01888     */
01889 
01890     boolean fl;
01891     
01892     grabthreadglobalsnopriority ();
01893 
01894     fl = processrunstringnoerrorclear (bs);
01895     
01896     releasethreadglobalsnopriority ();
01897 
01898     return (fl);
01899     } /*fwsrunstring*/
01900 
01901 
01902 static boolean restartAccepter (SOCKET s, short listenstream) {
01903     boolean fl = true;
01904 
01905 #ifdef WIN95VERSION
01906     long err;
01907     #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
01908         bigstring bs;
01909     #endif
01910     unsigned long timewait;
01911 
01912     TCPTRACKERIN ("restartAccepter", __LINE__, listenstream);
01913 
01914     if (!sockstack[listenstream].flNotification
01915             && sockstack[listenstream].currentListenDepth < sockstack[listenstream].maxdepth) {
01916 
01917         /*Turn it on again!*/
01918 
01919         if (WSAAsyncSelect (s, shellframewindow, wm_processAccept, FD_ACCEPT) != SOCKET_ERROR)
01920             {
01921                 sockstack[listenstream].flNotification = true;
01922                 fl = true;
01923                 goto exit;
01924                 }
01925 
01926             /* Our interest in this has failed */
01927 
01928             err = WSAGetLastError();
01929 
01930             timewait = gettickcount() + (60L * 15L);        /*max of 15 seconds*/
01931 
01932             while (timewait > gettickcount()) {
01933                 if (err == WSAEINPROGRESS) {
01934                     /* let's see if we can restart this ourselves */
01935                     TCPprintf (wsprintf(TCPmsg, "In restartAccepter at line %d.  Attempting restart on listenstream: %d.\n", __LINE__, listenstream));
01936                     TCPWRITEMSG();
01937 
01938                     //threadyield (true);
01939 
01940                     Sleep (100L); //100 milliseconds -- make sure we don't control the thread globals!
01941 
01942                     if (WSAAsyncSelect (s, shellframewindow, wm_processAccept, FD_ACCEPT) != SOCKET_ERROR)
01943                         {
01944                         sockstack[listenstream].flNotification = true;
01945                         TCPprintf (wsprintf(TCPmsg, "In restartAccepter at line %d.  Got listen restarted on listenstream: %d.\n", __LINE__, listenstream));
01946                         TCPWRITEMSG();
01947                         fl = true;
01948                         goto exit;
01949                         }
01950 
01951                     err = WSAGetLastError();
01952                     }
01953                 else 
01954                     break;              /*any other error we get out*/
01955                 }
01956 
01957             sockstack[listenstream].typeID = SOCKTYPE_LISTENSTOPPED;
01958             #ifndef ACCEPT_IN_SEPARATE_THREAD
01959                 sockstack[listenstream].hevent = nil;
01960             #endif
01961 
01962             #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
01963                 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));
01964                 TCPWRITEMSG();
01965 
01966                 fl = fwsruncallback (listenstream, err * -1L, listenstream * -1L);
01967             #else
01968                 parsecallbackstring (listenstream, err * -1L, listenstream * -1L, bs);
01969 
01970                 TCPERRORprintf (wsprintf(TCPmsg, "In restartAccepter at line %d.  Error setting future accepts %s.\n", __LINE__, stringbaseaddress(bs)));
01971                 TCPERRORWRITEMSG();
01972                 
01973                 fl = fwsrunstring (bs);
01974             #endif
01975         }
01976 
01977 exit:
01978 
01979     TCPTRACKEROUT ("restartAccepter", __LINE__, listenstream);
01980 
01981 #endif
01982     return (fl);
01983     } /*restartAccepter*/
01984 
01985 
01986 static boolean checkAccepter (unsigned long stream) {
01987 
01988     if (sockstack[stream].listenReference != 0) {
01989 
01990         long listenstream = sockstack[stream].listenReference;
01991 
01992         --sockstack[listenstream].currentListenDepth;
01993 
01994         #ifdef WIN95VERSION
01995             #ifndef ACCEPT_IN_SEPARATE_THREAD
01996                 {
01997                 boolean fl;
01998 
01999                 releasethreadglobalsnopriority ();
02000 
02001                 fl = restartAccepter (sockstack[listenstream].sockID, listenstream);
02002 
02003                 grabthreadglobalsnopriority ();
02004 
02005                 return (fl);
02006                 }
02007             #endif
02008         #endif
02009         }
02010 
02011     return (true);
02012     } /*checkAccepter*/
02013 
02014 
02015 #ifdef ACCEPT_IN_SEPARATE_THREAD
02016 
02017 static boolean fwsacceptsocket (long listenstream) {
02018 
02019     /*
02020     Process an accept pending message on a socket
02021     */
02022 
02023     int sasize;
02024     struct sockaddr_in sa;
02025     SOCKET acceptsock;
02026     long err;
02027     boolean fl = false;
02028     long newstream;
02029     long dummy = 0; /*need a pointer to nil for ioctlsocket call*/
02030 
02031     TCPTRACKERIN ("fwsacceptsocket", __LINE__, listenstream);
02032     
02033     /*Accept connection*/
02034 
02035     sasize = sizeof(sa);
02036     
02037     acceptsock = accept (sockstack[listenstream].sockID, (struct sockaddr *)&sa, &sasize);
02038 
02039     if (acceptsock != INVALID_SOCKET) {
02040 
02041 #ifdef PIKE
02042         if (incrementconnectioncounter ()) {
02043 #endif
02044 
02045             /*Increment listen depth*/
02046 
02047             ++sockstack[listenstream].currentListenDepth;
02048 
02049             /*get socket record for accepted socket*/
02050 
02051             if (!addsockrecord (&newstream)) {
02052                 
02053                 struct linger l;
02054 
02055                 l.l_onoff = 1;
02056                 l.l_linger = 0;
02057 
02058                 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));
02059                 TCPERRORWRITEMSG();
02060 
02061                 setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l)); /*abort*/
02062 
02063                 fl = closesocket (acceptsock);
02064 
02065                 #ifdef PIKE
02066                     decrementconnectioncounter ();
02067                 #endif
02068 
02069                 goto exit;
02070                 }
02071     
02072             /*Add Socket to list*/      
02073             sockstack[newstream].sockID = acceptsock;
02074             sockstack[newstream].typeID = SOCKTYPE_OPEN;
02075             sockstack[newstream].listenReference = listenstream;
02076             sockstack[newstream].refcon = 0;
02077 
02078             /*Pass "stream" and "refcon" to callback*/
02079 
02080             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));
02081             TCPWRITEMSG();
02082 
02083             fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
02084 
02085 #ifdef PIKE
02086             }
02087         else {
02088 
02089             struct linger l;
02090 
02091             l.l_onoff = 1;
02092             l.l_linger = 0;
02093 
02094             TCPERRORprintf (wsprintf(TCPmsg, "In fwsacceptsocket at line %d.  Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
02095             TCPERRORWRITEMSG();
02096 
02097             setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
02098 
02099             fl = closesocket (acceptsock);
02100             }
02101 #endif
02102 
02103         }
02104     else
02105         {
02106         /*if an error - pass this on to callback*/
02107         err = WSAGetLastError();
02108 
02109         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));
02110         TCPWRITEMSG();
02111 
02112         fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
02113         
02114         }
02115 
02116 exit:
02117 
02118     TCPprintf (wsprintf(TCPmsg, "Exiting fwsacceptsocket at line %d.  Return value is %s.\n", __LINE__, fl?"True":"False"));
02119     TCPWRITEMSG();
02120     
02121     return (fl);
02122     } /*fwsacceptsocket*/
02123 
02124 
02125 static void *fwsacceptingthreadmain (long *param) {
02126 
02127     /*
02128     6.2a12 AR: we sit in a loop waiting for new connections.
02129 
02130     7.1b29 PBS: fix CPU usage 100% bug on Win98/ME by yielding in this loop.
02131     
02132     9.1b3 AR: Increased select timeout from 10 microseconds to 1 second.
02133     When select times out, it returns zero and all we do is check whether
02134     we need to break out of the while loop, so a higher timeout value is
02135     not a problem. This also makes the 7.1b29 bug fix redundant.
02136     
02137     Further, we only need to check the current listen depth if we just
02138     accepted another connection.
02139     
02140     Also, it's good practice to initialize the timeval struct through
02141     every iteration of the loop.
02142     */
02143 
02144     long listenstream = (long) param;
02145     register sockRecord* sockrecptr = &sockstack[listenstream];
02146     register SOCKET sock = sockrecptr->sockID;
02147     Handle hcallback = sockrecptr->hcallbacktree; /*keep a copy in our stack so we can safely dispose it*/  
02148     long maxdepth = sockrecptr->maxdepth;
02149     fd_set readset;
02150     struct timeval tv;
02151     int res;
02152 
02153     TCPTRACKERIN ("fwsacceptingthreadmain", __LINE__, listenstream);
02154     
02155     attachtomainthread (sockrecptr->idthread); /*6.2b7 AR*/
02156     
02157     while (sockrecptr->typeID == SOCKTYPE_LISTENING) {
02158 
02159         FD_ZERO (&readset);
02160 
02161         FD_SET (sock, &readset);
02162 
02163         tv.tv_sec = 1L;     /* 1 second */
02164         tv.tv_usec = 0L;    /* 0 micro-seconds */
02165 
02166         res = select (sock+1, &readset, NULL, NULL, &tv);
02167         
02168         TCPprintf (wsprintf(TCPmsg, "In fwsacceptingthreadmain at line %d.  Select returned %ld.\n", __LINE__, (long) res));
02169         TCPWRITEMSG();
02170     
02171         if (sockrecptr->typeID != SOCKTYPE_LISTENING || flshellclosingall) {
02172             break;
02173             }
02174 
02175         if (res == 1) {
02176 
02177             (void) fwsacceptsocket (listenstream);
02178 
02179             while (sockrecptr->currentListenDepth >= maxdepth) {
02180                 usleep (10L);   /* sleep for 10 milli-seconds */
02181                 }
02182             }
02183 
02184 /*      
02185 #ifdef PIKE
02186         usleep (10L); /+7.1b29 PBS: fix CPU usage 100% bug on Win98/ME by yielding in this loop.+/
02187 #endif
02188 */
02189         }/*while*/  
02190 
02191     disposehandle (hcallback);
02192 
02193     if (sockrecptr->typeID == SOCKTYPE_LISTENSTOPPED) {
02194         /*we have been asked by fwsNetEventCloseListen to take responsibility of cleaning up*/
02195         sockrecptr->sockID = INVALID_SOCKET;
02196         sockrecptr->typeID = SOCKTYPE_CLOSED;
02197         }
02198 
02199     TCPTRACKEROUT ("fwsacceptingthreadmain", __LINE__, listenstream);
02200 
02201     return (nil);
02202     }/*fwsacceptingthreadmain*/
02203 
02204 
02205 static boolean fwslaunchacceptingthread (long stream) {
02206     
02207     #ifdef WIN95VERSION
02208 
02209         HANDLE hthread;
02210 
02211         /*create listening thread*/
02212 
02213         hthread = CreateThread (nil, nil, (LPTHREAD_START_ROUTINE) &fwsacceptingthreadmain, (LPVOID) stream, CREATE_SUSPENDED, &sockstack[stream].idthread);
02214 
02215         if (hthread == NULL) {
02216             
02217             neterror("create listen thread", GetLastError ());
02218 
02219             return (false);
02220             }
02221 
02222         ResumeThread (hthread); /*let the new thread fly*/
02223 
02224     #else
02225     
02226         pthread_t idthread;
02227         pthread_attr_t attr;
02228         
02229         pthread_attr_init (&attr);
02230         
02231         pthread_create ((pthread_t *) &sockstack[stream].idthread, &attr, fwsacceptingthreadmain, (void *)stream);
02232     
02233         pthread_attr_destroy (&attr);
02234         
02235     #endif
02236     
02237     return (true);
02238     }/*fwslaunchacceptingthread*/
02239 
02240 #endif
02241 
02242 void fwsNetEventShutdownDependentListeners (long hdatabase) {
02243 
02244 #ifdef ACCEPT_IN_SEPARATE_THREAD
02245     long i;
02246 
02247     for (i = 1; i < FRONTIER_MAX_STREAM; i++)
02248         if (sockstack[i].typeID == SOCKTYPE_LISTENING)
02249             if (sockstack[i].hdatabase == (hdldatabaserecord) hdatabase)
02250                 sockstack[i].typeID = SOCKTYPE_LISTENSTOPPED; /*make sure the separate thread terminates before the database goes away*/
02251 #endif  
02252     }/*fwsNetEventShutdownDependentListeners*/
02253 
02254 
02255 /* Abort a stream and delete associated data */
02256 boolean fwsNetEventAbortStream (unsigned long stream) {
02257 
02258     /*
02259     5.1.5 dmb: release thread globals while we close; don't reset 
02260     socket typeID until close is complete
02261     
02262     6.2a9 AR: Don't reset socket typeID and sockID until close is complete
02263     so addsockrecord doesn't get to hand it out before we're done.
02264     This bug probably sneaked back in during the 6.1 development cycle.
02265     */
02266 
02267     SOCKET sock;
02268     int res, errcode;
02269     struct linger l;
02270 //  struct hostData hostdata;
02271 
02272     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02273         return (false);
02274 
02275     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
02276         intneterror (INTNETERROR_INVALIDSTREAM);
02277         return (false);
02278         }
02279 
02280     TCPTRACKERIN ("fwsNetEventAbortStream", __LINE__, stream);
02281 
02282     sock = sockstack[stream].sockID;
02283 
02284     l.l_onoff = 1;
02285     l.l_linger = 0;
02286 
02287     releasethreadglobalsnopriority();
02288 
02289     setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
02290 
02291     res = closesocket(sock);
02292 
02293     errcode = WSAGetLastError ();
02294 
02295     grabthreadglobalsnopriority();
02296 
02297 #ifdef PIKE
02298     decrementconnectioncounter();
02299 #endif
02300 
02301     checkAccepter (stream);
02302 
02303     sockstack[stream].sockID = INVALID_SOCKET;
02304     sockstack[stream].typeID = SOCKTYPE_CLOSED;
02305 
02306     if (res == SOCKET_ERROR) {
02307         neterror("abort stream", errcode);
02308         return (false);
02309         }
02310 
02311     TCPTRACKEROUT ("fwsNetEventAbortStream", __LINE__, stream);
02312 
02313     return (true);
02314     } /*fwsNetEventAbortStream*/
02315 
02316 
02317 boolean fwsNetEventCloseStream (unsigned long stream) {
02318 
02319     /*
02320     Close a stream and delete associated data
02321     
02322     do we want or should the user control the SO_LINGER flag for a
02323     graceful verses hard socket closure.  for now it is the user.
02324 
02325     6.2a9 AR: Don't reset socket typeID and sockID until close is complete
02326     so addsockrecord doesn't get to hand it out before we're done.
02327     This bug probably sneaked back in during the 6.1 development cycle.
02328     */
02329 
02330     SOCKET sock;
02331     long err;
02332     
02333     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02334         return (false);
02335 
02336     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
02337         intneterror (INTNETERROR_INVALIDSTREAM);
02338         return (false);
02339         }
02340 
02341     TCPTRACKERIN ("fwsNetEventCloseStream", __LINE__, stream);
02342 
02343     sock = sockstack[stream].sockID;
02344 
02345 #ifdef PIKE
02346     decrementconnectioncounter();
02347 #endif
02348 
02349     releasethreadglobalsnopriority();
02350 
02351     if (shutdown (sock, SD_SEND) == SOCKET_ERROR) {
02352         
02353         err = WSAGetLastError ();
02354 
02355         goto error;
02356         }
02357 
02358     if (closesocket(sock) == SOCKET_ERROR) {
02359         
02360         err = WSAGetLastError ();
02361 
02362         goto error;
02363         }
02364 
02365     grabthreadglobalsnopriority();
02366 
02367     checkAccepter (stream);
02368 
02369     sockstack[stream].sockID = INVALID_SOCKET;
02370     sockstack[stream].typeID = SOCKTYPE_CLOSED;
02371 
02372     TCPprintf (wsprintf(TCPmsg, "Leaving closeStream at line %d.  Thread duration: %ld ticks.\n", __LINE__, gettickcount()-(**getcurrentthreadglobals()).timestarted));
02373     TCPWRITEMSG();
02374 
02375     return (true);
02376 
02377 error:
02378     
02379     grabthreadglobalsnopriority ();
02380 
02381     sockstack[stream].sockID = INVALID_SOCKET;
02382     sockstack[stream].typeID = SOCKTYPE_CLOSED;
02383 
02384     neterror ("close stream", err);
02385 
02386     return (false);
02387     } /*fwsNetEventCloseStream*/
02388 
02389 
02390 boolean fwsNetEventCloseListen (unsigned long stream) {
02391 
02392     /*
02393     Close a listen and delete associated data
02394     
02395     do we want or should the user control the SO_LINGER flag for a
02396     graceful verses hard socket closure.  for now it is the user.
02397     
02398     5.1.5b7 dmb: set linger timeout to zero for Mac (now implemented in GUSI)
02399 
02400     6.2a9 AR: Don't reset socket typeID and sockID until close is complete
02401     so addsockrecord doesn't get to hand it out before we're done.
02402     */
02403 
02404     SOCKET sock;
02405     int res, errcode;
02406     #ifdef MACVERSION
02407         int i,j;
02408         struct linger l;
02409     #endif
02410 //  struct hostData hostdata;
02411 
02412     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02413         return (false);
02414 
02415     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
02416         intneterror (INTNETERROR_INVALIDSTREAM);
02417         return (false);
02418         }
02419 
02420     sock = sockstack[stream].sockID;
02421 
02422     /* No more messages */
02423     #ifndef ACCEPT_IN_SEPARATE_THREAD
02424         sockstack[stream].maxdepth = -100;      /*never restart select call*/
02425     #endif
02426     
02427     TCPTRACKERIN ("fwsNetEventCloseListen", __LINE__, stream);
02428 
02429     releasethreadglobalsnopriority();
02430 
02431     #ifdef WIN95VERSION
02432         #ifndef ACCEPT_IN_SEPARATE_THREAD
02433             WSAAsyncSelect (sock, shellframewindow, 0, 0);
02434         #endif
02435     #endif
02436 
02437     #ifdef MACVERSION
02438         for (i = 0; i < sockListenCount; i++) {
02439             if (sockListenList [i] == stream) {
02440                 if (i == (sockListenCount - 1)) {
02441                     //easy case - end of list to remove
02442                     --sockListenCount;
02443                     }
02444                 else {
02445                     //Move remaining down in the list
02446                     for (j = i; j < sockListenCount - 1; j++)
02447                         sockListenList[j] = sockListenList[j+1];
02448 
02449                     --sockListenCount;
02450                     }
02451 
02452                 break;      //It can only be in the list once.
02453                 }
02454             }
02455     
02456         l.l_onoff = 1;
02457         l.l_linger = 0;
02458         
02459         setsockopt (sock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
02460     
02461     #endif
02462 
02463     res = closesocket(sock);
02464 
02465     errcode = WSAGetLastError ();
02466 
02467     grabthreadglobalsnopriority();
02468 
02469 #ifdef ACCEPT_IN_SEPARATE_THREAD
02470     sockstack[stream].typeID = SOCKTYPE_LISTENSTOPPED;
02471 #else
02472     sockstack[stream].sockID = INVALID_SOCKET;
02473     sockstack[stream].typeID = SOCKTYPE_CLOSED;
02474 #endif
02475 
02476     if (res == SOCKET_ERROR) {
02477         neterror("close listen", errcode);
02478         return (false);
02479         }
02480 
02481     TCPTRACKEROUT ("fwsNetEventCloseListen", __LINE__, stream);
02482 
02483     return (true);
02484     } /*fwsNetEventCloseListen*/
02485 
02486 
02487 static short is_ipaddress (char *name) {
02488     
02489     short ctfields = 1;
02490     short fieldlen = 0;
02491     char *p = name;
02492     
02493     for (p = name; *p; ++p) {
02494         
02495         if (*p == '.') {
02496             
02497             if (fieldlen == 0) //leading dot, or consequtive dots
02498                 return (false);
02499             
02500             ++ctfields;
02501             
02502             fieldlen = 0;
02503             }
02504         else {
02505             if (!isdigit (*p))
02506                 return (false);
02507             
02508             if (++fieldlen > 3) // four consecutive digits
02509                 return (false);
02510             }
02511         }
02512     
02513     return (ctfields == 4);
02514     } /*is_ipaddress*/
02515 
02516 
02517 static boolean fwsOpenStream (struct sockaddr_in *sa, unsigned long * stream) {
02518     
02519     /*
02520     5.0.2b4 dmb: the common code between openAddrStream and openNameStream, so we
02521     don't have to convert one to the other to open a stream of either type
02522 
02523     6.1d13 AR: Release thread globals.
02524 
02525     6.2b1 AR: For Pike, decrement connection counter if connection attempt fails.
02526     */
02527     
02528     SOCKET sock;
02529     int errcode;
02530     long streamref;
02531 
02532     if (!addsockrecord (&streamref)) {
02533         neterror ("open stream", WSAEMFILE); /*Too many open sockets*/
02534         return (false);
02535         }       
02536 
02537 #ifdef PIKE
02538     if (!incrementconnectioncounter ()) {
02539 
02540         plainneterror (BIGSTRING ("\x54" "Can't open stream because no more than five TCP connections may be open at any time."));
02541 
02542         return (false);
02543         }
02544 #endif
02545     
02546     releasethreadglobalsnopriority ();
02547 
02548     sock = socket(PF_INET, SOCK_STREAM, 0);
02549 
02550     if (sock == INVALID_SOCKET) {
02551         errcode = WSAGetLastError ();
02552         goto exit;
02553         }
02554 
02555     if (connect (sock, (struct sockaddr *) sa, sizeof(*sa)) == SOCKET_ERROR) {
02556         errcode = WSAGetLastError ();
02557         closesocket (sock);
02558         goto exit;
02559         }
02560 
02561     sockstack[streamref].typeID = SOCKTYPE_OPEN;
02562 
02563     sockstack[streamref].sockID = sock;
02564 
02565     *stream = streamref;
02566     
02567     grabthreadglobalsnopriority ();
02568 
02569     return (true);
02570 
02571 exit:
02572 
02573     sockstack[streamref].typeID = SOCKTYPE_INVALID;
02574 
02575     grabthreadglobalsnopriority ();
02576 
02577     neterror ("open stream", errcode);
02578 
02579 #ifdef PIKE
02580     decrementconnectioncounter ();
02581 #endif
02582 
02583     return (false);
02584     } /*fwsOpenStream*/
02585 
02586 
02587 boolean fwsNetEventOpenAddrStream (unsigned long addr, unsigned long port, unsigned long * stream) {
02588 
02589     /*
02590     Open a stream and create associated data
02591     
02592     5.1.6 dmb: don't use a hostent; construct the sockaddr from the address, avoiding DNS
02593     */
02594     
02595     unsigned long netaddr;
02596     struct hostData hostdata;
02597     struct sockaddr_in sa;
02598     
02599     if (!fwsNetEventLaunch (&hostdata))
02600         return (false);
02601 
02602     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenAddrStream at line %d.  Address: %ld.\n", __LINE__, addr));
02603     TCPWRITEMSG();
02604 
02605     netaddr = htonl(addr);
02606 
02607     #ifdef MACVERSION
02608         sHostID = 0; //clear cached value
02609     #endif
02610     
02611     memset (&sa, 0, sizeof(sa));
02612     
02613     memcpy (&(sa.sin_addr), &netaddr, sizeof (netaddr));
02614     
02615     sa.sin_family = AF_INET;
02616     
02617     sa.sin_port = htons ((unsigned short) port);
02618     
02619     return (fwsOpenStream (&sa, stream));
02620     } /*fwsNetEventOpenAddrStream*/
02621 
02622 
02623 boolean fwsNetEventOpenNameStream (bigstring name, unsigned long port, unsigned long * stream) {
02624 
02625     /*
02626     Open a stream and create associated data
02627     
02628     5.1.6 dmb: if passed an IP address, encode address and use that instead (avoid dns)
02629     */
02630 
02631     char sysstring[256];
02632     struct hostent * hp;
02633     struct hostData hostdata;
02634     unsigned long addr;
02635     struct sockaddr_in sa;
02636     long errcode;
02637 
02638     if (!fwsNetEventLaunch (&hostdata))
02639         return (false);
02640     
02641     copyptocstring (name, sysstring);
02642     
02643     #ifdef MACVERSION
02644         sHostID = 0; //clear cached value
02645     #endif
02646     
02647     TCPprintf (wsprintf(TCPmsg, "Entering fwsNetEventOpenNameStream at line %d.  Domain name: %s.\n", __LINE__, sysstring));
02648     TCPWRITEMSG();
02649     
02650     if (is_ipaddress (sysstring)) {
02651         
02652         if (!fwsNetEventAddressEncode (name, &addr))
02653             return  (false);
02654         
02655         return (fwsNetEventOpenAddrStream (addr, port, stream));
02656         }
02657     
02658     releasethreadglobalsnopriority ();
02659 
02660     hp = gethostbyname (sysstring);
02661 
02662     errcode = WSAGetHostError ();
02663 
02664     grabthreadglobalsnopriority ();
02665 
02666     if (hp == NULL) {
02667         neterror("open named stream", errcode);
02668         return (false);
02669         }
02670     
02671     memset (&sa, 0, sizeof(sa));
02672     
02673     memcpy (&(sa.sin_addr), hp->h_addr_list[0], hp->h_length);
02674     
02675     sa.sin_family = hp->h_addrtype;
02676     
02677     sa.sin_port = htons ((unsigned short) port);
02678     
02679     return (fwsOpenStream (&sa, stream));
02680     } /*fwsNetEventOpenNameStream*/
02681 
02682 
02683 boolean fwsNetEventReadStream (unsigned long stream, unsigned long * bytesToRead, char * buffer) {
02684 
02685     /* Read from a stream */
02686 
02687     SOCKET sock;
02688     int res, errcode;
02689 //  struct hostData hostdata;
02690 
02691     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02692         return (false);
02693 
02694     TCPTRACKERIN ("fwsNetEventReadStream", __LINE__, stream);
02695 
02696     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
02697         intneterror (INTNETERROR_INVALIDSTREAM);
02698         return (false);
02699         }
02700 
02701     sock = sockstack[stream].sockID;
02702 
02703     releasethreadglobalsnopriority();
02704 
02705     res = recv (sock, buffer, *bytesToRead, 0);
02706     
02707     errcode = WSAGetLastError ();
02708 
02709     grabthreadglobalsnopriority();
02710 
02711     if (res == SOCKET_ERROR) {
02712         neterror("read stream", errcode);
02713         return (false);
02714         }
02715 
02716     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 ();})
02717     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStream at line %d.  Bytes requested = %ld, read = %ld.\n", __LINE__, *bytesToRead, (unsigned long) res));
02718     TCPWRITEMSG ();
02719 
02720 //  if (res == (int) bytesToRead)
02721 //      return (true);
02722 //
02723 //  return (false);
02724 
02725     *bytesToRead = res;
02726 
02727     return (true);
02728     } /*fwsNetEventReadStream*/
02729 
02730 
02731 boolean fwsNetEventWriteStream (unsigned long stream, unsigned long bytesToWrite, char * buffer) {
02732 
02733     /*
02734     Write to a Stream
02735     
02736     5.0.2b3 dmb: if we write fewer bytes than requested, we need to retry, generate error
02737     */
02738     
02739     SOCKET sock;
02740     int res, errcode;
02741 //  int len = sizeof (res);
02742 
02743 //  struct hostData hostdata;
02744 
02745     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
02746         return (false);
02747 
02748     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
02749         intneterror (INTNETERROR_INVALIDSTREAM);
02750         return (false);
02751         }
02752 
02753     TCPTRACKERIN ("fwsNetEventWriteStream", __LINE__, stream);
02754 
02755     sock = sockstack[stream].sockID;
02756     
02757     //if (getsockopt  (sock, SOL_SOCKET, SO_SNDBUF, &res, &len) != 0)
02758     //  ;
02759 
02760     releasethreadglobalsnopriority();
02761     
02762     res = send (sock, buffer, bytesToWrite, 0);
02763     
02764     errcode = WSAGetLastError ();
02765 
02766     grabthreadglobalsnopriority();
02767 
02768     if (res == SOCKET_ERROR) {
02769         neterror("write stream", errcode);
02770         return (false);
02771         }
02772 
02773     if (res < (int) bytesToWrite) {
02774         neterror("write stream", WSAEWOULDBLOCK);
02775         return (false);
02776         }
02777 
02778     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteStream at line %d.  Bytes requested = %ld, written = %ld.\n", __LINE__, bytesToWrite, (unsigned long) res));
02779     TCPWRITEMSG ();
02780 
02781     return (true);
02782     } /*fwsNetEventWriteStream*/
02783 
02784 
02785 #ifdef MACVERSION
02786 /*
02787 static unsigned long selects = 0;
02788 static unsigned long accepts = 0;
02789 static unsigned long selecting = 0;
02790 static unsigned long accepting = 0;
02791 static unsigned long avgselect = 0;
02792 static unsigned long avgaccept = 0;
02793 */
02794 static unsigned long maxlistendepth = 0;
02795 
02796 #ifdef FRONTIER_GUSI_2
02797 
02798 boolean fwsNetEventCheckAndAcceptSocket () { return (true); }
02799 
02800 #else
02801 
02802 boolean fwsNetEventCheckAndAcceptSocket () {
02803     int i;
02804     int res;
02805     SOCKET sock;
02806     fd_set readset;
02807     struct timeval tv;
02808     int sasize;
02809     struct sockaddr_in sa;
02810     SOCKET acceptsock;
02811     long listenstream, newstream;
02812     long err;
02813     boolean fl = true;
02814 #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
02815     bigstring bs;
02816 #endif
02817     
02818     if (!frontierWinSockLoaded)
02819         return (false);
02820 
02821 #ifndef FRONTIER_GUSI_2 
02822     wakecompletedthreads ();
02823 #endif
02824 
02825 //  unsigned long ticks;
02826 
02827     //We could set all the sockets at one time, but I think that is harder to manage.
02828     //Let's just loop through each listen socket and see if it is ready.
02829 
02830     for (i = 0; i < sockListenCount; i++) {
02831         listenstream = sockListenList[i];
02832 
02833         if (sockstack[listenstream].currentListenDepth <= (sockstack[listenstream].maxdepth)) {
02834             sock = sockstack[listenstream].sockID;
02835 
02836             tv.tv_sec = 0;
02837             tv.tv_usec = 0;
02838 
02839             FD_ZERO (&readset);
02840 
02841             FD_SET(sock, &readset);
02842 
02843             /* now check for data */
02844 
02845         //  ticks = gettickcount ();
02846             
02847             res = select (sock+1, &readset, NULL, NULL, &tv);
02848             
02849         //  selecting += gettickcount () - ticks;
02850         //  avgselect = selecting / ++selects;
02851 
02852             if (res == 1) { /* we have a live one...*/
02853 
02854                 /*Grab socket record for child socket*/
02855                 
02856                 if (!addsockrecord (&newstream)) {
02857                     /* if an error - pass this on to callback */
02858                     long err = WSAEMFILE;
02859                     
02860                     #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
02861                         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));
02862                         TCPWRITEMSG();
02863 
02864                         fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
02865                     #else
02866                         parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);;
02867 
02868                         TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d.  Error addding new socket record %s.\n", __LINE__, stringbaseaddress(bs)));
02869                         TCPERRORWRITEMSG();
02870                         
02871                         fl = fwsrunstring (bs);
02872                     #endif
02873                     
02874                     continue;
02875                     }
02876 
02877                 /*Accept connection*/
02878 
02879                 sasize = sizeof(sa);
02880                 
02881             //  ticks = gettickcount ();
02882                 
02883                 acceptsock = accept (sock, (struct sockaddr *)&sa, &sasize);
02884                 
02885             //  accepting += gettickcount () - ticks;
02886             //  avgaccept = accepting / ++accepts;
02887                 
02888                 if (acceptsock != INVALID_SOCKET) {
02889 #ifdef PIKE
02890                     if (incrementconnectioncounter ()) {
02891 #endif
02892                         /*sucessful connection -  assign this */
02893                         ++sockstack[listenstream].currentListenDepth;
02894                     
02895                         maxlistendepth = max (maxlistendepth, sockstack[listenstream].currentListenDepth);
02896                     
02897                         /*Add Socket to list*/
02898                         sockstack[newstream].refcon = 0;
02899                         sockstack[newstream].sockID = acceptsock;
02900                         sockstack[newstream].typeID = SOCKTYPE_OPEN;
02901                         sockstack[newstream].listenReference = listenstream;
02902 
02903                         /*Pass "stream" and "refcon" to callback*/
02904                         
02905                         #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
02906                             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));
02907                             TCPWRITEMSG();
02908 
02909                             fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
02910                         #else
02911                             parsecallbackstring (listenstream, newstream, sockstack[listenstream].refcon, bs);
02912 
02913                             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)));
02914                             TCPWRITEMSG();
02915                             
02916                             fl = fwsrunstring (bs);
02917                         #endif
02918                         
02919                         --i; // back up so we'll check this socket again
02920 #ifdef PIKE
02921                         }
02922                     else {
02923 
02924                         struct linger l;
02925 
02926                         l.l_onoff = 1;
02927                         l.l_linger = 0;
02928 
02929                         TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d.  Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
02930                         TCPERRORWRITEMSG();
02931 
02932                         setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
02933 
02934                         fl = closesocket (acceptsock);
02935 
02936                         sockstack[newstream].typeID = SOCKTYPE_INVALID;
02937                         }
02938 #endif
02939                     }
02940                 else
02941                     {
02942                     /* if an error - pass this on to callback */
02943                     err = WSAGetLastError();
02944 
02945                     #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
02946                         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));
02947                         TCPWRITEMSG();
02948 
02949                         fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
02950                     #else
02951                         parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
02952 
02953                         TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventCheckAndAcceptSocket at line %d.  Error processing accept message %s.\n", __LINE__, stringbaseaddress(bs)));
02954                         TCPERRORWRITEMSG();
02955                         
02956                         fl = fwsrunstring (bs);
02957                     #endif
02958                     
02959                     if (err == ENOTCONN) {
02960                     
02961                         // 6.0b2 dmb: this code isn't right. the listens keep succeeding, 
02962                         // chewing up resources until they're gone; accepts still fail
02963                         /*
02964                         if (listen (sock, 5) == SOCKET_ERROR) {
02965                         
02966                             neterror("setup listen stream", WSAGetLastError ());
02967                             
02968                             fwsNetEventCloseListen (listenstream);
02969                             //closesocket (sock);
02970                             }
02971                         */
02972                         }
02973                     sockstack[newstream].typeID = SOCKTYPE_INVALID;
02974                     }
02975                 }
02976             else if (res == SOCKET_ERROR) {
02977                 //The select on that socket had an error - What to do??
02978                 }
02979             }
02980         }
02981 
02982     return (fl);
02983     } /*fwsNetEventCheckAndAcceptSocket*/
02984 #endif
02985 #endif
02986 
02987 #ifdef WIN95VERSION
02988 boolean fwsNetEventAcceptSocket (WPARAM wParam, LPARAM lParam) {
02989 
02990     /*
02991     Process an accept pending message on a socket
02992     
02993     5.1.2 dmb: release thread globals on all errors
02994     */
02995 
02996 #ifdef ACCEPT_IN_SEPARATE_THREAD
02997 
02998     TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d. THIS FUNCTION IS NOT SUPPOSED TO BE CALLED!\n", __LINE__));
02999     TCPWRITEMSG();
03000 
03001     return (false);
03002 
03003 #else
03004 
03005     int sasize;
03006     struct sockaddr_in sa;
03007     SOCKET s, acceptsock;
03008     long err;
03009     boolean fl = false;
03010     long listenstream, newstream;
03011     long dummy = 0; /*need a pointer to nil for ioctlsocket call*/
03012     #ifndef ACCEPT_CONN_WITHOUT_GLOBALS
03013         bigstring bs;
03014     #endif
03015 
03016     s = (SOCKET) wParam;
03017 
03018     /*get listen stream*/
03019     if (!getsockrecord (s, &listenstream))
03020         goto exit;
03021 
03022     TCPTRACKERIN ("fwsNetEventAcceptSocket", __LINE__, listenstream);
03023 
03024     if (listenstream < 0)
03025         goto exit;
03026 
03027     if (sockstack[listenstream].typeID != SOCKTYPE_LISTENING) {
03028         /*something has happened to close this listen*/
03029         goto exit;
03030         }
03031 
03032     /*Check for error*/
03033 
03034     err = WSAGETSELECTERROR(lParam);
03035 
03036     if (err != 0) {
03037         /* if an error - pass this on to callback */
03038         #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03039             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));
03040             TCPWRITEMSG();
03041 
03042             fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
03043         #else
03044             parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
03045 
03046             TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  Error in accept message %s.\n", __LINE__, stringbaseaddress(bs)));
03047             TCPERRORWRITEMSG();
03048             
03049             fl = fwsrunstring (bs);
03050         #endif
03051 
03052         goto exit;
03053         }
03054     
03055     /*get socket record for accepted socket*/
03056     
03057     if (!addsockrecord (&newstream)) {
03058         /* if an error - pass this on to callback */
03059         long err = WSAEMFILE;
03060         
03061         #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03062             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));
03063             TCPWRITEMSG();
03064 
03065             fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
03066         #else
03067             parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
03068 
03069             TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  Error addding new socket record %s.\n", __LINE__, stringbaseaddress(bs)));
03070             TCPERRORWRITEMSG();
03071             
03072             fl = fwsrunstring (bs);
03073         #endif
03074 
03075         goto exit;
03076         }
03077 
03078     /*We do not want any more connection messages - at least if we've reached maximum listen depth*/
03079 
03080     if (!(sockstack[listenstream].currentListenDepth + 1 < sockstack[listenstream].maxdepth)) {
03081 
03082         sockstack[listenstream].flNotification = false;
03083 
03084         WSAAsyncSelect(s, shellframewindow, 0, 0);
03085         }
03086 
03087     /*Accept connection*/
03088 
03089     sasize = sizeof(sa);
03090     
03091     acceptsock = accept (s, (struct sockaddr *)&sa, &sasize);
03092 
03093     if (acceptsock != INVALID_SOCKET) {
03094 
03095     #ifdef PIKE
03096         if (incrementconnectioncounter ()) {
03097     #endif
03098             /*Switch child socket to blocking mode*/
03099             if (WSAAsyncSelect(acceptsock, shellframewindow, 0, 0) == SOCKET_ERROR) {
03100                 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  WSAAsyncSelect call failed: %ld.\n", __LINE__, WSAGetLastError ()));
03101                 TCPERRORWRITEMSG();
03102                 }
03103 
03104             if (ioctlsocket (acceptsock, FIONBIO, &dummy) == SOCKET_ERROR) {
03105                 TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  ioctlsocket call failed: %ld.\n", __LINE__, WSAGetLastError ()));
03106                 TCPERRORWRITEMSG();
03107                 }
03108 
03109             /*Increment listen depth*/
03110             ++sockstack[listenstream].currentListenDepth;
03111     
03112             /*Add Socket to list*/      
03113             sockstack[newstream].sockID = acceptsock;
03114             sockstack[newstream].typeID = SOCKTYPE_OPEN;
03115             sockstack[newstream].listenReference = listenstream;
03116             sockstack[newstream].refcon = 0;
03117 
03118             /*Pass "stream" and "refcon" to callback*/
03119 
03120             #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03121                 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));
03122                 TCPWRITEMSG();
03123 
03124                 fl = fwsruncallback (listenstream, newstream, sockstack[listenstream].refcon);
03125             #else
03126                 parsecallbackstring (listenstream, newstream, sockstack[listenstream].refcon, bs);
03127 
03128                 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)));
03129                 TCPWRITEMSG();
03130                 
03131                 fl = fwsrunstring (bs);
03132             #endif
03133 
03134     #ifdef PIKE
03135             }
03136         else {
03137 
03138             struct linger l;
03139 
03140             l.l_onoff = 1;
03141             l.l_linger = 0;
03142 
03143             TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  Exceeded number of maximum connections: %ld of %ld.\n", __LINE__, ctconnections, maxconnections));
03144             TCPERRORWRITEMSG();
03145 
03146             setsockopt (acceptsock, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l));
03147 
03148             fl = closesocket (acceptsock);
03149 
03150             sockstack[newstream].typeID = SOCKTYPE_INVALID;
03151             }
03152     #endif
03153 
03154         }
03155     else
03156         {
03157         /*if an error - pass this on to callback*/
03158         err = WSAGetLastError();
03159 
03160         #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03161             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));
03162             TCPWRITEMSG();
03163 
03164             fl = fwsruncallback (listenstream, err * -1L, sockstack[listenstream].refcon);
03165         #else
03166             parsecallbackstring (listenstream, err * -1L, sockstack[listenstream].refcon, bs);
03167 
03168             TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventAcceptSocket at line %d.  Error processing accept message %s.\n", __LINE__, stringbaseaddress(bs)));
03169             TCPERRORWRITEMSG();
03170             
03171             fl = fwsrunstring (bs);
03172         #endif
03173         
03174         sockstack[newstream].typeID = SOCKTYPE_INVALID;
03175         }
03176     
03177     restartAccepter (s, listenstream);
03178 
03179     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventAcceptSocket at line %d.  Return value is %s.\n", __LINE__, fl?"True":"False"));
03180     TCPWRITEMSG();
03181     
03182     exit:
03183 
03184     return (fl);
03185 #endif
03186     } /*fwsNetEventAcceptSocket*/
03187 #endif
03188 
03189 
03190 boolean fwsNetEventListenStream (unsigned long port, long depth, bigstring callback, unsigned long refcon, unsigned long * stream, unsigned long ipaddr, long hdatabase) {
03191 
03192     /* Set up a listner on a port */
03193 
03194     SOCKET sock;
03195     SOCKADDR_IN addr;
03196     int errcode;
03197     long streamref;
03198 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03199     Handle hcallbacktree = nil;
03200 #endif
03201     
03202     nullterminate (callback);
03203     TCPprintf(wsprintf(TCPmsg, "Entering fwsNetEventListenStream at line %d. Port = %ld, Depth = %ld, Refcon = %ld, Callback = %s.\n", __LINE__, port, depth, refcon, stringbaseaddress(callback)));
03204     TCPWRITEMSG ();
03205 
03206     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03207         return (false);
03208 
03209     if (!addsockrecord (&streamref)) {
03210         neterror ("initialize listen stream", WSAEMFILE); /*Too many open sockets*/
03211         return (false);
03212         }       
03213 
03214 #ifdef ACCEPT_CONN_WITHOUT_GLOBALS
03215     if (!fwsgetcallbackcodetree (callback, &hcallbacktree))
03216         return (false);
03217 #endif
03218 
03219     releasethreadglobalsnopriority();
03220 
03221     sock = socket(PF_INET, SOCK_STREAM, 0);
03222 
03223     TCPprintf (wsprintf(TCPmsg, "In fwsNetEventListenStream at line %d.  socket call result is sock = %ld.\n", __LINE__, (long)sock));
03224     TCPWRITEMSG ();
03225 
03226     if (sock == INVALID_SOCKET) {
03227         errcode = WSAGetLastError ();
03228         grabthreadglobalsnopriority();
03229         neterror("create listen stream", errcode);
03230         sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
03231         disposehandle (hcallbacktree);
03232         return (false);
03233         }
03234 
03235     addr.sin_family = AF_INET;
03236     addr.sin_addr.s_addr = htonl(ipaddr);
03237     addr.sin_port = htons((unsigned short) port);
03238 
03239     if (bind(sock, (LPSOCKADDR)&addr, sizeof (addr)) == SOCKET_ERROR) {
03240         errcode = WSAGetLastError ();
03241         grabthreadglobalsnopriority();
03242         neterror("bind listen stream", errcode);
03243         closesocket (sock);
03244         sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
03245         disposehandle (hcallbacktree);
03246         return (false);
03247         } 
03248 
03249     if (listen (sock, SOMAXCONN) == SOCKET_ERROR) {
03250         errcode = WSAGetLastError ();
03251         grabthreadglobalsnopriority();
03252         neterror("setup listen stream", errcode);
03253         closesocket (sock);
03254         sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
03255         disposehandle (hcallbacktree);
03256         return (false);
03257         }
03258 
03259     grabthreadglobalsnopriority();
03260     
03261     sockstack[streamref].refcon = refcon;
03262 
03263     sockstack[streamref].sockID = sock;
03264 
03265     sockstack[streamref].typeID = SOCKTYPE_LISTENING;
03266 
03267     copystring (callback, sockstack[streamref].callback);
03268 
03269     sockstack[streamref].maxdepth = depth;
03270 
03271     sockstack[streamref].listenReference = 0; //6.2a14 AR: was refcon, but probably doesn't make a difference (yet!)
03272 
03273     sockstack[streamref].currentListenDepth = 0;
03274     
03275     sockstack[streamref].hcallbacktree = hcallbacktree;
03276     
03277 
03278     *stream = streamref;
03279 
03280     #ifdef MACVERSION
03281         sockListenList[sockListenCount++] = *stream;
03282     #endif
03283 
03284     #ifdef ACCEPT_IN_SEPARATE_THREAD
03285         sockstack[streamref].hdatabase = (hdldatabaserecord) hdatabase; /*hdldatabaserecord of the db that contains the daemon script*/
03286 
03287         if (!fwslaunchacceptingthread (streamref)) {
03288             closesocket (sock);
03289             sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
03290             disposehandle (hcallbacktree);
03291             return (false);
03292             }
03293     #else
03294         #ifdef WIN95VERSION
03295             releasethreadglobalsnopriority();
03296 
03297             if (WSAAsyncSelect (sock, shellframewindow, wm_processAccept, FD_ACCEPT) == SOCKET_ERROR) {
03298             /* Our interest in this has failed */
03299                 errcode = WSAGetLastError ();
03300                 grabthreadglobalsnopriority();
03301                 neterror("setup listen stream", errcode);
03302                 closesocket (sock);
03303                 sockstack[streamref].typeID = SOCKTYPE_INACTIVE;
03304                 disposehandle (hcallbacktree);
03305                 return (false);
03306                 }
03307 
03308             sockstack[stream].flNotification = true;
03309             
03310             grabthreadglobalsnopriority();
03311         #endif
03312     #endif
03313 
03314     TCPTRACKEROUT ("fwsNetEventListenStream", __LINE__, *stream);
03315     return (true);
03316 
03317     } /*fwsNetEventListenStream*/
03318 
03319 
03320 boolean fwsNetEventStatusStream (unsigned long stream, bigstring status, unsigned long * bytesPending) {
03321 
03322     /* get the status of a stream */
03323 
03324     int res;
03325     SOCKET sock;
03326     fd_set readset;
03327     struct timeval tv;
03328 //  struct hostData hostdata;
03329 
03330 //#if (TCPTRACKER == 1)
03331     if (!inmainthread())
03332         TCPTRACKERIN ("fwsNetEventStatusStream", __LINE__, stream);
03333 //#endif
03334 
03335     *bytesPending = 0;
03336 
03337     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03338         return (false);
03339 
03340     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03341         intneterror (INTNETERROR_INVALIDSTREAM);
03342         return (false);
03343         }
03344 
03345     sock = sockstack[stream].sockID;
03346 
03347     switch (sockstack[stream].typeID) {
03348         case SOCKTYPE_INVALID:
03349             intneterror(INTNETERROR_INVALIDSTREAM);
03350             copyctopstring ("INACTIVE", status);
03351             return (false);
03352 
03353         case SOCKTYPE_UNKNOWN:
03354             copyctopstring ("UNKNOWN", status);
03355             break;
03356 
03357         case SOCKTYPE_OPEN:
03358             copyctopstring ("OPEN", status);
03359 
03360             tv.tv_sec = 0;
03361             tv.tv_usec = 0;
03362 
03363             FD_ZERO (&readset);
03364 
03365             FD_SET(sock, &readset);
03366 
03367             /* now check for data */
03368 
03369             res = select (sock+1, &readset, NULL, NULL, &tv);
03370 
03371             if (res == SOCKET_ERROR) {
03372                 neterror("check status on stream", WSAGetLastError ());
03373                     copyctopstring ("INACTIVE", status);
03374                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03375                 return (false);
03376                 }
03377 
03378             if (res == 1) {  /*this means that the socket we sent has data */
03379                 res = ioctlsocket (sock, FIONREAD, bytesPending);
03380 
03381                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventStatusStream at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, *bytesPending));
03382                 TCPWRITEMSG ();
03383 
03384                 if (res == SOCKET_ERROR) {
03385                     neterror("check status on stream", WSAGetLastError ());
03386                     copyctopstring ("INACTIVE", status);
03387                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03388                     return (false);
03389                     }
03390 
03391                 if (*bytesPending == 0)
03392                     {
03393                     copyctopstring ("INACTIVE", status);
03394 
03395                     /* this condition means that the virtual socket has been closed */
03396 
03397                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03398                     }
03399                 else
03400                     copyctopstring ("DATA", status);
03401                 }
03402 
03403             break;
03404 
03405         case SOCKTYPE_LISTENING:
03406             copyctopstring ("LISTENING", status);
03407             break;
03408 
03409         case SOCKTYPE_CLOSED:
03410             copyctopstring ("CLOSED", status);
03411             break;
03412 
03413         case SOCKTYPE_LISTENSTOPPED:
03414             copyctopstring ("STOPPED", status);
03415             break;
03416 
03417         case SOCKTYPE_INACTIVE:
03418             copyctopstring ("INACTIVE", status);
03419             break;
03420 
03421         default:
03422             copyctopstring ("UNKNOWN", status);
03423             break;
03424         }
03425 
03426     nullterminate (status);
03427 
03428 //#if (TCPTRACKER == 1)
03429     if (!inmainthread()) {
03430         TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventStatusStream at line %d, result is %s with bytes pending %ld.\n", __LINE__, stringbaseaddress(status), *bytesPending));
03431         TCPWRITEMSG ();
03432         }
03433 //#endif
03434 
03435     return (true);
03436     } /*fwsNetEventStatusStream*/
03437 
03438 
03439 boolean fwsNetEventGetPeerAddress (unsigned long stream, unsigned long * peeraddress, unsigned long * peerport) {
03440     SOCKADDR_IN sockAddr;
03441     SOCKET sock;
03442     int nSockAddrLen;
03443     int res;
03444 
03445     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03446         intneterror (INTNETERROR_INVALIDSTREAM);
03447         return (false);
03448         }
03449     
03450     TCPTRACKERIN ("fwsNetEventGetPeerAddress", __LINE__, stream);
03451 
03452     sock = sockstack[stream].sockID;
03453     
03454     memset(&sockAddr, 0, sizeof(sockAddr));
03455 
03456     nSockAddrLen = sizeof(sockAddr);
03457 
03458     res = getpeername(sock, (SOCKADDR*)&sockAddr, &nSockAddrLen);
03459 
03460     if (res == SOCKET_ERROR) {
03461         neterror("get peer address", WSAGetLastError());
03462         return (false);
03463         }
03464 
03465     *peerport = (unsigned long) ntohs(sockAddr.sin_port);
03466     *peeraddress = ntohl(sockAddr.sin_addr.s_addr);
03467 
03468     TCPTRACKEROUT ("fwsNetEventGetPeerAddress", __LINE__, stream);
03469 
03470     return (true);
03471     } /*fwsNetEventGetPeerAddress*/
03472 
03473 
03474 boolean fwsNetEventReadStreamUntil (unsigned long stream, Handle hbuffer, Handle hpattern, unsigned long timeoutsecs) {
03475 
03476     /*
03477     6.1d1 AR: Read from a stream appending to hbuffer until hpattern is found.
03478 
03479     6.1d13 AR: Only grab globals when growing the handle (for proper out of memory errors).
03480 
03481     6.1b9 AR: Check the whole buffer for the pattern -- not only the part we read.
03482     */
03483 
03484     SOCKET sock;
03485     fd_set readset;
03486     struct timeval tv;
03487     int res, errcode;
03488     long ix = gethandlesize (hbuffer);
03489     long ixstart = ix;
03490     unsigned long bytes;
03491 
03492     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03493         return (false);
03494 
03495     TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, stream);
03496 
03497     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03498         intneterror (INTNETERROR_INVALIDSTREAM);
03499         return (false);
03500         }
03501 
03502     sock = sockstack[stream].sockID;
03503 
03504     if (sock == INVALID_SOCKET) {
03505         neterror ("read stream", WSAENOTSOCK);
03506         return (false);
03507         }
03508 
03509     releasethreadglobalsnopriority();
03510 
03511     tv.tv_sec = timeoutsecs;
03512     tv.tv_usec = 0;
03513 
03514     FD_ZERO (&readset);
03515 
03516     FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
03517                              doing this just once should be totally safe.*/
03518 
03519     while (searchhandle (hbuffer, hpattern, 0, ix) == -1L) {
03520 
03521         res = select (sock+1, &readset, NULL, NULL, &tv);
03522 
03523         switch (res) {
03524 
03525             case 1:  /*this means that the socket has data */
03526                 res = ioctlsocket (sock, FIONREAD, &bytes);
03527 
03528                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
03529                 TCPWRITEMSG ();
03530 
03531                 if (res == SOCKET_ERROR) {
03532                     errcode = WSAGetLastError ();
03533                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03534                     goto exit;
03535                     }
03536 
03537                 if (bytes == 0) { /*closed prematurely*/
03538                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03539                     goto error_closedprematurely;
03540                     }
03541                                 
03542                 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
03543 
03544                 if (!sethandlesize (hbuffer, ix + bytes))
03545                     return (false); /*we have the thread globals, so we can return immediately*/
03546                 
03547                 releasethreadglobalsnopriority();
03548 
03549                 lockhandle (hbuffer);
03550 
03551                 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
03552                 
03553                 unlockhandle (hbuffer);
03554                 
03555                 if (res == SOCKET_ERROR) {
03556                     errcode = WSAGetLastError ();
03557                     goto exit;
03558                     }
03559                                 
03560                 ix += res;
03561 
03562                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntil at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
03563                 TCPWRITEMSG ();
03564 
03565                 break;
03566         
03567             case 0: /*select timed out*/
03568                 errcode = WSAETIMEDOUT;
03569                 goto exit;
03570 
03571             case SOCKET_ERROR:
03572                 errcode = WSAGetLastError ();
03573                 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03574                 goto exit;
03575 
03576             default:
03577                 errcode = -1; /* should never happen*/
03578                 goto exit;
03579             }
03580         }
03581 
03582     grabthreadglobalsnopriority();
03583 
03584     if (!sethandlesize (hbuffer, ix))
03585         return (false);
03586 
03587     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntil at line %d.  Total bytes read = %ld.\n", __LINE__, ix - ixstart));
03588     TCPWRITEMSG ();
03589 
03590     return (true);
03591 
03592 exit:
03593     grabthreadglobalsnopriority();
03594 
03595     if (!sethandlesize (hbuffer, ix))
03596         return (false);
03597 
03598     neterror ("read stream", errcode);
03599 
03600     return (false);
03601 
03602 error_closedprematurely:
03603     grabthreadglobalsnopriority();
03604 
03605     if (!sethandlesize (hbuffer, ix))
03606         return (false);
03607 
03608     plainneterror (STR_P_ERROR_CLOSED_PREMATURELY);
03609 
03610     return (false);
03611     } /*fwsNetEventReadStreamUntil*/
03612 
03613 
03614 
03615 boolean fwsNetEventReadStreamUntilClosed (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
03616 
03617     /*
03618     6.1b15 AR: Branched from fwsNetEventReadStreamUntil. Don't look for a pattern, just read until closed.
03619     */
03620 
03621     SOCKET sock;
03622     fd_set readset;
03623     struct timeval tv;
03624     int res, errcode;
03625     long ix = gethandlesize (hbuffer);
03626     long ixstart = ix;
03627     unsigned long bytes;
03628 
03629     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03630         return (false);
03631 
03632     TCPTRACKERIN ("fwsNetEventReadStreamUntil", __LINE__, stream);
03633 
03634     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03635         intneterror (INTNETERROR_INVALIDSTREAM);
03636         return (false);
03637         }
03638 
03639     sock = sockstack[stream].sockID;
03640 
03641     if (sock == INVALID_SOCKET) {
03642         neterror ("read stream", WSAENOTSOCK);
03643         return (false);
03644         }
03645 
03646     releasethreadglobalsnopriority();
03647 
03648     tv.tv_sec = timeoutsecs;
03649     tv.tv_usec = 0;
03650 
03651     FD_ZERO (&readset);
03652 
03653     FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
03654                              doing this just once should be totally safe.*/
03655 
03656     while (true) {
03657 
03658         res = select (sock+1, &readset, NULL, NULL, &tv);
03659 
03660         switch (res) {
03661 
03662             case 1:  /*this means that the socket has data */
03663                 res = ioctlsocket (sock, FIONREAD, &bytes);
03664 
03665                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
03666                 TCPWRITEMSG ();
03667 
03668                 if (res == SOCKET_ERROR) {
03669                     errcode = WSAGetLastError ();
03670                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03671                     goto exit;
03672                     }
03673 
03674                 if (bytes == 0) { /*we're done*/
03675                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03676                     goto done;
03677                     }
03678                                 
03679                 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
03680 
03681                 if (!sethandlesize (hbuffer, ix + bytes))
03682                     return (false); /*we have the thread globals, so we can return immediately*/
03683                 
03684                 releasethreadglobalsnopriority();
03685 
03686                 lockhandle (hbuffer);
03687 
03688                 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
03689                 
03690                 unlockhandle (hbuffer);
03691                 
03692                 if (res == SOCKET_ERROR) {
03693                     errcode = WSAGetLastError ();
03694                     goto exit;
03695                     }
03696                                 
03697                 ix += res;
03698 
03699                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamUntilClosed at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
03700                 TCPWRITEMSG ();
03701 
03702                 break;
03703         
03704             case 0: /*select timed out*/
03705                 errcode = WSAETIMEDOUT;
03706                 goto exit;
03707 
03708             case SOCKET_ERROR:
03709                 errcode = WSAGetLastError ();
03710                 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03711                 goto exit;
03712 
03713             default:
03714                 errcode = -1; /* should never happen*/
03715                 goto exit;
03716             }
03717         }
03718 
03719 done:
03720     grabthreadglobalsnopriority();
03721 
03722     if (!sethandlesize (hbuffer, ix))
03723         return (false);
03724 
03725     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamUntilClosed at line %d.  Total bytes read = %ld.\n", __LINE__, ix - ixstart));
03726     TCPWRITEMSG ();
03727 
03728     return (true);
03729 
03730 exit:
03731     grabthreadglobalsnopriority();
03732 
03733     if (!sethandlesize (hbuffer, ix))
03734         return (false);
03735 
03736     neterror ("read stream", errcode);
03737 
03738     return (false);
03739     }/*fwsNetEventReadStreamUntilClosed*/
03740 
03741 
03742 boolean fwsNetEventReadStreamBytes (unsigned long stream, Handle hbuffer, long ctbytes, unsigned long timeoutsecs) {
03743 
03744     /*
03745     6.1d1 AR: Read the specified number of bytes from the stream appending to hbuffer.
03746     
03747     6.1b9 AR: ctbytes applies to the whole buffer -- not only the part we read.
03748     */
03749 
03750     SOCKET sock;
03751     fd_set readset;
03752     struct timeval tv;
03753     int res;
03754     long lenbuffer = gethandlesize (hbuffer);
03755     long ix = lenbuffer;
03756     long bytes;
03757     long errcode;
03758 
03759     if (ctbytes <= lenbuffer) /*6.1b8 AR: don't do anything*/
03760         return (true);
03761 
03762     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03763         return (false);
03764 
03765     TCPTRACKERIN ("fwsNetEventReadStreamBytes", __LINE__, stream);
03766 
03767     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03768         intneterror (INTNETERROR_INVALIDSTREAM);
03769         return (false);
03770         }
03771 
03772     if (!sethandlesize (hbuffer, ctbytes)) //make enough room in one go
03773         return (false);
03774                 
03775     sock = sockstack[stream].sockID;
03776 
03777     if (sock == INVALID_SOCKET) {
03778         neterror ("read stream", WSAENOTSOCK);
03779         return (false);
03780         }
03781 
03782     releasethreadglobalsnopriority();   //from now on, don't touch lang globals before
03783                                         //having called grabthreadglobalsnopriority
03784     tv.tv_sec = timeoutsecs;
03785     tv.tv_usec = 0;
03786 
03787     FD_ZERO (&readset);
03788 
03789     FD_SET (sock, &readset);
03790 
03791     lockhandle (hbuffer);
03792 
03793     while (ix < ctbytes) {
03794 
03795         res = select (sock+1, &readset, NULL, NULL, &tv);
03796 
03797         switch (res) {
03798 
03799             case 1:  /*this means that the socket has data */
03800                 res = ioctlsocket (sock, FIONREAD, &bytes);
03801 
03802                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
03803                 TCPWRITEMSG ();
03804 
03805                 if (res == SOCKET_ERROR) {
03806                     errcode = WSAGetLastError ();
03807                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03808                     goto exit;
03809                     }
03810 
03811                 if (bytes == 0) { /*closed prematurely*/
03812                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03813                     goto error_closedprematurely;
03814                     }
03815                                 
03816                 if (bytes > (ctbytes - ix)) /* Don't read more than ctbytes */
03817                     bytes = ctbytes - ix;               
03818                 
03819                 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
03820                 
03821                 if (res == SOCKET_ERROR) { /* might be WSAEMSGSIZE if we read less data than is available? */
03822                     errcode = WSAGetLastError ();
03823                     goto exit;
03824                     }
03825                 
03826                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventReadStreamBytes at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
03827                 TCPWRITEMSG ();
03828 
03829                 ix += res;
03830 
03831                 break;
03832         
03833             case 0: /*select timed out*/
03834                 errcode = WSAETIMEDOUT;
03835                 goto exit;
03836 
03837             case SOCKET_ERROR:
03838                 errcode = WSAGetLastError ();
03839                 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03840                 goto exit;
03841 
03842             default:
03843                 errcode = -1;
03844                 //assert (false);
03845                 goto exit;
03846             }
03847         }
03848 
03849     grabthreadglobalsnopriority();
03850 
03851     unlockhandle (hbuffer);
03852 
03853     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventReadStreamBytes at line %d.  Total bytes requested = %ld, bytes read = %ld.\n", __LINE__, ctbytes, ix));
03854     TCPWRITEMSG ();
03855     
03856     return (true);
03857 
03858 exit:
03859     grabthreadglobalsnopriority();
03860 
03861     neterror("read stream", errcode);
03862 
03863     unlockhandle (hbuffer);
03864 
03865     sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
03866 
03867     return (false);
03868 
03869 error_closedprematurely:
03870     grabthreadglobalsnopriority();
03871 
03872     plainneterror (STR_P_ERROR_CLOSED_PREMATURELY);
03873 
03874     unlockhandle (hbuffer);
03875 
03876     sethandlesize (hbuffer, ix); /*shrinking, can't fail*/
03877 
03878     return (false);
03879     } /*fwsNetEventReadStreamBytes*/
03880 
03881 
03882 boolean fwsNetEventWriteHandleToStream (unsigned long stream, Handle hbuffer, unsigned long chunksize, unsigned long timeoutsecs) {
03883 
03884     /* Write to stream in chunks */
03885 
03886     SOCKET sock;
03887     fd_set writeset;
03888     struct timeval tv;
03889     int res;
03890     long ix = 0;
03891     unsigned long bytesremaining = gethandlesize (hbuffer);
03892     long bytestowrite;
03893     long errcode;
03894 
03895     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
03896         return (false);
03897 
03898     TCPTRACKERIN ("fwsNetEventWriteHandleToStream", __LINE__, stream);
03899 
03900     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
03901         intneterror (INTNETERROR_INVALIDSTREAM);
03902         return (false);
03903         }
03904 
03905     sock = sockstack[stream].sockID;
03906 
03907     if (sock == INVALID_SOCKET) {
03908         neterror ("write stream", WSAENOTSOCK);
03909         return (false);
03910         }
03911 
03912     tv.tv_sec = timeoutsecs;
03913     tv.tv_usec = 0;
03914 
03915     FD_ZERO (&writeset);
03916 
03917     FD_SET (sock, &writeset);
03918 
03919     lockhandle (hbuffer);
03920 
03921     releasethreadglobalsnopriority();   //from now on, don't touch lang globals before
03922                                         //having called grabthreadglobalsnopriority
03923     do {
03924 
03925         res = select (sock+1, NULL, &writeset, NULL, &tv);
03926 
03927         switch (res) {
03928 
03929             case 1:  /*this means that we can write to the socket */
03930                 bytestowrite = (bytesremaining < chunksize) ? bytesremaining : chunksize;
03931 
03932                 res = send (sock, &((*hbuffer) [ix]), bytestowrite, 0);
03933                 
03934                 if (res == SOCKET_ERROR) {
03935                 
03936                     errcode = WSAGetLastError ();
03937 
03938                     #ifdef WIN95VERSION
03939                         if (errcode == WSAEWOULDBLOCK) { /*work around winsock bug on win95/win98*/
03940                         
03941                             unsigned long timewait = gettickcount() + (60L * 15L); /*max of 15 seconds*/
03942                             
03943                             while (timewait > gettickcount ()) {
03944 
03945                                 Sleep (100L); /*wait six ticks (100 milliseconds) and try again*/
03946 
03947                                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d.  Attempting to re-send on stream: %d.\n", __LINE__, stream));
03948                                 TCPWRITEMSG();
03949                                 
03950                                 res = send (sock, &((*hbuffer) [ix]), bytestowrite, 0);
03951                                 
03952                                 if (res == SOCKET_ERROR) {
03953                                     errcode = WSAGetLastError ();
03954                                     
03955                                     if (errcode != WSAEWOULDBLOCK) {
03956                                     
03957                                         TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d.  Error re-sending on stream: %d.\n", __LINE__, stream));
03958                                         TCPERRORWRITEMSG();
03959                                         
03960                                         goto exit; /*terminate attempts to send data and throw a script error*/
03961                                         }
03962                                     }
03963                                 else
03964                                     goto continue_send;
03965                                 }/*while*/
03966                             }
03967                             
03968                         TCPERRORprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d.  Gave up re-sending on stream: %d.\n", __LINE__, stream));
03969                         TCPERRORWRITEMSG();
03970                     #endif
03971 
03972                     goto exit; /*unconditionally throw a script error*/
03973                     }
03974                     
03975             continue_send:
03976 
03977                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventWriteHandleToStream at line %d, requested writing %ld bytes, wrote %ld bytes.\n", __LINE__, bytestowrite, res));
03978                 TCPWRITEMSG ();
03979 
03980                 bytesremaining -= res;
03981                 
03982                 ix += res;
03983                 
03984                 break;
03985         
03986             case 0: /*select timed out*/
03987                 errcode = WSAETIMEDOUT;
03988                 goto exit;
03989 
03990             case SOCKET_ERROR:
03991                 errcode = WSAGetLastError ();
03992                 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
03993                 goto exit;
03994 
03995             default: /*should never happen*/
03996                 errcode = -1;
03997                 //assert (false);
03998                 goto exit;
03999             }
04000     } while (bytesremaining > 0);
04001 
04002     grabthreadglobalsnopriority();
04003     
04004     unlockhandle (hbuffer);
04005 
04006     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteHandleToStream at line %d.  Total bytes written = %ld.\n", __LINE__, ix));
04007     TCPWRITEMSG ();
04008 
04009     return (true);
04010 
04011 exit:
04012     grabthreadglobalsnopriority();
04013 
04014     neterror("write stream", errcode);
04015 
04016     unlockhandle (hbuffer);
04017 
04018     return (false);
04019     } /*fwsNetEventWriteHandleToStream*/
04020 
04021 
04022 //#if 0
04023 
04024 static boolean fwstransmitfile (unsigned long stream, ptrfilespec fs) {
04025 
04026     char *buffer;
04027     static const long kFileBufferSize = 32767L;
04028     boolean fl = false;
04029     hdlfilenum fnum;
04030     long ctread = 0;
04031     long ix = 0;
04032 
04033     /* open file */
04034 
04035     if (!openfile (fs, &fnum, true))
04036         return (false);
04037 
04038     /* allocate buffer */
04039 
04040     buffer = malloc (kFileBufferSize);
04041 
04042     if (buffer == nil) {
04043         memoryerror ();
04044         goto exit;
04045         }
04046         
04047     while (true) {
04048 
04049         /* read from file */
04050         
04051         if (!filesetposition (fnum, ix))
04052             goto exit;
04053 
04054         if (!filereaddata (fnum, kFileBufferSize, &ctread, buffer))
04055             goto exit;
04056 
04057         if (ctread == 0) {
04058             fl = true;
04059             goto exit;
04060             }
04061         
04062         ix += ctread;
04063 
04064         /* write to stream */
04065 
04066         if(!fwsNetEventWriteStream (stream, ctread, buffer))
04067             goto exit;
04068         }
04069 
04070 exit:
04071     /* free buffer */
04072 
04073     if (buffer != nil)
04074         free (buffer);
04075 
04076     /* close file */
04077 
04078     fl = closefile (fnum);
04079 
04080     return (fl);
04081     }/*fwstransmitfile*/
04082 
04083 
04084 boolean fwsNetEventWriteFileToStream (unsigned long stream, Handle hprefix, Handle hsuffix, ptrfilespec fs) {
04085 
04086     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04087         return (false);
04088 
04089     TCPTRACKERIN ("fwsNetEventWriteFileToStream", __LINE__, stream);
04090 
04091 #ifdef WIN95VERSION
04092 
04093     if (adrTransmitFile != nil) {
04094 
04095         SOCKET sock;
04096         boolean fl;
04097         long errcode = 0;
04098         TRANSMIT_FILE_BUFFERS transmitbuffers;
04099         HANDLE hfile = INVALID_HANDLE_VALUE;
04100         char fn[300];
04101 
04102         if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
04103             intneterror (INTNETERROR_INVALIDSTREAM);
04104             return (false);
04105             }
04106 
04107         sock = sockstack[stream].sockID;    
04108 
04109         /* open file */
04110 
04111         copyptocstring (fsname (fs), fn);
04112 
04113         hfile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ,
04114             NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
04115  
04116         if (hfile == INVALID_HANDLE_VALUE) {
04117 
04118             oserror (GetLastError ());
04119             
04120             return (false);
04121             }
04122 
04123         /* set up transmit buffers */
04124 
04125         if (hprefix != nil) {
04126 
04127             lockhandle (hprefix);
04128 
04129             transmitbuffers.HeadLength = gethandlesize (hprefix);
04130 
04131             transmitbuffers.Head = (void *) *hprefix;
04132             }
04133         else {
04134             transmitbuffers.HeadLength = nil;
04135 
04136             transmitbuffers.Head = nil;
04137             }
04138 
04139         
04140         if (hsuffix != nil) {
04141 
04142             lockhandle (hsuffix);
04143 
04144             transmitbuffers.TailLength = gethandlesize (hsuffix);
04145 
04146             transmitbuffers.Tail = (void *) *hsuffix;
04147             }
04148         else {
04149             transmitbuffers.TailLength = nil;
04150 
04151             transmitbuffers.Tail = nil;
04152             }
04153 
04154         /* kernel call */
04155 
04156         releasethreadglobalsnopriority ();
04157 
04158         fl = adrTransmitFile (sock, hfile, nil, nil, nil, &transmitbuffers, TF_WRITE_BEHIND);
04159         
04160         if (!fl)
04161             errcode = GetLastError ();
04162 
04163         grabthreadglobalsnopriority ();
04164 
04165         /* clean up */
04166         
04167         if (hprefix != nil)
04168             unlockhandle (hprefix);
04169 
04170         if (hsuffix != nil)
04171             unlockhandle (hsuffix);
04172 
04173         if (!fl) {
04174 
04175             neterror ("write file to stream", errcode);
04176             
04177             return (false);
04178             }
04179 
04180         TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__));
04181         TCPWRITEMSG ();
04182 
04183         return (true);
04184         }
04185 
04186 #endif /*WIN95VERSION*/
04187 
04188     if (hprefix != nil) {
04189         boolean fl;
04190 
04191         lockhandle (hprefix);
04192 
04193         fl = fwsNetEventWriteStream (stream, gethandlesize (hprefix), *hprefix);
04194 
04195         unlockhandle (hprefix);
04196 
04197         if (!fl)
04198             return (false);
04199         }
04200 
04201     if (!fwstransmitfile (stream, fs))
04202         return (false);
04203 
04204     if (hsuffix != nil) {
04205         boolean fl;
04206 
04207         lockhandle (hsuffix);
04208 
04209         fl = fwsNetEventWriteStream (stream, gethandlesize (hsuffix), *hsuffix);
04210 
04211         unlockhandle (hsuffix);
04212 
04213         if (!fl)
04214             return (false);
04215         }
04216 
04217     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventWriteFileToStream at line %d.\n", __LINE__));
04218     TCPWRITEMSG ();
04219 
04220     return (true); 
04221     } /*fwsNetEventWriteFileToStream*/
04222 
04223 //#endif
04224 
04225 /*
04226 loop { //wait for data to read
04227     status = tcp.statusStream (stream, @bytespending);
04228     if (bytespending > 0) and (status == "DATA") {
04229         paramTable.request = paramTable.request + tcp.readStream (stream, bytespending);
04230         tcTimeout = clock.ticks () + 30}; //Now give only 1/2 second to get more data
04231     if status == "CLOSED" {
04232         break};
04233     if status == "INACTIVE" {
04234         break};
04235     if clock.ticks () > tcTimeout {
04236         break};
04237     if status == "OPEN" {
04238         sys.systemTask (); //yield a little within this thread for the system
04239         thread.sleepfor (1)}}} //yield this thread for a second to allow normal Frontier processing
04240 */
04241 
04242 
04243 boolean fwsNetEventInetdRead (unsigned long stream, Handle hbuffer, unsigned long timeoutsecs) {
04244 
04245     /*
04246     6.1b2 AR: Wait timeoutsecs seconds for data to come in. After the first packed has been
04247     received, continue reading with a reduced timeout of 1 second. (For historical reasons.)
04248     */
04249 
04250     SOCKET sock;
04251     fd_set readset;
04252     struct timeval tv;
04253     int res, errcode;
04254     long ix = gethandlesize (hbuffer);
04255     long ixstart = ix;
04256     unsigned long bytes;
04257 
04258     if (!fwsNetEventLaunch (NO_HOST_SERVICES))
04259         return (false);
04260 
04261     TCPTRACKERIN ("fwsNetEventInetdRead", __LINE__, stream);
04262 
04263     if ((stream < 1) || (stream >= FRONTIER_MAX_STREAM)) {
04264         intneterror (INTNETERROR_INVALIDSTREAM);
04265         return (false);
04266         }
04267 
04268     sock = sockstack[stream].sockID;
04269 
04270     if (sock == INVALID_SOCKET) {
04271         neterror ("read stream", WSAENOTSOCK);
04272         return (false);
04273         }
04274 
04275     releasethreadglobalsnopriority();
04276 
04277     tv.tv_sec = timeoutsecs;
04278     tv.tv_usec = 0;
04279 
04280     FD_ZERO (&readset);
04281 
04282     FD_SET (sock, &readset); /*as long as we're dealing with a single socket,
04283                              doing this just once should be totally safe.*/
04284     while (true) {
04285 
04286         res = select (sock+1, &readset, NULL, NULL, &tv);
04287 
04288         switch (res) {
04289 
04290             case 1:  /*this means that the socket has data */
04291                 res = ioctlsocket (sock, FIONREAD, &bytes);
04292 
04293                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, ioctlsocket returned %ld with the number of bytes pending as %ld.\n", __LINE__, res, bytes));
04294                 TCPWRITEMSG ();
04295 
04296                 if (res == SOCKET_ERROR) {
04297                     errcode = WSAGetLastError ();
04298                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
04299                     goto exit;
04300                     }
04301 
04302                 if (bytes == 0) { /*closed prematurely*/
04303                     sockstack[stream].typeID = SOCKTYPE_INACTIVE;
04304                     goto done; /*not an error in this case*/
04305                     }
04306                                 
04307                 grabthreadglobalsnopriority(); /*we need the globals because sethandlesize might throw an error*/
04308 
04309                 if (!sethandlesize (hbuffer, ix + bytes))
04310                     return (false); /*we have the thread globals, so we can return immediately*/
04311                 
04312                 releasethreadglobalsnopriority();
04313 
04314                 lockhandle (hbuffer);
04315 
04316                 res = recv (sock, &((*hbuffer) [ix]), bytes, 0);
04317                 
04318                 unlockhandle (hbuffer);
04319                 
04320                 if (res == SOCKET_ERROR) {
04321                     errcode = WSAGetLastError ();
04322                     goto exit;
04323                     }
04324                                 
04325                 ix += res;
04326                 
04327                 tv.tv_sec = 1; /*reduce timeout to one second after the first packet has been received*/
04328 
04329                 TCPprintf (wsprintf(TCPmsg, "In fwsNetEventInetdRead at line %d, requested reading %ld bytes, read %ld bytes.\n", __LINE__, bytes, res));
04330                 TCPWRITEMSG ();
04331 
04332                 break;
04333         
04334             case 0: /*select timed out*/
04335                 goto done; /*not an error in this case*/
04336 
04337             case SOCKET_ERROR:
04338                 errcode = WSAGetLastError ();
04339                 sockstack[stream].typeID = SOCKTYPE_INACTIVE;
04340                 goto exit;
04341 
04342             default:
04343                 errcode = -1; /* should never happen*/
04344                 goto exit;
04345             }
04346         }/*while*/
04347 
04348 done:
04349     grabthreadglobalsnopriority();
04350 
04351     if (!sethandlesize (hbuffer, ix))
04352         return (false);
04353 
04354     TCPprintf (wsprintf(TCPmsg, "Exiting fwsNetEventInetdRead at line %d.  Total bytes read = %ld.\n", __LINE__, ix - ixstart));
04355     TCPWRITEMSG ();
04356 
04357     return (true);
04358 
04359 exit:
04360     grabthreadglobalsnopriority();
04361 
04362     neterror ("read stream", errcode);
04363 
04364     return (false);
04365     } /*fwsNetEventInetdRead*/
04366 
04367 
04368 boolean fwsNetEventGetStats (unsigned long stream, bigstring bs) {
04369     
04370     unsigned long ctopen = 0;
04371     unsigned long ctdata = 0;
04372     unsigned long ctclosed = 0;
04373     unsigned long ctinactive = 0;
04374     unsigned long i;
04375     
04376     setemptystring (bs);
04377     
04378     for (i = 1; i <= FRONTIER_MAX_STREAM; i++) {
04379         
04380         if (sockstack[i].listenReference == (long) stream) {
04381             
04382             switch (sockstack[i].typeID) {
04383                     
04384                 case SOCKTYPE_OPEN:
04385                     ctopen++;
04386                     break;
04387                     
04388                 case SOCKTYPE_DATA:
04389                     ctdata++;
04390                     break;
04391                     
04392                 case SOCKTYPE_CLOSED:
04393                     ctclosed++;
04394                     break;
04395                     
04396                 case SOCKTYPE_INACTIVE:
04397                     ctinactive++;
04398                     break;
04399                 }/*switch*/
04400             }
04401         }/*for*/
04402 
04403     pushlong (ctopen, bs);
04404 
04405     pushchar (',', bs);
04406 
04407     pushlong (ctdata, bs);
04408 
04409     pushchar (',', bs);
04410 
04411     pushlong (ctclosed, bs);
04412 
04413     pushchar (',', bs);
04414 
04415     pushlong (ctinactive, bs);
04416 
04417     return (true);
04418     }/*fwsNetEventGetStats*/
04419 

Generated on Wed May 31 18:20:04 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6