• Re: Apache + mod_php performance (1/2)

    From Dave Froble@21:1/5 to Dan Cross on Thu Oct 10 23:32:02 2024
    On 10/7/2024 11:52 AM, Dan Cross wrote:
    In article <vdvoeq$1jerg$1@dont-email.me>,
    Dave Froble <davef@tsoft-inc.com> wrote:

    Well, some of the issue is in the text of the question. What does one mean be
    "pass socket"?

    Perhaps an example will be illuminating.

    Ok, I normally refrain from posting large amounts of code. But, perhaps that will show what I was doing.

    Notes:

    In the Listener process, comments mention sub-process. Later I decided the worker process should be a detached process. Comments were never corrected.

    I figured the inter-process communications to be important. In the development code I used a file for SYS$INPUT to the create process system service, and a mailbox. There are better methods, but I thought shared global sections and such was a bit much for a proof of concept.

    An admission to Steve Hoffman that item lists can be a bit tedious, both to write, and to read.

    It has been years since I worked on this ....



    2 !********************************************************************
    !
    ! Program: TCP_LISTENER.BAS
    ! Function: Test Using TCP/IP Sockets as a Listener
    ! Version: 1.00
    ! Created: 01-Dec-2011
    ! Author(s): DFE
    !
    ! Purpose/description:
    !
    ! This program will set up TCP/IP sockets to allow
    ! itself to listen for connection requests. When
    ! a connection request is received, this program
    ! will spawn a subprocess and have the subprocess
    ! service the connection request.
    !
    !********************************************************************
    !
    ! Copyright 2011 by Dave Froble Enterprises, Inc.
    !
    ! This program is the sole property of Dave Froble
    ! Enterprises, Inc. and may not be copied in whole
    ! or in part without the express written permission
    ! of Dave Froble Enterprises, Inc.
    !
    !********************************************************************
    !
    ! Modification history:
    !
    !********************************************************************

    Option Size = ( Integer Word , Real Double )
    %Include "FL:SUPLIB.INC"
    %Include "FL:KBCOMM.INC"
    %Include "FL:TCP_STRUCT.INC"
    %Include "SYS$SHARE:TCPIP$INETDEF.BAS"

    %Include "$SSDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB"
    %Include "$IODEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB"
    %Include "$JPIDEF" %FROM %LIBRARY "SYS$LIBRARY:BASIC$STARLET.TLB"

    External Long Function SYS$ASSIGN, ! System services &
    SYS$CREMBX, &
    SYS$CREPRC, &
    SYS$DASSGN, &
    LIB$GETDVI, &
    SYS$QIOW


    Declare Long ByteCount%, ! Longwords &
    Long ClientNameLen%, &
    Long ClientPort%, &
    Long ConnectNameLen%, &
    Long ConnectPort%, &
    Long Ctx%, &
    Long D9%, &
    Long One%, &
    Long ServerPort%, &
    Long ShareVal%, &
    Long Sock%, &
    Long Stat%, &
    Long Temp%, &
    Long UIC%, &
    Long WorkerPID%


    !**************************************************
    ! Declare Variables of User Defined Structures
    !**************************************************

    DECLARE IOSB_Struct IOSB, ! I/O status blk &
    ItemList_2 ServerItemLst, ! Server item list &
    ItemList_2 SockOptItemList, ! Socket options list &
    ItemList_3 ClientItemLst, ! Client item list &
    ItemList_3 ConnectItemList, ! Connect sock list &
    ItemList_3 ConnectItemList2, ! Connect sock list &
    Socket_Options ListenOpt, ! Socket options &
    Sock_Addr ClientAdr, ! Client IP adr/port &
    Sock_Addr ConnectSockAdr, ! Connect sock data &
    Sock_Addr ConnectSockAdr2, ! Connect sock data &
    Sock_Addr ServerAdr, ! Server IP adr/port &
    SockOpt OptList, ! Socket options list &
    Buff ClientName, ! Client name buffer &
    Buff ServerName, ! Server name buffer &
    IP_Adr IP, ! Ip address &
    Buff Msg ! Message buffer



    200 !**************************************************
    ! Program Initialization
    !**************************************************

    GoSub 4990

    Print #KB% ! Display banner
    Print #KB%, P8$; " "; DATEL(D9%,4%); " "; TIME$(0%)


    ServerPort% = 12345%
    BuffSize% = Len(MSG::BUF$)
    JobCount% = 0%
    DetLogin$ = "SYS$SYSTEM:LOGINOUT.EXE"


    Call SSGETJPI( X'304' , 2% , Z$ ) ! Get UIC
    UIC% = CVT$F(Z$)
    Print #KB%, "Listener UIC: "; Num1$(UIC%)


    !**************************************************
    ! Assign channels to 'TCPIP$DEVICE:'
    !**************************************************

    Dev$ = "TCPIP$DEVICE:"

    Stat% = SYS$ASSIGN( Dev$ , ListenCh% , , )
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to assign listener channel - "; E$
    GoTo 4900
    End If

    Print #KB%, "Internal VMS channel for listener socket:"; ListenCh%

    Stat% = SYS$ASSIGN( Dev$ , ClientCh% , , )
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to assign client channel - "; E$
    GoTo 4900
    End If

    Print #KB%, "Internal VMS channel for client socket:"; ClientCh%


    !**************************************************
    ! Create Listener socket
    ! Bind server's IP address and port # to listener
    ! socket, set socket as a passive socket
    ! Note: we used to do this in 2 calls, but can be combined
    !**************************************************

    ListenOpt::Protocol% = TCPIP$C_TCP ! Listener socket optn
    ListenOpt::Typ$ = Chr$(TCPIP$C_STREAM)
    ListenOpt::AF$ = Chr$(TCPIP$C_AF_INET)

    One% = 1% ! Set to 'True'

    SockOptItemList::Len% = 24% ! Socket options buffer
    SockOptItemList::Typ% = TCPIP$C_SOCKOPT
    SockOptItemList::Adr% = Loc(OptList::ReUseAdrLen%)

    OptList::ReuseAdrLen% = 4%
    OptList::ReuseAdrType% = TCPIP$C_REUSEADDR
    OptList::ReuseAdrAdr% = Loc(One%)

    OptList::ReusePortLen% = 4%
    OptList::ReusePortType% = TCPIP$C_REUSEPORT
    OptList::ReusePortAdr% = Loc(One%)

    OptList::ShareLen% = 4%
    OptList::ShareType% = TCPIP$C_SHARE
    OptList::ShareAdr% = Loc(One%)

    ServerItemLst::Len% = 16% ! Server item list
    ServerItemLst::Typ% = TCPIP$C_SOCK_NAME
    ServerItemLst::Adr% = Loc(ServerAdr::Fam%)

    ServerAdr::Fam% = TCPIP$C_AF_INET ! Server Ip adr/port
    ServerAdr::Port% = SWAP%(ServerPort%)
    ServerAdr::IP.Adr% = TCPIP$C_INADDR_ANY
    ServerAdr::Zero1% = 0%
    ServerAdr::Zero2% = 0%

    BackLog% = 1%

    Stat% = SYS$QIOW( , ! Event flag &
    ListenCh% By Value, ! VMS channel &
    IO$_SETCHAR By Value, ! Operation &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    ListenOpt::Protocol%, ! P1 &
    , ! P2 &
    ServerItemLst::Len%, ! P3 - local socket nam
    e &
    BackLog% By Value, ! P4 - connection backl
    og &
    SockOptItemList::Len%, ! P5 - socket options &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue create and bind listener socket - "
    ; E$
    GoTo 4900
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to create and bind listener socket - "; E$
    GoTo 4900
    End If

    Print #KB%, "Listener socket created ...."
    Print #KB%, "Listener socket bind ...."



    1000 !************************************************************
    ! Main Processing
    !************************************************************


    !**************************************************
    ! Wait for a Client Connection Request
    !************************************************** Listen_for_Connection:
    Print #KB%
    Print #KB%, "Port:"; ServerPort%
    Print #KB%, "Waiting for a client connection ...."

    ClientItemLst::Len% = 16% ! Client item list
    ClientItemLst::Typ% = 0%
    ClientItemLst::Adr% = Loc(ClientAdr::Fam%)
    ClientItemLst::Ret.Len.Ptr% = Loc(ClientNameLen%)
    ClientNameLen% = 16% ! Length of ClientAdr

    ClientAdr::Fam% = 0% ! Client Ip adr/port
    ClientAdr::Port% = 0%
    ClientAdr::IP.Adr% = 0%
    ClientAdr::Zero1% = 0%
    ClientAdr::Zero2% = 0%

    Stat% = SYS$QIOW( , ! Event flag &
    ListenCh% By Value, ! VMS channel &
    IO$_ACCESS OR IO$M_ACCEPT By Value, &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    , ! P1 &
    , ! P2 &
    ClientItemLst::Len%, ! P3 - client socket na
    me &
    ClientCh%, ! P4 - connect channel
    &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue listen for client connection - "; E
    $
    GoTo Close_Listener_Socket
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to listen for client connection - "; E$
    GoTo Close_Listener_Socket
    End If

    !**************************************************
    ! A client has been granted a connection request
    !**************************************************

    IP::IP% = ClientAdr::IP.Adr%
    ClientIP$ = NUM1$(Ascii(IP::IP1$)) + "." &
    + NUM1$(Ascii(IP::IP2$)) + "." &
    + NUM1$(Ascii(IP::IP3$)) + "." &
    + NUM1$(Ascii(IP::IP4$))

    Print #KB%, "Client connection established:"
    Print #KB%, " Client: "; ClientIP$

    ClientPort% = SWAP%(ClientAdr::Port%)
    ClientPort% = "65536"L + ClientPort% If ClientPort% < 0%
    Print #KB%, " Port :"; ClientPort%

    Msg$ = ""


    !**************************************************
    ! Get device name of client socket
    !**************************************************

    Stat% = LIB$GETDVI( 32% , ! Item code &
    ClientCh% , ! Channel # &
    , ! Device name &
    0% , ! Int val &
    SocketDev$, ! Result string &
    NameLen%) ! Result length

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to get client socket name - "; E$
    GoTo Shutdown_Client_Socket
    End If

    Print #KB%, "Client socket device: <"; Trm$(SocketDev$); ">"


    1050 !**************************************************
    ! Get connection socket data
    !**************************************************

    ConnectItemList::Len% = 16% ! Connect item list
    ConnectItemList::Typ% = TCPIP$C_SOCK_NAME
    ConnectItemList::Adr% = Loc(ConnectSockAdr::Fam%)
    ConnectItemList::Ret.Len.Ptr% = Loc(ConnectNameLen%)
    ConnectNameLen% = 16%

    ConnectSockAdr::Fam% = 0% ! Connect Ip adr/port
    ConnectSockAdr::Port% = 0%
    ConnectSockAdr::IP.Adr% = 0%
    ConnectSockAdr::Zero1% = 0%
    ConnectSockAdr::Zero2% = 0%

    ConnectItemList2::Len% = 16% ! Connect item list
    ConnectItemList2::Typ% = TCPIP$C_SOCK_NAME
    ConnectItemList2::Adr% = Loc(ConnectSockAdr2::Fam%)
    ConnectItemList2::Ret.Len.Ptr% = Loc(ConnectNameLen2%)
    ConnectNameLen2% = 16%

    ConnectSockAdr2::Fam% = 0% ! Connect Ip adr/port
    ConnectSockAdr2::Port% = 0%
    ConnectSockAdr2::IP.Adr% = 0%
    ConnectSockAdr2::Zero1% = 0%
    ConnectSockAdr2::Zero2% = 0%

    Stat% = SYS$QIOW( , ! Event flag &
    ClientCh% By Value, ! VMS channel &
    IO$_SenseMode By Value, ! Function &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    , ! P1 &
    , ! P2 &
    ConnectItemList::Len%, ! P3 - Connect socket n
    ame &
    ConnectItemList2::Len%, ! P4 &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue socket data request - "; E$
    GoTo Close_Listener_Socket
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to get socket data - "; E$
    GoTo Close_Listener_Socket
    End If

    Print #KB%
    Print #KB%, "Connection socket data:"
    Print #KB%, " Family:"; ConnectSockAdr::Fam%
    Print #KB%, " Port #:"; Swap%(ConnectSockAdr::Port%)
    Print #KB%, " IP Adr:"; ConnectSockAdr::IP.Adr%
    Print #KB%, " Word 3:"; ConnectSockAdr::Zero1%
    Print #KB%, " Word 4:"; ConnectSockAdr::Zero2%

    Print #KB%, " Family:"; ConnectSockAdr2::Fam%
    Print #KB%, " Port #:"; Swap%(ConnectSockAdr2::Port%)
    Print #KB%, " IP Adr:"; ConnectSockAdr2::IP.Adr%
    Print #KB%, " Word 3:"; ConnectSockAdr2::Zero1%
    Print #KB%, " Word 4:"; ConnectSockAdr2::Zero2%


    1100 !**************************************************
    ! Peek the Incoming Message
    !**************************************************
    Read_Msg:
    Print #KB%, "Peeking client message ...."

    GoSub Peek_Socket ! Look for "SHUTDOWN"
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Print #KB%, E$
    GoTo Shutdown_Client_Socket
    End If

    Print #KB%, ByteCount%; "bytes read from socket"
    Msg$ = Left(MSG::BUF$,ByteCount%)
    Print #KB%, Len(Msg$); "message bytes in buffer"


    !**************************************************
    ! Message Peeked, Display Message
    !**************************************************
    Msg_Completed:
    Print #KB%, "Message peeked, message is"; Len(Msg$); "bytes"
    Print #KB%, "<"; Msg$; ">"


    GoTo Shutdown_Client_Socket If Edit$(Msg$,32%) = "SHUTDOWN"


    !**************************************************
    ! Create a temporary mailbox for communications
    !**************************************************

    Print #KB%, "Creating MailBox"
    Stat% = SYS$CREMBX( 0% By Value , ! Temp mailbox &
    MbxCh% , ! Mailbox channel &
    512% By Value , ! Max mxg size &
    , ! Buffer quota &
    0% By Value , ! Prot mask &
    3% By Value , ! Access mode (user) &
    , ! Logical name &
    , ! Flags (read/write) &
    ) ! Null arg

    Stat% = LIB$GETDVI( 32% , ! Item code &
    MbxCh% , ! Channel # &
    , ! Device name &
    0% , ! Int val &
    MbxDev$, ! Result string &
    NameLen%) ! Result length

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to get mailbox name - "; E$
    GoTo Shutdown_Client_Socket
    End If

    Print #KB%, "Mailbox created, name: <"; Trm$(MbxDev$); ">"

    Call Parse( MbxDev$ , "MBA" , Z1$ , Z2$ )
    Call Parse( Z2$ , ":" , Z1$ , Z2$ )
    Call NIVAL( Z1$ , JobNum% , E% )

    Print #KB%, "Job number will be: "; Num1$(JobNum%)


    !**************************************************
    ! Create subprocess to process incoming request
    !**************************************************

    ProcName$ = "SockWorker" + Num1$(JobNum%)
    CmdFile$ = ProcName$ + ".COM"
    OutFile$ = ProcName$ + ".LOG"

    Open CmdFile$ For Output As File #91%
    Print #91%, "$ show logical tt"
    Print #91%, "$ show logical sys$command"
    Print #91%, "$ show logical sys$input"
    Print #91%, "$ run TCP_WORKER"
    Print #91%, MbxDev$
    Print #91%, ClientIP$
    Print #91%, Num1$(ClientPort%)
    Print #91%, "$ exit"
    Close #91%

    Stat% = SYS$CREPRC( WorkerPID% , ! Worker PID &
    DetLogin$ , ! Loginout &
    CmdFile$ , ! Sys$Command &
    OutFile$ , ! Sys$Output &
    , ! Sys$Error &
    , ! Priv mask &
    , ! Quota mask &
    ProcName$ , ! Process name &
    Prio% By Value , ! Priority &
    UIC% By Value , ! UIC &
    , ! Term mbx &
    64% By Value ) ! PRC$M_NOUAF

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue create worker process - "; E$
    GoTo Close_Listener_Socket
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to create worker process - "; E$
    GoTo Close_Listener_Socket
    End If


    Print #KB%, "Worker process created:"
    Print #KB%, " Name: "; ProcName$
    Print #KB%, " PID: "; Num1$(WorkerPID%)



    !Print #KB%, "Writing to MailBox"
    !Open MbxDev$ As File #92%
    !Field #92%, 32% as Mbx$
    !Lset Mbx$ = SocketDev$
    !Put #92%
    !Lset Mbx$ = Num1$(ClientAdr::IP.Adr%)
    !Put #92%
    !Lset Mbx$ = Num1$(ClientPort%)
    !Put #92%

    !Get #92%
    !Sleep 3%
    !Close 92%

    Input "Wait for worker process to acquire socekt", I0$

    Stat% = SYS$DASSGN( MbxCh% By Value )


    !**************************************************
    ! Worker Process has socket, close in Listener
    !**************************************************

    Print #KB%, "Closing client socket ...."

    Stat% = SYS$QIOW( , ! Event flag &
    ClientCh% By Value, ! VMS channel &
    IO$_DEACCESS By Value, &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    , ! P1 - I/O buffer &
    , ! P2 - length of buffer
    &
    , ! P3 &
    , ! P4 &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue close connection socket - "; E$
    GoTo 4900
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to close connection socket - "; E$
    GoTo 4900
    End If

    GoTo Listen_for_Connection


    !**************************************************
    !**************************************************
    ! 'SHUTDOWN' received, shut down listener
    ! Break the Connection
    !************************************************** Shutdown_Client_Socket:
    Print #KB%, "Shutting down client socket ...."

    Stat% = SYS$QIOW( , ! Event flag &
    ClientCh% By Value, ! VMS channel &
    IO$_DEACCESS OR IO$M_SHUTDOWN By Value, ! Function code &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    , ! P1 - I/O buffer &
    , ! P2 - length of buffer
    &
    , ! P3 &
    TCPIP$C_DSC_ALL By Value, ! P4 &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue close connection - "; E$
    GoTo 4900
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to close connection - "; E$
    GoTo 4900
    End If


    !**************************************************
    ! Close Listener Socket
    !************************************************** Close_Listener_Socket:
    Print #KB%, "Closing listener socket ...."

    Stat% = SYS$QIOW( , ! Event flag &
    ListenCh% By Value, ! VMS channel &
    IO$_DEACCESS By Value, &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    , ! P1 - I/O buffer &
    , ! P2 - length of buffer
    &
    , ! P3 &
    , ! P4 &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to queue close listener socket - "; E$
    GoTo 4900
    End If

    If ( IOSB::Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( IOSB::Stat% , E$ )
    Print #KB%, "Unable to close listener socket - "; E$
    GoTo 4900
    End If


    !**************************************************
    ! Deassign Channel(s)
    !**************************************************
    Deassign_Channel:
    Print #KB%, "Deassigning client channel ...."

    Stat% = SYS$DASSGN( ClientCh% By Value )
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to deassign client channel - "; E$
    GoTo 4900
    End If

    Print #KB%, "Deassigning listener channel ...."

    Stat% = SYS$DASSGN( ListenCh% By Value )
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    Print #KB%, "Unable to deassign listener channel - "; E$
    GoTo 4900
    End If

    GoTo 4950


    4900 !************************************************************
    ! Exit Point
    !************************************************************

    Print #KB%
    E% = KBINPT( "Type <CR> to exit ...." , 0% , I0$ , E% )


    4950 Print #KB%
    Print #KB%, "End of "; P8$
    Print #KB%
    GoTo 32760



    !************************************************************
    ! Subroutines
    !************************************************************


    4990 !**************************************************
    ! Program Initialization
    !**************************************************

    P9$ = "TCP_LISTENER" ! Program name
    P8$ = "Test Using TCP/IP Sockets as a Listener" ! Function name
    On Error GoTo 32000 ! Enable error trapping
    KB% = 99% ! Keyboard channel
    KB.MODE% = 0% ! Mode for keyboard ope
    n
    Call KBOPEN( KB% , KB.MODE% ) ! Open keyboard
    X3% = 0% ! No cursor addressing
    Z% = CTRLC ! ^C trap
    Call SYPRAM(U1$,U1%,U2$,U3$,D9%,U5$,T2$) ! Read sys parameters
    E1$ = " not a valid " ! Std error text
    E2$ = "Unable to " ! Std error text
    DI0$ = STRING$(4%,0%) ! DI zero string
    Return !



    6800 !**************************************************
    ! Peek into Socket
    !**************************************************
    Peek_Socket:
    Stat% = SYS$QIOW( , ! Event flag &
    ClientCh% By Value, ! VMS channel &
    IO$_READVBLK By Value, ! Function code &
    IOSB::Stat%, ! I/O status block &
    , ! AST routine &
    , ! AST parameter &
    MSG::BUF$ By Ref, ! P1 - I/O buffer &
    BuffSize% By Value, ! P2 - length of buffer
    &
    , ! P3 &
    TCPIP$C_MSG_PEEK By Value, ! P4 - peek at msg &
    , ! P5 &
    ) ! P6

    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    E$ = "Unable to queue read server message - " + E$
    Return
    End If

    Stat% = IOSB::Stat%
    If ( Stat% And SS$_NORMAL ) = 0%
    Then Call VMSERR( Stat% , E$ )
    E$ = "Unable to read server message - " + E$
    End If

    ByteCount% = IOSB::Cnt%

    Return



    32000 !******************** ERROR TRAPS ********************


    32700 Print ! Final error trap
    Print "Unforseen error detected in <"; P9$; ">"
    On Error GoTo 0

    32760

    32766 Chain U1$ Unless U1$=""


    32767 End

    2 !********************************************************************
    !
    ! Program: TCP_WORKER.BAS
    ! Function: Worker Program To Service A Connection Request
    ! Version: 1.00
    ! Created: 16-Dec-2011
    ! Author(s): DFE
    !
    ! Purpose/description:
    !
    ! This program will be spawned as a detached
    ! process to service client connection requests.
    !

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)