Xb2.NET - Internet Library for Xbase++ Listen Bud... it's got radioactive blood!


    Release: 3.2.00
    2007.11.07


    Copyright © 2001-2007, Xb2.NET inc.
    All rights reserved

    Updates:
    Updates to Xb2.NET will be posted on the product homepage: http://www.xb2.net

    Reporting problems:
    Problems discovered with Xb2.NET should be reported by email to: support@xb2.net

    Redistributable software components:
    Provided that the Redistribution Requirements as specified in the Xb2.NET License Agreement are satisfied, licensed users may copy and distribute the XB2NET.DLL runtime file with their applications.

    License keys:
    License keys supplied to registered users must be treated confidentially and must NOT be disclosed to any third party. In addition, Xb2.NET license keys may only be linked into an application executable (.EXE). Linking a license key into any DLL (dynamic link library) or OBJ (object file) that is to be distributed to a third party is NOT permitted and constitutes a license infringement.

    CLASS HIERARCHY:

    xbSocket | Complete object-oriented sockets library that provides a protocol-independent | base for developing virtually any kind of communications software. | +-- xbServer (derived from: xbSocket, Thread) | | A generic protocol-independent server that can be easily configured for a | | variety of Telnet applications. | | | +-- xbHTTPServer (derived from: xbServer) | A powerful object-oriented HTTP 1.1 web and SOAP server that is build right into your | Xbase++ application. No need to configure and manage complex 3P web servers, | gateways and CGI scripts. Your Xbase++ program is the server! | +-- xbSocketThread (derived from: xbSocket, Thread) | This is the client thread that is spawned by xbServer when a connection with a peer | is accepted. This "worker" thread will handle the request and send a response back | to the connected client. | +-- xbHTTPThread (derived from: xbSocket, Thread) This is the client thread that is spawned by xbHTTPServer when a connection is accepted from a user agent (a browser). This "worker" thread is responsible for handling the client request and generating an appropriate xbHTTPResponse that will be sent back to the client. xbHTTPMessage | An abstract class for composing and parsing HTTP messages. | +-- xbHTTPRequest (derived from: xbHTTPMessage, xbURI) | Client side: Compose HTTP request and send to HTTP server. | Server side: Parse HTTP request received from client. | +-- xbHTTPResponse (derived from: xbHTTPMessage) Client side: Parse HTTP response received from server. Server side: Compose HTTP response and send to client. xbHTTPClient | Provides a higher level interface for developing HTTP client applications. | +-- xbXMLDocument (derived from: xbHTTPClient) | This class provides a simplified means for generating XML requests and parsing XML responses. | +-- xbSOAPEnvelope (derived from: xbHTTPClient) This class provides the code necessary to generate and parse SOAP messages. SOAP is a remote procedure calling protocol that encodes requests and responses in XML format. Using SOAP a client can execute methods or functions on a server and receive an XML response containing the return values. xbComplexType Used to represent complex data structures. Data structures can be nested, and may contain any other type, including an array. Instances of xbComplexType are typically used by the xbSOAPEnvelope class to serialize and deserialize complex data structures. xbForm This class represents a url-encoded form. The form typically contains data expressed as "name=value" pairs, encoded for safe transport over the net. This class allows you to parse an existing form as well as create a brand new form. xbFTPClient FTP (File Transfer Protocol) client provides methods for managing directories and files on a remote FTP or FTPS server. The class is fully compliant with RFC's 959, 2228 and 4217. It provides support for AUTH TLS, AUTH SSL and Implicit SSL connections. xbPayload Provides methods for serializing and deserializing one or more attachments of any size (files, character strings, objects or any Xbase++ data) for transmission between an HTTP client and server. This class is also used by the xbSOAPEnvelope class for sending SOAP attachments. xbSSLContext Provides a context for implementing secure network communications using the OpenSSL library. Once initialized, an xbSSLContext object can be attached to an xbSocket, xbServer, xbHTTPServer, xbHTTPClient, xbXMLDocument or xbSOAPEnvelope instance to provide secure communications. xbSession HTTP by nature is stateless and in itself provides limited session management capability. This class simplifies session management and provides the ability of saving persistent data across multiple HTTP requests. Sessions are automatically managed by the xbHTTPServer class. xbStream Provides generic methods for reading and writing to data stream files. xbTLog Class for logging client requests using Extended Log File Format (W3C Working Draft WD-logfile-960323). This log format is compatible with Microsoft Internet Information Server (IIS) and is supported by many third party web log analyzers. xbURI Create, parse, encode and decode URI and URL strings.

    FUNCTIONS:

    xbErrorLog( xError, [nErrorCode], [lisSSL], [cFile], [lFlash], [lLogCallstack] ) -> NIL This function will log an error or event to a file. It is typically called from within an xbSocket:OnError codeblock. Parameters: xError This parameter specifies the type of event that will be logged. The options are as follows:
    - An error object, derived from the Xbase++ "Error" class.
    - An object derived from the "xbSocket" class.
    - A character string. nErrorCode The WinSock or OpenSSL error code number. lisSSL A logical value, which when set to .T., indicates that the error was raised by the OpenSSL library. cFile The name of the file where the information will be logged. If not specified, the default is xbSocket():ErrorLogFile. lFlash An optional logical value that is used to provide visual feedback of the error. When set to .T., the error message will be briefly flashed on the display screen. The default is .F., meaning that no visual feedback is provided. lLogCallstack An optional logical value specifying if the callstack will be written to the file. The default is to log the callstack, however this can be turned off by setting this parameter to .F. xbCreateGuid() -> cGuid Returns a globally unique identifier as a 36-character (hex) string in the following format "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", eg:
    6B29FC40-CA47-1067-B31D-00DD010662DA

    When the originating computer does not have an ethernet/token ring address, the generated ID is only guaranteed to be unique among all IDs generated on the same computer. Although very small, the possibility however does exists that another computer without an ethernet/token ring address generated the identical ID. Computers with ethernet/token ring addresses generate GUIDs that are guaranteed to be globally unique. xbGetFileMimeType( cFileName ) -> cMimeType Return the MIME media type for a given file name. The MIME media type is determined by file name's 3 or 4 character extension. For example; file names with the extension .HTM will have a MIME media type of "text/html". xbGetTickCount() -> nMilliseconds Return the number of milliseconds that have elapsed since the system was started. The maximum return value is limited to a 32 bit integer therefore, the time will wrap around to zero if the system is run continuously for 49.7 days. xbGMTDate( [dDate], [cnTime] ) -> cGMTDate Return a string representing the date and time in GMT using Internet conventions in the following form:
    Day, DD Mon YYYY HH:MM:SS GMT, eg:
    Wed, 07 Oct 2004 19:23:50 GMT

    Both parameters are optional if not specified the current date/time is used. cnTime can be a numeric as returned by SECONDS(), or a string as returned by TIME(). The timezone is based on the return value of xbTimezoneOffset(). xbHTTPErrorHandler( oError, [cFile], [lLogError] ) -> cErrorMessage This is the default HTTP error handler that will be used in the absence of an xbHTTPServer:onHTTPError codeblock. The function is evaluated when a runtime error occurs during the processing of an HTTP request. It will log the error to a file, prepare an HTML error message and send it to the client. The function returns the HTML formatted string that will be sent to the client. Parameters: oError An Xbase++ error object. cFile The name of the file where the error will be logged. If not specified, the default is xbSocket():ErrorLogFile. lLogError An optional logical value that determines whether the error is logged to a file. The default behavior is to log the error to a file, however this can be disabled by setting lLogError to .F.

    Example: // use default error handler but don't log errors:
    oServer:onHTTPError := {|oError| xbHTTPErrorHandler(oError,nil,.f.)}
    xbIP2Decimal(cAddress) -> nAddress Converts a dotted-decimal IP address into it's equivalent decimal format. The return value is a 32-bit unsigned integer.

    Example: nIP := xbIP2Decimal('216.19.71.75') // returns 3625142091
    xbSaveToFile( cString, [cFile], [lAppend] ) -> lSuccess Write the string cString to a file. If not specified, cFile defaults to xbSocket():ErrorLogFile. If the file does not exist, it will be created. If lAppend is set to .T. (the default), then cString will be appended to the end of the file. Otherwise the current file (if there is one) will be overwritten. The function returns .T. if the data was written successfully. xbSocketErrorText( [nErrorCode], [lisSSL] ) -> cErrorText When lisSSL is NIL or .F., return error description of WinSock error code nErrorCode. Otherwise, when lisSSL is .T., return error description of OpenSSL error code nErrorCode. If not supplied, nErrorCode defaults to the most recent error code produced in this thread. xbTcpWindowSize( [nSize] ) -> nTcpWindowSize Get or set the system's TCP window size parameter. The TCP window is the amount of unacknowledged data in flight between the sender and the receiver. Although TCP tries to optimize the transmit window to maximize throughput over the lifetime of a connection, the value returned by xbTcpWindowSize puts a hard limit on the window size.

    The TCP window size is stored in the system registry under the following path:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpWindowSize

    The system's TCP window size registry value can be changed by setting nSize to the desired number of bytes. The optimal window size for a given TCP connection can be determined by multiplying the network bandwidth by the delay. For example a 1.5Mbps DSL connection with a round-trip delay of 200ms gives a window size of 37,500 bytes. Keep in mind that this parameter cannot be changed at will. A system reboot is typically required for the change to become effective. The window size should therefore be made large enough to accomodate the fastest networks with the slowest delay. xbTimezoneOffset( [nMinutes] ) -> nTimezoneOffset Get/set the difference between the local time and GMT as an integer representing the number of minutes. Unless the local time is GMT, this function should be called at program start so that xbGMTDate() can return the correct GMT date. If a parameter is not specified, the function returns the current timezone offset. When using Xbase++ 1.7 or higher, the timezone offset will be automatically set on startup to the return value of SetLocale(NLS_ITZBIAS). xbUniqueFile( [cPath], [cPrefix], [cExt], [nAttr], [@nHandle] ) -> cFileName Creates and returns a file name that is unique within the directory specified. The file name is returned including path information. If an error occurs, the return value is a null string and the error code can be retrieved using FError(). Parameters: cPath Optional character string that specifies the directory in which the file will be created. If not provided, the system temporary file directory (defined in the 'TEMP' environment variable) is used. cPrefix Optional character string to use as the file name prefix. If not specified, the file prefix will default to "~". cExt Optional character string to use as the file name extension. If not specified, the file extension will default to ".tmp". nAttr An integer numeric value which sets the access mode for the file. Various symbolic constants are defined in the Xbase++ include file "Fileio.ch". For more information, consult the Xbase++ documentation for FCREATE. This parameter is optional and defaults to FC_NORMAL: nHandle This is an optional output parameter. If provided, the reference operator "@" must be placed in front of the argument nHandle. In this case, the newly created file will be left in an open state with the low-level file handle returned in the memory variable nHandle. The file remains open for write access until the file handle is passed to the Xbase++ function FClose(). xbWChar(cAnsiString) -> cUnicodeString Convert a single-byte ANSI string to double-byte unicode. xbWindowHandle( [nHandle] ) -> nWindowHandle Get or set the application's default window handle. A specific window handle can be set by calling this function with a numeric nHandle value. The return value is used as the parent window by certain Internet error dialogs.


    Bitwise functions

    xbAND( n1, n2 ) -> nResult Returns the bitwise AND of the values provided by n1 and n2. xbOR( n1, n2 ) -> nResult Returns the bitwise OR of the values provided by n1 and n2. xbXOR( n1, n2 ) -> nResult Returns the bitwise XOR of the values provided by n1 and n2. xbNOT( nVal ) -> nResult Returns the bitwise complement of nVal. xbSHL( nVal, [nCount] ) -> nResult Returns the value of nVal, shifted left by nCount bits. As bits are shifted left, zero's are placed on the right. If not specified, nCount defaults to 1. xbSHR( nVal, [nCount] ) -> nResult Returns the value of nVal, shifted right by nCount bits. As bits are shifted right, zero's are placed on the left. If not specified, nCount defaults to 1. xbHtonl( nULong ) -> nResult Convert a 32-bit unsigned long integer from host byte order to network byte order (little-Endian to big-Endian). xbHtons( nUShort ) -> nResult Convert a 16-bit unsigned short integer from host byte order to network byte order (little-Endian to big-Endian). xbNtohl( nULong ) -> nResult Convert a 32-bit unsigned long integer from network byte order to host byte order (big-Endian to little-Endian). xbNtohs( nUShort ) -> nResult Convert a 16-bit unsigned short integer from network byte order to host byte order (big-Endian to little-Endian).


    Encoding functions

    xbBase64Encode( cString, [lCRLF76] ) -> cBase64String Return cString in base64 encoded format. Base64 encoding coverts binary information from 8 bits per byte to 6 bits per byte. Information in 3-8bit bytes (24 bits) is converted into 4-6bit bytes (same 24 bits), resulting in a encoded string that is 1.333 times larger than the original.

    The optional parameter lCRLF76 can be set to .T. in order to have the encoded output stream formatted in lines of 76 characters. The default for lCRLF76 is .F. xbBase64Decode( cBase64String ) -> cOriginalString Decodes a base64 encoded string into it's original form. xbCrypt( cInString, [nLen], [nSeed] ) -> cOutString Encrypt or decrypt a string. Parameters: cInString The string to be encrypted or decrypted. nLen Optional number of characters within cInString to process. nSeed Optional random number seed. If cInString is the encrypted string, then the same random number seed as was used to encrypt the string must be supplied to decrypt it.

    Example: cCrypt := xbCrypt("ABCD")
    ? xbCrypt(cCrypt) // -> "ABCD"
    xbEscape( cString, [cAllowed] ) -> cEscapedString Convert an input string cString into URL encoded format where reserved characters are replaced with a percent sign followed by a hex number. For example, the space character is replaced with %20, a question mark (?) is replaced with %27.

    cAllowed is an optional string that can be used to supply the list of characters which will NOT be translated. If not directly specified, cAllowed will default to the following:
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'() xbUnEscape( cString ) -> cOriginalString Decodes a URL encoded string into it's original form.


    OpenSSL functions

    xbSSLAvailable() -> lSuccess Indicates whether the OpenSSL library has been loaded. The function returns .T. when the OpenSSL library is loaded and ready for use. Possible reasons why the OpenSSL library cannot be loaded include:

    • The Xb2NetKey is invalid or does not include SSL/TLS support.
    • The OpenSSL LIB files: LIBSSL32.DLL and LIBEAY32.DLL cannot be found in the system path.
    • Wrong version of OpenSSL is being used.

    xbSSLFreeErrorQueue() -> NIL Destroy a thread's error queue. This method must be called at end of a thread that uses an xbSSLContext. Failure to do this may result in memory leaks. The xbServer, xbSocketThread and xbHTTPThread classes already perform a proper cleanup at thread termination. It is therefore not necessary to call this method when the xbSSLContext is used in conjunction with one of these classes. xbSSLGetErrorString( [nError] ) -> cError Return a human-readable string representing the OpenSSL error code nError. The returned string will have the following format:
    error:[error code]:[library name]:[function name]:[reason string]

    Where error code is an 8 digit hexadecimal number, library name, function name and reason string are ASCII text.

    If nError is not provided, it defaults to the return value of xbSSLGetLastError(). xbSSLGetLastError() -> nError Returns the earliest error code from the thread's OpenSSL error queue and removes the entry. This function can be called repeatedly until there are no more error codes to return.


    XML functions

    xbXML2Array( cXMLDocument ) -> aXMLTree Parse an XML document into a hierarchical array of XML tags. The returned array contains subarrays of 4 elements each which may be accessed with the following define constants available in Xb2NET.CH. An empty array will be returned when the passed string is not a valid XML document.

    XTAG_NAME - xml tag element name as string.
    XTAG_ATTRIB - element attributes as string.
    XTAG_CONTENT - tag contents; a string (tag value) or array containing subnodes (XTAG_TYPE = XTYPE_NODE)
    XTAG_TYPE - numeric value indicating type of XTAG_CONTENT. The following values are possible:
        XTYPE_NODE - a subnode
        XTYPE_TEXT - a data value

    Example: TEXT INTO cString
    <env:Envelope
        xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/1999/XMLSchema">
        <env:Body>
          <ns:getQuote
            xmlns:ns="urn:xmethods-delayed-quotes"
            env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <symbol xsi:type="xsd:string">IBM</symbol>
          </ns:getQuote>
        </env:Body>
    </env:Envelope>
    ENDTEXT

    aXMLTree := xbXML2Array(cString)

    // aXMLTree will contain the following:

    {{env:Envelope, xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema",
    {{env:Body, ,
    {{ns:getQuote, xmlns:ns="urn:xmethods-delayed-quotes" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
    {{symbol, xsi:type="xsd:string", IBM, 1}}, 0}}, 0}}, 0}}
    xbXMLDateTime( [dDate], [cnTime] ) -> cXMLDate Return a string representing the date and time with timezone offset in the following format:
    yyyy-mm-ddThh:mm:ss.0000000-hh:mm, eg:
    2004-12-05T23:33:38.0000000-05:00

    Both parameters are optional if not specified the current date/time is used. cnTime can be a numeric as returned by SECONDS(), or a string as returned by TIME(). The timezone is based on the return value of xbTimezoneOffset(). xbXMLGetAttribute( cAttrib | aXMLNode, [cAttribName] ) -> cAttribValuez Return attribute value for a given attribute item. The first parameter can be specified as a string representing the entire attribute value, or as a XML Node array. If cAttribName is NIL, then the entire attribute is returned.

    Example: // using aXMLTree from xbXML2Array example above...
    ? xbXMLGetAttribute( aXMLTree[1], "xsd" )
    // returns: http://www.w3.org/1999/XMLSchema
    ? xbXMLGetAttribute('se:arrayType="xsd:int[3]" xsi:type="se:Array"', 'type' )
    // returns: se:Array
    xbXMLGetNode( aXMLTree, cName ) -> aChildNode | NIL Scan aXMLTree for a node with the name cName and return the first node found with that name. Note, the returned node may itself contain other subnodes. The XTAG_TYPE element will specify the type of content (see above). If cNode cannot be found, the function returns NIL.

    Example: // using aXMLTree from xbXML2Array example above...
    ? xbXMLGetNode( aXMLTree, "getQuote" )

    // returns the following array:
    {ns:getQuote, xmlns:ns="urn:xmethods-delayed-quotes" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
    {{symbol, xsi:type="xsd:string", IBM, 1}}, 0}



    ZLIB functions

    These functions provide an interface to the free and open-source ZLib compression library written by Jean-Loup Gailly and Mark Adler. Technical information, source code and compiled versions of the library can be found on the ZLib homepage: http://www.zlib.net/. xbZCompress( cData, [nLevel], [@nError], [lRaw] ) -> cCompressedData | NIL Compress an input string using the 'deflate' compression method. The function will return NIL if an error occurred. Parameters: cData The input string to be compressed. nLevel Optional parameter specifying the compression level to use. Where 0 = no compression, 1 = minimum compression, maximum speed, and 9 = maximum compression, slowest speed. If not specified, the compression level defaults to 6. nError Optional parameter that must be passed by reference. On return, nError will contain one of the following numeric codes:

    Z_OK - the input string was successfully compressed.
    Z_MEM_ERROR - failed; insufficient memory.
    Z_BUF_ERROR - failed; output buffer was too small.
    Z_STREAM_ERROR - failed; the nLevel parameter is invalid.
    lRaw Optional logical parameter specifying whether to include a 2-byte ZLib header in the output cCompressedData string. When set to .T. (the default), the ZLib signature will NOT be included. xbZCompressFile( cFileIn, cFileOut, [nLevel], [cFileAttr] ) -> lSuccess Compress a file using the 'deflate' compression method. The function will return .F. if an error occurs, and .T. if successful. Parameters: cFileIn The name of a file to be compressed. cFileOut The name of an output file where the compressed version of cFileIn will be stored. nLevel Optional parameter specifying the compression level to use. Where 0 = no compression, 1 = minimum compression, maximum speed, and 9 = maximum compression, slowest speed. If not specified, the compression level defaults to 6. cFileAttr An optional character string describing the attributes to be set for the output file. One or more of the following characters can be specified. Example, "HR" indicates a hidden, read-only file:

    H - Hidden
    S - System
    R - Read-only
    A - Archive
    N - Normal (the default)
    xbZCRC32( [nCRC], cBuffer, [nLen] ) -> nCRC32 Calculate a running CRC (Cyclic Redundancy Check) value of an input buffer. nCRC is the previous CRC value, which defaults to zero if not provided. cBuffer is a character string buffer that we wish to calculate a CRC for, and nLen is the number of bytes within cBuffer to examine. nLen defaults to the length of cBuffer if not directly specified.

    Example: // calculate CRC32 value for a file
    cBuffer := Space(32768)
    nFile := FOpen("xb2net.dll", FO_READ)
    nCRC := 0

    while (nBytes := FRead(nFile, @cBuffer, 32768)) > 0
       nCRC := xbZCRC32(nCRC, cBuffer, nBytes)
    end
    FClose(nFile)
    ? "CRC32 value = ", nCRC
    xbZError( nError ) -> cErrorString Returns a character string corresponding to a ZLib error code nError. xbZUnCompress( cCompressedData, nOriginalSize, [@nError], [lRaw] ) -> cOriginalData | NIL Inflate an input string that was previously compressed using the 'deflate' compression method. The function will return NIL if an error occurred. Parameters: cCompressedData The compressed string to be inflated. nOriginalSize The (exact) original size of the uncompressed data. nError Optional parameter that must be passed by reference. On return, nError will contain one of the following numeric codes:

    Z_OK - the input string was successfully uncompressed.
    Z_MEM_ERROR - failed; insufficient memory.
    Z_BUF_ERROR - failed; output buffer was too small.
    Z_DATA_ERROR - failed, the input buffer cCompressedData was corrupted.
    lRaw Optional logical parameter specifying whether the input string cCompressedData contains a 2-byte ZLib header. Setting lRaw to .T. (the default), indicates that the input string does NOT contain a header. xbZUnload() -> lSuccess Unload the ZLIB.DLL library. Returns .T. if the DLL file was unloaded successfully. Note that the ZLIB.DLL file is automatically loaded whenever a ZLIB function is executed. xbZVersion() -> cVersion Returns the ZLIB.DLL version number as a string.



    CLASSES:

    xbSocket

    xbSocket: Class methods

    :New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext]) -> self, or;
    :New(oParent, [nHandle]) -> self
    Creates a new instance of the xbSocket class and allocates system resources to bind the newly created socket to a specific transport service provider. All parameters are optional.

    Connection-oriented sockets such as SOCK_STREAM provide full-duplex connections, and must be in a connected state before any data can be sent or received on it. A connection to another socket is created with a :Connect call. Once connected, data can be transferred using :Send and :Recv calls. When a session has been completed, a :Close or :Destroy must be performed.

    The communications protocols used to implement a reliable, connection-oriented socket ensure that data is not lost or duplicated. If data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, the connection is considered broken and subsequent calls will fail with the :ErrorCode set to WSAETIMEDOUT.

    Connectionless, message-oriented sockets allow sending and receiving of datagrams to and from arbitrary peers. If such a socket is connected to a specific peer (see :Connect), datagrams can be sent/received only to/from this peer. Parameters: nAddrFamily An address family, define constant AF_*. Default is AF_INET. nSocketType The socket type. Winsock 1.1 only supports types SOCK_STREAM (the default) and SOCK_DGRAM.

    SOCK_STREAM - Provides sequenced, reliable, two-way, connection-based byte streams with an out-of-band data transmission mechanism. Uses TCP for the Internet address family.

    SOCK_DGRAM - Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses UDP for the Internet address family. nProtocol A particular protocol to be used with the socket that is specific to the indicated address family. Default is IPPROTO_IP. Other values can be discovered by using the :GetProtoByName and :GetProtoByNumber methods. oSSLContext This parameter can be set to an instance of xbSSLContext to secure data transmission on this socket. Note that only connection-oriented (SOCK_STREAM) sockets can be secured. oParent A parent/child relation can be established between sockets by using this parameter. The new instance will inherit :AddrFamily, :SockType, :Protocol, :SSLContext, :Encode, :Decode and :onError properties from oParent. This is done implicitly when a connection is accepted by the :Accept method. nHandle The :Handle of an already open socket. If a handle is not specified, a brand new socket will be created with the same address family, socket type and protocol as the oParent socket. :DllLoad() -> lSuccess Load and initialize winsock dll. :DllUnload() -> lSuccess Close all sockets and unload winsock dll. :DllReset() -> lSuccess Close all sockets and reinitialize winsock dll. :ErrorText(nErrorCode, [lisSSL]) -> cErrorText When lisSSL is NIL or .F., return error description of WinSock error code nErrorCode. Otherwise, when lisSSL is .T., return error description of OpenSSL error code nErrorCode. :GetHostByAddr(nAddress, nType) -> aHostInfo | NIL Retrieves the host information corresponding to a network address. nAddress is a numeric IP address in network byte order, nType is the address family, eg. AF_INET. The method returns an array containing host information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    HOSTENT_CNAME - character string representing the name of the host
    HOSTENT_ALIAS - a one dimension array holding alternate names of the host. If none exist the array will be empty
    HOSTENT_NTYPE - numeric value indicating the address family, eg. AF_INET
    HOSTENT_NLEN - length, in bytes required to represent the network byte order addresses in HOSTENT_ADDR
    HOSTENT_ADDR - a one dimensional array of numeric IP addresses for the host in network byte order :GetHostByName(cHostName) -> aHostInfo | NIL Retrieves the host information corresponding to a host name. cHostName is a character string representing the name of the host (eg. "sqlexpress.net") for which to retrieve the information. The method returns an array containing host information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    HOSTENT_CNAME - character string representing the name of the host
    HOSTENT_ALIAS - a one dimension array holding alternate names of the host. If none exist the array will be empty
    HOSTENT_NTYPE - numeric value indicating the address family, eg. AF_INET
    HOSTENT_NLEN - length, in bytes required to represent the network byte order addresses in HOSTENT_ADDR
    HOSTENT_ADDR - a one dimensional array of numeric IP addresses for the host in network byte order :GetProtoByName(cProtocolName) -> aProtocolInfo | NIL Retrieves protocol information corresponding to a protocol name. The method returns an array containing protocol information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    PROTOENT_CNAME - character string representing the official name of the protocol.
    PROTOENT_ALIAS - a one dimension array holding alternate names of the protocol. If none exist the array will be empty.
    PROTOENT_NUMBER - a numeric protocol number, in host byte order. :GetProtoByNumber(nProtocolNumber) -> aProtocolInfo | NIL Retrieves protocol information corresponding to a protocol number. The method returns an array containing protocol information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    PROTOENT_CNAME - character string representing the official name of the protocol.
    PROTOENT_ALIAS - a one dimension array holding alternate names of the protocol. If none exist the array will be empty.
    PROTOENT_NUMBER - a numeric protocol number, in host byte order. :GetServByName(cServiceName, [cProtocolName]) -> aServiceInfo | NIL Retrieves service information corresponding to a service name and protocol. cProtocolName is optional, if not specified, the method returns the first service where the name matches cServiceName. The method returns an array containing service information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    SERVENT_CNAME - character string representing the official name of the service.
    SERVENT_ALIAS - a one dimension array holding alternate names of the service. If none exist the array will be empty.
    SERVENT_NPORT - a numeric port number at which the service can be contacted.
    SERVENT_CPROT - the name of the protocol to use when contacting the service. :GetServByPort(nPort, [cProtocolName]) -> aServiceInfo | NIL Retrieves service information corresponding to a port and protocol. cProtocolName is optional, if not specified, the method returns the first service where the port number matches nPort. The method returns an array containing service information, or NIL on failure. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    SERVENT_CNAME - character string representing the official name of the service.
    SERVENT_ALIAS - a one dimension array holding alternate names of the service. If none exist the array will be empty.
    SERVENT_NPORT - a numeric port number at which the service can be contacted.
    SERVENT_CPROT - the name of the protocol to use when contacting the service. :InetAddr(cAddress) -> nAddress Converts a dotted-decimal IP address (eg. '127.0.0.1') to a numeric Internet address in network byte order :InetNtoA(nAddress) -> cAddress Converts a numeric Internet network byte order address into it's human readable dotted-decimal string format, eg. '127.0.0.1'


    xbSocket: Class properties

    :Copyright readonly/character Returns Xb2.NET library copyright information :DisplayErrors exported/logical Enable/disable console display of winsock error and warning messages. When set to .T., a console dialog box will be displayed whenever a winsock error occurs. The default setting is .F.. The most recent winsock error is saved in the :ErrorCode ivar. :DllDescription readonly/character Description of the Windows Sockets implementation. :DllStatus readonly/character Relevant status or configuration information as returned by winsock. :DllVersion readonly/character The version of the Windows Sockets specification used on the local machine. :ErrorLogFile exported/character The name of the file where errors are logged. Default is XB2ERROR.LOG. This property is used by the xbErrorLog function. :LocalName readonly/character Standard host name of the local machine. :Version readonly/character Returns Xb2.NET library version number as a string.


    xbSocket: Object methods

    Life Cycle :Open([nAddrFamily], [nSocketType], [nProtocol]) -> lSuccess Allocates system resources and causes the socket to be bound to a specific transport service provider. Technically this is equivalent to calling :New() except that a new class instance is not created. For additional information on parameters, see :New(). :Bind([xLocalAddr], [nPort]) -> lSuccess Associate a local address with a socket. This method is used to bind to either connection-oriented (stream) or connectionless (datagram) sockets before subsequent calls to the :Connect or :Listen methods. When a socket is instantiated or opened using :Open, it is associated with an address family only. In order for the socket to be able to communicate with a remote process it should be bound to a local address and port. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (ex. 127.0.0.1). If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default). This allows the underlying service provider to use any appropriate network address, potentially simplifying application programming in the presence of multihomed hosts (hosts that have more than one network interface and address). nPort This is the numeric port number on the local computer to bind the socket to. The default is zero and this allows the underlying service provider to assign a unique port to the application with a value between 1024 and 5000. Binding to a specific port number other than port 0 is discouraged for client applications, since there is a danger of conflicting with another socket already using that port number. :Connect(xRemoteAddr, nPort) -> lSuccess This method is used to establish a connection to a specified destination. If the socket is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound.

    Connection-oriented sockets (eg. SOCK_STREAM), must be in a connected state before data can be transmitted using :Send/:Recv. Any attempt to re-connect an active connection will fail with the :ErrorCode WSAEISCONN.

    For a connectionless socket (eg. SOCK_DGRAM), the operation performed by :Connect is merely to establish a default destination address that will be used on subsequent :Send and :Recv calls. Any datagrams received from an address other than the destination address specified will be discarded. If the xRemoteAddr parameter is specified as zero, the socket will be "disconnected". The default destination can be changed by simply calling connect again, even if the socket is already connected. Any datagrams queued for receipt are discarded if xRemoteAddr or nPort are different from the previous connect.

    Any valid xRemoteAddr and nPort can be specified for connectionless sockets, including a broadcast address. However, to connect to a broadcast address, :Broadcast(.t.) must be set first. Otherwise, :Connect will fail with the :ErrorCode WSAEACCES. Parameters: xRemoteAddr The remote address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (ex. 127.0.0.1). nPort This is the numeric port number on the remote computer to connect to. :SSLConnect([oSSLContext]) -> lSuccess Initiate a SSL/TLS handshake with a connected server. The socket must be of type SOCK_STREAM and it must already be in a connected state when this method is called.

    oSSLContext is an optional parameter than can be set to an instance of the xbSSLContext class. This is only necessary if specific SSL/TLS properties need to be set, such as a client certificate, CA lists, cypher suites, etc.

    The method will return .T. if an SSL/TLS connection has been successfully established with the peer. Otherwise, the method returns .F. :Listen([nBacklog]) -> lSuccess Place a socket in a state where it is listening for incoming connections. This method is typically used by servers that can have more than one connection request at a time. If a connection request arrives and the queue is full, the client will receive an error with an indication of WSAECONNREFUSED.

    nBacklog is an optional parameter that specifies the maximum length of the queue of pending connections. If this value is SOMAXCONN (the default), then the underlying service provider responsible for this socket will set the backlog to a maximum "reasonable" value. There is no standard provision to find out the actual backlog value.

    Subsequent calls to :Listen will update the current backlog for the listening socket. If there are more pending connections than the new backlog value, the excess pending connections will be reset and dropped. :Accept([oSocketClass]) -> oClientSocket | NIL This method is used by a server process for accepting incoming connections. The method extracts the first connection in the queue of pending connections and then creates a new socket object that is bound to the extracted connection. The newly created socket inherits most of it's properties from the parent (this socket) and is the socket that will handle the actual communication with the remote process.

    The optional parameter oSocketClass can be used to provide a reference to the class function from which the new socket object will be instantiated. If oSocketClass is NIL, then the client socket will be created based on one of the following conditions: (1) if the parent (this socket) is derived from either xbServer or xbHTTPServer, the client socket will be instantiated from the class object referenced by the server's :WorkerClass property (usually xbSocketThread or xbHTTPThread), (2) otherwise the new socket will be instantiated from xbSocket.

    If the socket is marked as blocking (see :SetBlockingMode) and there are no pending connections on the queue, then the :Accept method will block the calling routine until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, :Accept returns NIL. After the successful completion of :Accept, the method returns a new socket object. The original socket remains open and listens for new connection requests. :Recv([nBytes], [nFlag], [cBuffer], [nDelayTime]) -> cReceived | NIL Read incoming data. Calling :Recv on a connection-oriented socket (eg. SOCK_STREAM), will return as much information as is currently available; up to nBytes. If the socket has been configured for in-line reception of out-of-band data (see :OOBInLine) and out-of-band data is available; only out-of-band data will be returned. The application can use :CatMark to determine whether any more out-of-band data remains to be read.

    For message-oriented or connectionless sockets (eg. SOCK_DGRAM), data is extracted from the first enqueued datagram (message); up to nBytes. If the datagram or message is larger than nBytes, the first part of the datagram is returned, and :ErrorCode will be set to WSAEMSGSIZE. For unreliable protocols (eg. UDP) the excess data is lost; for reliable protocols, the data is retained by the service provider until it is successfully read by calling :Recv with a large enough buffer. If the socket is not connected, the network address of the peer that sent the data will be copied into the :RemoteAddr and :RemotePort ivar.

    If there is no incoming data available and the socket is in blocking mode (see :SetBlockingMode), then :Recv will block the calling routine and wait for data to arrive. If the socket is nonblocking and the input queue is empty, :Recv returns a zero length string and :ErrorCode is set to WSAEWOULDBLOCK. After successfully reading data from the input queue :Recv returns a string containing the data read. If an error occurs, other than the ones specified above, the method returns NIL. The number of bytes read is saved in the :BytesReceived ivar and a cumulative total in :RecvCount. Parameters: nBytes The number of bytes to read from the input queue. If not specified, nBytes will default to 1460 bytes or if supplied; the size of cBuffer. nFlag Specifies the way data will be read from the input queue. The following options defined in Xb2NET.CH are available:
    MSG_NORMAL - Read incoming data and remove it from the input queue (this is the default).
    MSG_PEEK - Peek at the incoming data but do not remove it from the input queue.
    MSG_OOB - Process out-of-band data. cBuffer An optional character string buffer that will be used to receive data into. If supplied, it must be passed by reference and it's size must be greater than or equal to nBytes. If nBytes is NIL, then the method will continue reading until cBuffer is full. If :Recv is called continuously (eg. in a loop), then it's good programming practice to receive into a static buffer since it results in more efficient memory usage. nDelayTime Specifies an optional delay period in milliseconds to hold-off reading from the input queue until nBytes is available to be read. This can be useful when the peer is transmitting large amounts of data over a slow network since it will result in more efficient buffer and memory usage on the host machine.

    The delay will persist as long as data is being received and the number of bytes in the receive buffer is less than nBytes. The method checks the receive buffer every 20 ms, if no additional data is received within that time, it will read the data received so far and return to calling routine even if the dalay time has not yet expired. This parameter is only applicable on a connection-oriented socket. :RecvFile( xFile, [nBytesToRecv], [nBytesPerRecv] ) -> nBytesReceived | SOCKET_ERROR Read incoming data and save it into a file. For additional information on how data is read from the input queue, see :Recv above. Parameters: xFile The file where received data is saved can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is provided, then received data will be saved starting at the current file pointer offset. On return, the file pointer will be positioned on the last byte written to the file. If a file name is specified instead of a numeric file handle, then the file will be closed. nBytesToRecv Number of bytes to read. The method completes when it has read the specified number of bytes, or when an error occurs, whichever occurs first. Set nBytesToRecv to zero or NIL in order to continue reading into file until socket is disconnected. nBytesPerRecv Data is read from the input queue in discrete blocks. This parameter specifies the number of bytes of data read per block. Set nBytesPerRecv to zero or NIL to select the default read size. This parameter is useful for message protocols that have limitations on the size of individual read requests. :RecvLine([cEOLMarker], [nMaxBytes]) -> cReceived | NIL Read incoming data on a connection-oriented socket (eg. SOCK_STREAM) until cEOLMarker is reached or if specified; nMaxBytes have been read. If cEOLMarker is not supplied it defaults to CR+LF (Chr(13) + Chr(10)). See :Recv for additional information. :Send(cBuffer, [nFlag], [xToAddr], [nToPort], [nBytesToSend]) -> nBytesSent | SOCKET_ERROR Send data to a specific destination or a connected peer. If the socket is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound. The successful completion of a :Send does not indicate that the data was successfully delivered.

    For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, (see :MaxMessageSize). If the data is too long to pass atomically through the underlying protocol, :ErrorCode will be set to WSAEMSGSIZE, and no data is transmitted.

    If no buffer space is available within the transport system to hold the data to be transmitted, :Send will block unless the socket has been placed in a nonblocking mode. On nonblocking, stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server systems. Parameters: cBuffer This is the buffer containing the data to be transmitted. nFlag Specifies the way in which the call is made. The following options defined in Xb2NET.CH are available:
    MSG_NORMAL - Read incoming data and remove it from the input queue (this is the default).
    MSG_DONTROUTE - Specifies that the data should not be subject to routing.
    MSG_OOB - Send out-of-band data (SOCK_STREAM only). xToAddr This parameter is only valid when used with connectionless, message-oriented sockets. It is ignored if :SockType is SOCK_STREAM, otherwise xToAddr can be any valid address in the socket's address family, including a broadcast address. However, to send to a broadcast address, :Broadcast(.t.) must be set first. Otherwise, :Send will fail with the :ErrorCode WSAEACCES. For TCP/IP, an application can send to any multicast address without becoming a group member. If a message-oriented socket has been previously connected to a specific address (using :Connect), specifying xToAddr will override the default destination address for this datagram only. The address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (ex. 127.0.0.1). Default is INADDR_BROADCAST. nToPort This parameter is only valid when used with connectionless, message-oriented sockets. It is ignored if :SockType is SOCK_STREAM, otherwise it specifies the numeric port number on the remote computer to send to. Default is zero. nBytesToSend The number of bytes to send. If the parameter is NIL or not provided, the default is to send the entire contents of cBuffer. :SendFile(xFile, [nBytesToSend], [nBytesPerSend]) -> nBytesSent | SOCKET_ERROR Transmit file data over a connected socket. The method returns an integer numeric value indicating the number of bytes transmitted, or SOCKET_ERROR if an error occurred. NOTE: The successful completion of a :SendFile does not necessarily indicate that the data was successfully delivered to the remote peer. Parameters: xFile The file to be transmitted can be specified as either a numeric handle as returned by FOpen() or FCreate(), or as a character string denoting the file name and path. NOTE: If a file handle is specified, then the file data will be transmitted beginning at the current file pointer offset. To transmit the entire file make sure that the file pointer is set to the beginning of the file. nBytesToSend Number of file bytes to transmit. The method completes when it has sent the specified number of bytes, or when an error occurs, whichever occurs first. Set nBytesToSend to zero or NIL in order to transmit the entire file. nBytesPerSend The file contents are transmitted in discrete blocks of data. This parameter specifies the number of bytes of data sent per block. Set nBytesPerSend to zero or NIL to select the default send size. This parameter is useful for message protocols that have limitations on the size of individual send requests. :Shutdown([nHow], [lShutdownClients]) -> lSuccess This method is used on all types of sockets to disable reception and/or transmission of data. Note that :Shutdown does not close the socket. A socket can only be closed by executing the :Close or :Destroy methods. The method returns .T. when the shut down operation is successful, otherwise .F. is returned.

    If the nHow parameter is set to SD_SEND, subsequent calls to :Send will be disallowed. If it is set to SD_RECEIVE (the default), subsequent calls to :Recv are disallowed. If it is set to SD_BOTH then both sends and receives are disabled.

    If the socket is in a listening state and there are connected clients, the client sockets can be shut down by specifying .T. for lShutdownClients default is .F. :SSLShutdown() -> self Send an SSL/TLS shutdown request to the remote peer and wait for an acknowledgement that the peer has shut down. If there is no SSL connection open on the socket, then the method will return immediately. :Close([lCloseClients]) -> lSuccess Closes socket and releases allocated system resources. Any pending blocking, asynchronous calls issued by any thread in this process are canceled without posting any notification messages. If the socket is in a listening state and there are connected clients, the client sockets can also be closed by specifying .T. for lCloseClients, default is .F. The semantics of :Close are affected by the :LingerTimeout option, see :LingerTimeout for additional information. A socket that has been closed can later be reopened by using the :Open method. :Destroy([lDestroyClients]) -> lSuccess This method will first execute a :Close and if successful, the class instance will be dereferenced from the class object list. If the socket is in a listening state and there are connected clients, the client socket objects can also be destroyed by specifying .T. for lDestroyClients, default is .F. Configuration :Broadcast([lSet]) -> lSet Enable/disable transmission of broadcast messages on the socket. When lSet is not specified, the method will return the current setting. Default is .F. :Debug([lSet]) -> lSet Enable/disable recording of debugging information. When lSet is not specified, the method will return the current setting. The mechanism for generating the debug information and the form it takes are dependant on the winsock service provider and are beyond the scope of this manual. Default is .F. :KeepAlive([lSet]) -> lSet Enable/disable use of "keep-alive" packets on TCP connections. When lSet is not specified, the method will return the current setting. Default is .F. :LingerTimeout([nSec]) -> nSetting This method controls the action taken when unsent data is queued on a socket and a :Close or :Destroy is performed. The following types of behavior can be obtained:

    nSec is specified as a negative value: Graceful shutdown, immediate return - allowing the shutdown sequence to complete in the background. Although this is the default behavior, the application has no way of knowing when (or whether) the graceful shutdown sequence actually completes.

    nSec is specified as zero: Abortive shutdown sequence, immediate return from :Close

    nSec is specified as a positive value: Graceful shutdown, delaying return until either shutdown sequence completes or the specified time interval elapses. If the time interval expires before the graceful shutdown sequence completes, an abortive shutdown sequence occurs, and :Close returns.

    When nSec is not specified, the method will return the current setting. :OOBInLine([lSet]) -> lSet Enable/disable the reception of out-of-band data in the normal data stream. When lSet is not specified, the method will return the current setting. Default is .F. :RecvBufferSize([nSize]) -> nBytes Get/set buffer size for receives. When nSize is not specified, the method will return the current size of the receive buffer in bytes. :RecvTimeout([nMilliSec]) -> nTimeout Get/set maximum number of millisecs to wait when receiving data from a remote connection (may not work with all stack implementations). This option can be set on any type of socket in any state. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :ReuseAddr([lSet]) -> lSet By default, a socket cannot be bound to a local address that is already in use. Sometimes, however, it can be necessary to reuse an address in this way. Because every connection is uniquely identified by the combination of local and remote addresses, there is no problem with having two sockets bound to the same local address as long as the remote addresses are different. In order to allow the socket to be bound to an address that is already in use, the application should call this method by specifying lSet as .T. before issuing a :Bind call. Setting or resetting the option after the :Bind has no effect on this or any other socket. When lSet is not specified, the method will return the current setting. Default is .F. :Route([lSet]) -> lSet Enable/disable routing; when disabled packets are sent directly to interface. When lSet is not specified, the method will return the current setting. Default is .T. (enable routing). :SendBufferSize([nSize]) -> nBytes Get/set buffer size for sends. When nSize is not specified, the method will return the current size of the send buffer in bytes. :SendTimeout([nMilliSec]) -> nTimeout Get/set maximum number of millisecs to wait when sending data to a remote connection (may not work with all stack implementations). This option can be set on any type of socket in any state. The default value is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is valid to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds. When nMilliSec is not specified, the method will return the current setting. :SetBlockingMode([lSet]) -> lSet Enable/disable blocking mode on the socket. When enabled (which is the default), the process executing :Accept or sending/receiving data will wait for the operation to complete. If not specified lSet defaults to .T. :SetCallBack([xCallBack]) -> self Register an object or codeblock to receive callback events. If a callback has already been registered, it can be cancelled by setting xCallBack to NIL.

    When xCallBack is provided as an object, the object must be inherited from the Xbase++ XbpPartHandler class. In this case, the xbSocket class will place events of type xbeP_xbSocket into the Xbase++ event queue. These events can be read (asynchronously) from the event queue by using the standard Xbase++ function AppEvent(). For an example showing how to define asynchronous callbacks, please see: xbFTPClient:SetCallBack.

    When xCallBack is provided as a codeblock, the user codeblock will be executed (synchronously) whenever an event occurs within the xbSocket instance.

    Two message parameters are provided to the AppEvent() function / user codeblock. The first parameter will be an integer numeric status code defined in Xb2NET.CH with the prefix SOCK_ST_*, the second parameter will contain a reference to the socket object.

    Example (synchronous callback): oSock:SetCallBack({|a,b|DisplayStatus(a,b)}) // codeblock executes synchronously

    PROCEDURE DisplayStatus(nStatus, x)
      Static oXbp
      Local oWindow

      // create status CRT window if it does not exist
      if oXbp == nil
        oXbp := XbpCrt():new(,,{372,165},15,33,"STATUS")
        oXbp:autoFocus := .F.
        oXbp:create()
      endif

      // display status info in separate CRT window
      oWindow := SetAppWindow(oXbp)
      if valtype(x) == "O" .and. x:isDerivedFrom("xbSocket")
        ? nStatus, x:SendCount, x:RecvCount
      else
        ? nStatus, x
      endif
      DispOutAt(0,0,"StatusCode SendCount RecvCount", "gr+,w")
      SetAppWindow(oWindow)
      Return
    :SetSSLContext([oSSLContext]) -> self Attach an xbSSLContext object, oSSLContext to this socket in order to secure communications. The socket must be of type SOCK_STREAM and it must not be connected or in a listening state when the xbSSLContext object is attached. If oSSLContext is NIL or no parameter is supplied, then the present SSL/TLS connection (if there is one) will be shut down and it's corresponding xbSSLContext will be detached from this socket. :TCPNoDelay([lSet]) -> lSet Enable/disable use of Nagle algorithm for sends. The Nagle algorithm is disabled when lSet is .T. (and vice versa). The process involves buffering :Send data when there is unacknowledged data already "in flight" or buffering :Send data until a full-size packet can be sent. For most application protocols the Nagle Algorithm can deliver significant performance enhancements. However, in some cases this algorithm can impede performance, and :TCPNoDelay can be used to turn it off. These are applications where many small messages are sent, and the time delays between the messages are maintained. When lSet is NIL, the method returns the current setting. Status :ErrorMessage() -> cErrorText Return error description of most recent WinSock error. :CatMark() -> lNoOOBDataWaiting Check if out-of-band data is waiting to be read. This applies only to a stream oriented socket (eg. SOCK_STREAM) that has been configured for in-line reception of out-of-band data; see :OOBInLine. If no out-of-band data is waiting to be read, the operation returns .T. Otherwise, it returns .F., and the next :Recv or :RecvLine performed on the socket will retrieve some or all of the data preceding the "mark". The application should use :CatMark to determine whether any data remains. :GetReadCount() -> nBytesAvailable Use to determine the amount of data pending in the network's input buffer that can be read from the socket. If the socket is stream oriented (eg. SOCK_STREAM), this method returns the amount of data that can be read in a single call to the :Recv method; this might not be the same as the total amount of data queued on the socket. If the socket message oriented (ex. SOCK_DGRAM), this method returns the size of the first datagram (message) queued on the socket. :isListening() -> lListening Check if socket is in listening mode. :isConnected() -> lConnected Check if a connected socket is still alive. :isSecure() -> lSecureConnecton Check if there is a secure SSL/TLS connection open. :MaxMessageSize() -> nBytes Maximum size of a message for message-oriented socket types (eg., SOCK_DGRAM). Has no meaning for stream oriented sockets. :RemoteName() -> cHostName | NIL Return host name of remote machine or NIL if the remote host name cannot be resolved. :UpTime() -> {nDays, nHrs, nMin, nSec} Returns a one dimensional array specifying amount of time socket has been open. The following array constants available in Xb2NET.CH provide access to the individual array elements:

    UPTIME_DAY - number of days
    UPTIME_HRS - number of hours
    UPTIME_MIN - number of minutes
    UPTIME_SEC - number of seconds Child/Parent Relation :AddClient(oSocket) -> self Create a parent/child relation between this socket (the parent) and oSocket (the child). A list of all client sockets is available in the :ClientList ivar. :DelClient(oSocket) -> self Remove parent/child relation between this socket and oSocket. A list of all client sockets is available in the :ClientList ivar. :SetParent([oParent]) -> self Create or remove a parent/child relation between this socket (the child) and oParent (the parent). If oParent is not specified, the link is removed, otherwise a link is created. A reference to the parent socket is stored in the :Parent ivar.


    xbSocket: Object properties

    :Handle readonly/numeric Numeric socket descriptor as used by winsock. :SSLHandle readonly/numeric Numeric descriptor of SSL object as used by OpenSSL. :AddrFamily readonly/numeric The socket's address family. #define constants: AF_* :SockType readonly/numeric The socket type. #define constants: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET :Protocol readonly/numeric The protocol used. #define constants: IPPROTO_* :LocalAddr readonly/numeric The numeric IP address of the local machine in network byte order that the socket is bound to. :LocalPort readonly/numeric The numeric port number on the local machine that the socket is bound to. :RemoteAddr readonly/numeric The numeric IP address of the remote machine in network byte order that the socket is connected to. :RemotePort readonly/numeric The numeric port number on the remote machine that the socket is connected to. :BytesReceived readonly/numeric Number of bytes received by last :Recv or :RecvLine call. :BytesSent readonly/numeric Number of bytes transmitted by last :Send call. :RecvCount readonly/numeric A cumulative total of number of bytes received on this socket since it was opened. :SendCount readonly/numeric A cumulative total of number of bytes sent on this socket since it was opened. :ErrorCode exported/numeric Most recent result code returned by winsock. :onError exported/codeblock Provides the ability to optionally specify a codeblock that will be evaluated when a winsock error occurs. When evaluated three parameters are passed to the codeblock (1) a reference to socket object responsible for the error, (2) the OpenSSL or Winsock error code number, and (3) a logical indicating if the error originated from the OpenSSL library (.T.) or from WinSock (.F.). Example:

    oSocket:onError := {|oOwner,nErrCode,isSSL| xbErrorLog(oOwner,nErrCode,isSSL)} :isEncoded exported/logical Provides the ability to automatically encode and decode data transmitted on the socket. When set to .T., all inbound data will be decoded (see :Decode) and all outbound data will be encoded (see :Encode). This is quite a powerful feature since it means that data can be transparently "massaged" before it is passed on. For example, using the following codeblocks, any datatype can be sent and received between Xbase++ applications. Send an array, receive an array; send a codeblock, receive a codeblock... you can imagine the possibilities.

    oSocket:isEncoded := .T.
    oSocket:Encode := {|xVal| Var2Bin(xVal)}
    oSocket:Decode := {|cBuffer,nBytes| Bin2Var(Left(cBuffer,nBytes))}
    :Encode exported/codeblock Optional codeblock that is automatically evaluated to encode outbound data when :isEncoded is .T. If no user codeblock is supplied but :isEncoded is .T. a default built-in encryption algorithm will be used. When evaluated two parameters are passed to the codeblock (1) a reference to the value being transmitted, (which may be any data type), and (2) if the value to be transmitted is a string, this parameter will contain the length of the string, otherwise it will be -1. See :isEncoded for more information. :Decode exported/codeblock Optional codeblock that is automatically evaluated to decode inbound data when :isEncoded is .T. If no user codeblock is supplied but :isEncoded is .T. a default built-in decryption algorithm will be used. When evaluated two parameters are passed to the codeblock (1) a text buffer of the data received, and (2) the number of bytes received. See :isEncoded for more information. :Parent readonly/object Reference to parent socket or NIL if this socket has no parent. :ClientList readonly/array A one dimensional array listing all active client sockets either created through this socket's :Accept method or :AddClient method. :DateStarted readonly/date Date socket opened. :TimeStarted readonly/numeric Time socket opened (seconds after midnight). :ThreadID readonly/numeric Xbase++ thread ID number where socket was created. :SSLContext readonly/object Reference to the xbSSLContext instance, or NIL if no SSL context has been assigned. :Cargo exported/any data type Used to attach additional information to the object as required by the programmer.


    xbServer     inherited from xbSocket and Thread

    This class implements a generic socket listener that spawns an xbSocketThread when a client connection is accepted.

    xbServer: Class methods

    :New([xLocalAddr], [nPort], [oSSLContext]) -> self Creates a new instance of the xbServer class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbServer class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of it's superclasses. For information on the Thread class, please consult your Xbase++ documentation. All parameters are optional. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (ex. 127.0.0.1). If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default). This allows the underlying service provider to use any appropriate network address. nPort This is the numeric port number on the local computer to bind the socket to. If not supplied, the default is 23 (or 992 when using an xbSSLContext) which are the standard port numbers for Telnet and TelnetS respectfully. oSSLContext In order to secure data transmission and possibly authenticate clients, an instance of xbSSLContext can be passed using this parameter.

    xbServer: Object methods

    :ActiveConnections() -> nConnectionsOpen Returns the total number of connections currently open. :SetBacklog([nBacklog]) -> nBacklog Get/set the maximum length of the queue of pending connections. If this value is SOMAXCONN (the default), then the underlying service provider responsible for this socket will set the backlog to a maximum "reasonable" value. There is no standard provision to find out the actual backlog value however if nBacklog is not specified, the method will return the current backlog setting (which may not necessarily be the actual backlog value set by the service provider).

    If the server is running and the socket is in a listening state, calls to :SetBacklog will update the current backlog for the socket. If there are more pending connections than the new backlog value, the excess pending connections will be reset and dropped. :Start() -> lSuccess Start running the server in its own thread. If the server thread is started successfully, the method returns .T., otherwise it returns .F. Once started, the server will begin listening for incoming connections on the address and port specified when the xbServer object was instantiated. A new xbSocketThread object will be instantiated and bound to each accepted connection. It is the xbSocketThread object that is responsible for handling the actual communications with the client.

    The server will continue running in it's own thread and listening for incoming connections until it is terminated by calling the :Stop method. Once the server has stopped, it can be restarted by calling :Start. As long as the server thread is active, repeated calls to :Start are ignored. :Stop([nTimeOut]) -> lSuccess Close server socket and signal server plus all connected clients to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbServer thread (including all connected clients) to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbServer thread and all connected clients have terminated. The method returns .F. if the server could not be terminated within the specified time interval, otherwise it returns .T.


    xbServer: Object properties

    Status :ConnectCount exported/numeric Total number of connections accepted since server started. This is not the same as :ActiveConnections. :ThreadID readonly/numeric Numeric ID of thread. Configuration :MaxConnections exported/numeric | NIL Maximum allowable number of concurrent client connections. A value of NIL (the default) does not impose a limit on the number of concurrent client connections. See :onMaxConnect for additional information. :SleepTime exported/numeric Amount of time in 1/100ths of a second to idle the xbServer thread after accepting a new connection. :WorkerClass exported/reference to class function This instance variable provides a reference to a client socket handler class function. By default :WorkerClass contains a reference to the xbSocketThread class function, however it can be used to define a custom client socket handler to be used instead of xbSocketThread. When instantiated, the init method of the worker class will receive two parameters: (1) a reference to the parent server object, and (2) a numeric handle of the newly created socket. If a custom class is used, it should be derived either from the xbSocket and Thread classes or from the xbSocketThread class.

    Example: oServer:WorkerClass := MyClientHandler()

    CLASS MyClientHandler FROM xbSocketThread
    EXPORTED:
    INLINE METHOD Init(oParent, nHandle)
      ::xbSocketThread:init(oParent, nHandle)
      // add your custom init code here
      Return self

    // The :Execute method is where all the work is done, add your custom code here
    INLINE METHOD Execute()
      Local cRecv := ::Recv()
      if ::BytesReceived > 0
        ::Send( cRecv ) // just echo back whatever we receive
      endif
      Return self

    ENDCLASS
    Event Handling :atEnd exported/character | codeblock | NIL Can be used to provide an optional code block or a character string containing the name of a globally visible function that will be executed before the thread terminates. This property will be inherited by worker threads. :onConnect exported/codeblock | NIL This is the codeblock that will be executed when a client connection is accepted. If :onConnect is NIL, then the server will simply echo back to the client all received data (this is the default behavior). For the server to do anything useful, a codeblock must be attached to this ivar. The purpose of this codeblock is to receive the client request, process as required and send back a response. The connected socket can be kept open as long as required or until the client disconnects.

    It is important to note that the code encapsulated by the codeblock will be executed in a new xbSocketThread. This thread remains active as long as the socket connection is open. It may be terminated by closing the socket connection (from either the server or client sides) and exiting the procedure. The client socket will be automatically shut down and closed just before the thread terminates.

    Example: oServer:onConnect := {||ServiceClient()}

    Procedure ServiceClient()
      Local cRecv, cSend
      Local oClient := ThreadObject()
      Local cTempFile := "~" + NTrim(oClient:Handle) + ".tmp"

      while (cRecv := oClient:RecvLine()) != NIL
        cSend := cRecv
        cRecv := StrTran(StrTran(cRecv,chr(10),""),chr(13),"")
        RunShell( "/C " + cRecv + " > " + cTempFile,,.f.,.t. )
        cSend += MemoRead(cTempFile)
        FErase(cTempFile)
        if oClient:Send( cSend ) < 0
          exit
        endif
      end
    Return
    :onMaxConnect exported/character | codeblock | NIL The :onMaxConnect ivar determines what happens when :ActiveConnections reaches :MaxConnections. The following options are possible:

    NIL - do not accept any more connections until an existing client connection is closed.
    STRING - accept new connection, receive request, send string contained in :onMaxConnect to client and immediately close connection.
    CODEBLOCK - accept new connection, create new xbSocketThread object and execute codeblock contained in :onMaxConnect within this new thread.

    Example: oServer:MaxConnections := 50
    oServer:onMaxConnect := "Too many connections, please try later..."
    // or
    oServer:onMaxConnect := {||SendBusy()}

    Procedure SendBusy()
      Local oThread := ThreadObject()
      oThread:Recv()
      if oThread:BytesReceived > 0
        oThread:Send( "Too many connections, please try later...")
      endif
    Return


    xbHTTPServer     inherited from xbServer

    This class implements an HTTP 1.1 listener that spawns an xbHTTPThread when a client connection is accepted.

    xbHTTPServer: Class methods

    :New([xLocalAddr], [nPort], [oSSLContext]) -> self Creates a new instance of the xbHTTPServer class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbHTTPServer class is inherited from xbServer which in turn is inherited from xbSocket and Thread. An instance of this class will therefore have access to all methods and properties of it's superclasses. For information on the Thread class, please consult your Xbase++ documentation. All parameters are optional. Parameters: xLocalAddr The local address can be specified either as a numeric address in network byte order, or as an IP address in form of a dotted octet string (ex. 127.0.0.1). If an application does not care what local address is assigned, specify the constant value INADDR_ANY (the default). This allows the underlying service provider to use any appropriate network address. nPort This is the numeric port number on the local computer to bind the socket to. If not supplied, the default is 80 (or 443 when using an xbSSLContext) which are the standard port numbers for HTTP and HTTPS respectfully. oSSLContext In order to secure data transmission and possibly authenticate clients, an instance of xbSSLContext can be passed using this parameter.


    xbHTTPServer: Class properties

    :ServerName readonly/character Contains server name and version number, eg. Xb2.NET/0.0.54

    xbHTTPServer: Object methods

    :RootDir( [cPath] ) -> cPath Get/set default root directory for HTTP server. If not specified, the default is the current path where the webserver application is running. :StatusText( nStatusCode ) -> cStatusText Return a text message corresponding to an HTTP response status code. An HTTP status code is a 3-digit integer where the first digit defines the class of response. There are 5 values for the first digit (the remaining two digits are not categorized):

    1xx: Informational - Request received, continuing process
    2xx: Success - The action was successfully received, understood, and accepted
    3xx: Redirection - Further action must be taken to complete the request
    4xx: Client Error - The request contains bad syntax or cannot be fulfilled
    5xx: Server Error - The server failed to fulfill an apparently valid request


    xbHTTPServer: Object properties

    Configuration :AllowDelete exported/logical When set to .T., client is permitted to delete a file on the HTTP server by using the DELETE method. The target file is specified in the URI request. This property is ignored when the :onDELETE ivar contains a codeblock. The default value is .F. :AllowTrace exported/logical When set to .T., client is permitted to submit HTTP TRACE requests. The default is .F., ie. the TRACE command is disabled. The HTTP TRACE command is used for testing and debugging. When an HTTP TRACE request is sent to a web server that supports it, that server will respond echoing the data that is passed to it, including any HTTP headers. It is recommended that TRACE be only supported in a test environment since it is theoretically possible for a client to use HTTP TRACE for cross-site-scripting attacks. :AllowUpload exported/logical When set to .T., client is permitted to upload a file to the HTTP server by using the PUT method. The target file is specified in the URI request, with the file contents contained within the body of the request. This property is ignored when the :onPUT ivar contains a codeblock. The default value is .F. :CompressedFilePrefix exported/character Specifies the file prefix to be used when saving temporary compressed versions of files found within :RootDir.

    Web server files are automatically compressed as they are requested. In order to save CPU cycles for future requests, a copy of the compressed file is saved within the same directory using a hidden attribute and a unique file name prefix. When a compressed version already exists, the server will compare the timestamp with the original file to determine if the compressed version is stale. The default file name prefix used is "~", eg:

    Original file: d:\www_root\index.htm
    Temporary compressed version (hidden): d:\www_root\~index.htm :CompressHttp10 exported/logical This property enables or disables compression for requests containing an HTTP 1.0 version number.

    HTTP 1.0, as described in RFC 1945, provides a minimal level of support for certain types of compression. However, some confusion exists around HTTP 1.0 compression, especially with regard to proxy servers. To minimize the chance of inappropriately returning a compressed file to a client that cannot decompress it, you can use this property to disable compression in questionable scenarios.

    The default value of this property is .F., meaning that compression is disabled for HTTP 1.0 requests. :CompressLevel exported/numeric Sets the default compression level to be used when compressing HTTP content. Acceptable values are between 0 and 9, where 0 = no compression and 9 = highest compression. Although a higher compression level will result in smaller data, it will also result in higher CPU utilization. Best performance can be achieved by setting the compression level to 6 or 7. The default is 0 or no compression.

    NOTE: Data compression is implemented by the open-source ZLIB.DLL library that uses the "deflate" method as documented in RFC-1950. :CompressTypes exported/character Specifies a list of HTTP content MIME types that will be automatically compressed when compression is enabled (:CompressLevel > 0). The default is: "text/html;text/xml;text/plain;text/sgml;text/rtf;text/vbscript;application/x-javascript;" :IndexFile exported/character | character array | NIL This is the default file that will be returned to the client when no resource is requested. A single value can be specified as a character string or multiple values as an array of character strings. When multiple values are specified, the server will search the root directory for the first match. The default is: {"default.htm", "default.html", "index.htm", "index.html", "main.htm", "main.html"}

    Setting :IndexFile to NIL will cause all client requests with an empty URI path component to be routed to the :onGET codeblock. :SessionTag exported/character This is the tag name that will be used to track a session-state between the server and client. Each session is identified by an ID that must be communicated between the server and client with each request-response state. By default, an xbHTTPThread object will use cookies to maintain this session ID between states. However, this may not always work since a client may have cookie support turned off. In such cases, the session ID can be communicated between states by embedding the session ID in the URL (as a query parameter) or as a hidden form variable within an HTML page. Each instance of the HTTP server can have a different session tag identifier. The default is: _SID :SessionTimeout exported/numeric Inactive session timeout in minutes. An inactive client xbSession object will be maintained in memory for a minimum :SessionTimeout minutes. The default is 150 minutes (2.5 hours). :SOAPParser exported/reference to class function This instance variable provides a reference to a SOAP parser class function. By default :SOAPParser contains a reference to the xbSOAPEnvelope class function, however it can be used to define a custom SOAP parser to be used instead of xbSOAPEnvelope. When instantiated, the init method of the SOAP parser will receive a single character string parameter containing the SOAP envelope. If a custom class is used, it should at minimum contain a GetVar method that returns the value of a SOAP parameter.

    Example: oServer:SOAPParser := MySOAPParser()

    CLASS MySOAPParser
    EXPORTED:
    INLINE METHOD init( cXMLString )
      // code to parse the XML SOAP envelope
      Return self

    INLINE METHOD GetVar( cName )
      // code to return value of input parameter cName
      Return xValue

    ENDCLASS
    :TLog exported/object | NIL Provides a reference to the object that will be used for logging client requests. To enable transaction logging, set :TLog to an instance of the xbTLog class. To disable or pause logging temporarily, set :TLog to NIL.

    Example: oTLog := xbTLog():new()
    oTLog:SetDir(".\LogFiles")

    oServer := xbHTTPServer():new()
    oServer:TLog := oTLog
    :WorkerClass exported/reference to class function This instance variable provides a reference to a client socket handler class function. By default :WorkerClass contains a reference to the xbHTTPThread class function, however it can be used to define a custom client socket handler to be used instead of xbHTTPThread. When instantiated, the init method of the worker class will receive two parameters: (1) a reference to the parent server object, and (2) a numeric handle of the newly created socket. If a custom class is used, it should be derived either from the xbSocket and Thread classes or from the xbHTTPThread class.

    Example: oServer:WorkerClass := MyHTTPHandler()

    CLASS MyHTTPHandler FROM xbHTTPThread
    EXPORTED:
    INLINE METHOD Init(oParent, nHandle)
      ::xbHTTPThread:init(oParent, nHandle)
      // add your custom init code here
      Return self

    // The :Execute method is where all the work is done, add your custom code here
    INLINE METHOD Execute()
      Local oRequest := ::HTTPRequest
      Local oResponse := ::HTTPResponse

      while !oRequest:Recv()
        do case
        case oRequest:Command == "GET"
          // code to generate GET response
        case oRequest:Command == "POST"
          // code to generate POST response
        case oRequest:Command == "HEAD"
          // code to generate HEAD response
        otherwise
          // send command not implemented status code
          oResponse:StatusCode := 501
        endcase
        oResponse:Send()
        if !oRequest:KeepAlive
          // client doesn't want to keep connection open
          ::Close()
        endif
        oResponse:Reset() // reinitialize object
      end
      Return self

    ENDCLASS
    Event Handling :FilterRequest exported/codeblock | NIL When supplied, this optional codeblock will be executed right after an HTTP request is received and prior to a response being generated. A :FilterRequest codeblock can be used to easily spy on all HTTP requests and if desired, modify the request prior to it being processed by the default HTTP handler. If supplied, the codeblock must return a logical value. A return value of .F. indicates that the codeblock has generated a response and no additional processing is required (ie. the request will not be processed by the default HTTP handler). A return value of .T. tells the default HTTP handler to process the request as usual. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example 1: oServer:FilterRequest := {|o|FilterRequest(o)}

    Function FilterRequest(oClient)
      QOut( oClient:HTTPRequest:StartLine )
      if "winnt" $ Lower(oClient:HTTPRequest:Path())
        // don't allow access to system dir
        oClient:HTTPResponse:ContentType("text/plain")
        oClient:HTTPResponse:Content := "The POLICE has been dispatched!"
        Return .F.
      endif
    Return .T.

    Example 2: The following function shows how to use :FilterRequest to do virtual hosting. It assumes that the hosted websites are organized as follows:

    /www_root/website1/...
    /www_root/website2/...
    /www_root/website3/...
    etc...


    For example if the 3 websites hosted are sqlexpress.net, xb2.net and alaska-software.com, then the directory structure will be as follows:

    /www_root/sqlexpress.net/...
    /www_root/xb2.net/...
    /www_root/alaska-software.com/...

    oServer:RootDir("/www_root")
    oServer:FilterRequest := {|o|VirtualHosting(o)}

    Function VirtualHosting(oClient)
      Local i
      Local cHost := Lower(oClient:HTTPRequest:Host())
      Local cPath := oClient:HTTPRequest:Path()

      // strip out port numbers
      if (i := At(':',cHost)) > 0
        cHost := Left(cHost,i-1)
      endif

      // modify requested path
      if cPath $ "/\" .or. Empty(cPath)
       cPath := "/index.htm"
      endif
      cPath := "/" + cHost + cPath
      oClient:HTTPRequest:Path(cPath)
    Return .T.
    :onDELETE exported/codeblock | NIL This is an optional codeblock that will be executed when a DELETE request is received. By default DELETE requests are rejected unless :AllowDelete is set to .T. or a custom codeblock is assigned to the :onDELETE ivar. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example: oServer:onDELETE := {|o|DeleteFile(o)}

    Procedure DeleteFile( oClient )
      Local cRootDir := oClient:Parent:RootDir()
      Local cFile := oClient:HTTPRequest:Path

      cFile := cRootDir + iif(Left(cPath,1)=="/", SubStr(cPath,2), cPath)
      oClient:HTTPResponse:ContentType("text/plain")
      if FErase(cFile) == 0
        oClient:HTTPResponse:Content := "File deleted"
      else
        oClient:HTTPResponse:Content := "Unable to delete file"
      endif
    Return
    :onGET exported/codeblock | NIL This is an optional codeblock that is used to process dynamic requests. Client requests that fall under this category include; (a) requests with a URI query component, and (b) requests with an empty URI path component and no :IndexFile defined. If a dynamic request is received, and no :onGET codeblock is defined, then the server will reply with a 404 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object. :onHTTPError exported/codeblock | NIL This is an optional codeblock that will be executed when a runtime error occurs while processing the HTTP request. If no custom codeblock is supplied, the default behavior is to log the error and return to the client a description of the error including callstack information. If a codeblock is supplied and a runtime error occurs within the connected client's xbHTTPThread, the codeblock will be evaluated with one parameter passed; a reference to the Xbase++ Error object. The function evaluated within the supplied codeblock must terminate with a Break(). If a character string is passed to the Break() function (as in the example below), then this string will be transmitted to the client. Alternatively, if an error object is passed, then the HTTP server will generate a corresponding reply.

    Example: oServer:onHTTPError := {|o|HTTPError(o)}

    Procedure HTTPError( oError )
      Local oClient := ThreadObject()
      Local cCRLF := chr(10)+chr(13)
      Local cResponse

      oClient:HTTPResponse:ContentType("text/plain")
      cResponse := "An error occurred in my Xbase++ web server:" + cCRLF +;
        iif(ValType(oError:subSystem) == "C", oError:subSystem, "???" ) + "/" +;
        iif(ValType(oError:subCode) == "N", Str(oError:subCode), "???" ) + cCRLF +;
        iif(ValType(oError:description) == "C", oError:description, "" )
      Break( cResponse )
    Return
    :onInvalidCommand exported/codeblock | NIL This is an optional codeblock that will be evaluated when a non-supported method is requested by the client. If no custom codeblock is supplied, the default behavior is to reply with an HTTP 501 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example: oServer:onInvalidCommand := {|o|MethodNotSupported(o)}

    Procedure MethodNotSupported( oClient )
      Local oResp := oClient:HTTPResponse
      oResp:StatusCode := 501
      oResp:ContentType := "text/plain"
      oResp:Content := "The requested method is not supported!"
    Return
    :onLog exported/codeblock | NIL An optional codeblock that will be evaluated immediately after a client request is completed and just before the transaction is to be logged. If supplied, the codeblock must return a logical value. A return value of .F. indicates an entry should not be added to the log file for this transaction. A return value of .T. indicates to proceed as usual; ie. if logging is enabled (see :TLog), then the transaction will be logged.

    This codeblock can therefore be used to filter what gets logged to the transaction log file and/or to perform custom logging. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example: oServer:onLog := {|o|OnLog(o)}

    Function OnLog( oClient )
      if oClient:InetNtoA(oClient:RemoteAddr) == "127.0.0.1"
        // don't log requests originating from localhost
        Return .F.
      endif
    Return .T.
    :onNotFound exported/codeblock | NIL This is an optional codeblock that will be evaluated when a requested resource is not found. If no custom codeblock is supplied, the default behavior is to reply with an HTTP 404 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example: oServer:onNotFound := {|o|FileNotFound(o)}

    Procedure FileNotFound( oClient )
      Local oReq := oClient:HTTPRequest
      Local oResp := oClient:HTTPResponse

      if oReq:Path == "/~5" .or. oReq:Path == "\~5"
        // redirect user to the new location
        oResp:Location := "http://www.SomeOtherLocation.com"
        oResp:StatusCode := 301
      else
        oResp:StatusCode := 404
        oResp:ContentType := "text/plain"
        oResp:Content := "The requested file is not found!"
      endif
    Return
    :onPOST exported/codeblock | NIL This is an optional codeblock that is used to process POST commands. If a POST command is received, and an :onPOST codeblock is not defined, then the server will reply with a 501 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object. :onPUT exported/codeblock | NIL This is an optional codeblock that will be executed when a PUT request is received. By default PUT requests are rejected unless :AllowUpload is set to .T. or a custom codeblock is assigned to the :onPUT ivar. When evaluated, the codeblock will receive one parameter; a reference to the connected xbHTTPThread object. See :onDELETE for an example. :onSessionClose exported/codeblock | NIL An optional codeblock that will be executed just before a client xbSession object is closed. When executed, one parameter is passed to the codeblock; a reference to the array containing the terminated session's data. :onSOAP exported/codeblock | NIL This is an optional codeblock that is used to process SOAP requests. If a SOAP request is received, and an :onSOAP codeblock has not been assigned, then the :onPOST codeblock will be evaluated. If that is also not defined, then the server will reply with a 501 status code. When evaluated, the supplied codeblock will receive one parameter; a reference to the connected xbHTTPThread object.

    Example: oServer:onSOAP := {|o| SOAPHandler(o)}

    Procedure SOAPHandler( oClient )
      Local cAction, oSOAPReq, oSOAPResp

      // :HTTPRequest:Content contains an xbSOAPEnvelope instance
      oSOAPReq := oClient:HTTPRequest:Content
      // this is the action requested by the client
      cAction := oSOAPReq:Action
      // create another SOAP envelope object where we will write our response
      oSOAPResp := xbSOAPEnvelope():new()
      // tack on the word "Response" to the reply envelope action, eg. "GetDateTimeResponse"
      oSOAPResp:Action := cAction + "Response"
     
      do case
      case cAction == "GetDateTime"
          oSOAPResp:SetVar("Date", Date())
          oSOAPResp:SetVar("Time", Time())
      case cAction == "SQLExecute"
          if Empty(oSOAPReq:GetVar("SQLStatement"))
            // the parameter is missing - send back an appropriate fault response.
            oSOAPResp:SetFault("Client", "SQLStatement parameter is missing")
          else
            nResult := DefaultSQLConnection():Execute( oSOAPReq:GetVar("SQLStatement") )
            oSOAPResp:SetVar("Result", nResult)
          endif
      otherwise
          // requested method is not available - send back a fault response.
          oSOAPResp:SetFault("Client", "Client request " + cAction + " not available")
      endcase

      // attach the SOAP response envelope to the HTTP response object
      // the Xb2.NET HTTP server will take care of the rest
      oClient:HTTPResponse:Content := oSOAPResp
    Return


    xbSocketThread     inherited from xbSocket and Thread

    This is the client thread that is spawned by xbServer when a connection with a peer is accepted. This "worker" thread will handle the request and send a response back to the connected client.

    xbSocketThread: Class methods

    :New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext]) -> self, or;
    :New(oParent, [nHandle]) -> self
    Creates a new instance of the xbSocketThread class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbSocketThread class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of it's superclasses. For information on the Thread class, please consult your Xbase++ documentation. For additional information on parameters, please see xbSocket:New(). All parameters are optional.

    xbSocketThread: Object methods

    :Start([cFuncName|bCodeBlock], [xParamList,...] ) -> lSuccess Starts the thread and executes the function cFuncName or evaluates the code block bCodeBlock within this thread. The parameters xParamList are passed on to the function or codeblock, respectively. If the thread is started successfully, the method returns .T., otherwise it returns .F.

    Once started the xbSocketThread will continue executing the code encapsulated by the specified function or codeblock until the socket is either disconnected by the remote host or, the thread is terminated by calling the :Stop method. Once the thread has stopped, it can be restarted by calling :Start. As long as the thread is active, repeated calls to :Start are ignored.

    If neither cFuncName or bCodeBlock are supplied, then the default behavior is to simply echo back to the connected peer all received data. The following is an example of a server type socket thread that implements two commands "GET TIME" and "GET DATE":

    Example: oSocket:Start("ServiceClient", oSocket)

    Procedure ServiceClient( oSocket )
      Local cRecv, cSend

      while (cRecv := oSocket:RecvLine()) != NIL
        cRecv := Upper(Left(cRecv,8))
        do case
        case cRecv == "GET TIME"
          cSend := Time()
        case cRecv == "GET DATE"
          cSend := DToS(Date())
        otherwise
          cSend := cRecv + " invalid command"
        endcase
        if oSocket:Send( cSend ) < 0
          exit
        endif
      end
    Return
    :Stop([nTimeOut]) -> lSuccess Close socket and signal socket thread to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbSocketThread thread to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbSocketThread thread has terminated. The method returns .F. if the thread could not be terminated within the specified time interval, otherwise it returns .T.


    xbSocketThread: Object properties

    :ThreadID readonly/numeric Numeric ID of thread.


    xbHTTPThread     inherited from xbSocket and Thread

    This is the client thread that is spawned by xbHTTPServer when a connection is accepted from a user agent (a browser). This "worker" thread is responsible for handling the client request and generating an appropriate xbHTTPResponse that will be sent back to the client. Typically, there is no need to instantiate this class in your code since it is automatically instantiated by the xbHTTPServer when a client connection is accepted.

    xbHTTPThread: Class methods

    :New([nAddrFamily], [nSocketType], [nProtocol], [oSSLContext]) -> self, or;
    :New(oParent, [nHandle]) -> self
    Creates a new instance of the xbHTTPThread class and allocates system resources to bind the newly created socket to a specific transport service provider. The xbHTTPThread class is inherited from xbSocket and Thread (part of Xbase++). An instance of this class will therefore have access to all methods and properties of it's superclasses. For information on the Thread class, please consult your Xbase++ documentation. For additional information on parameters, please see xbSocket:New(). All parameters are optional.

    xbHTTPThread: Object methods

    Life Cycle :Start([cFuncName|bCodeBlock], [xParamList,...] ) -> lSuccess Starts the HTTP server thread. If the thread is started successfully, the method returns .T., otherwise it returns .F. Once started the xbHTTPThread will continue running until the socket is either disconnected by the remote host or, the thread is terminated by calling the :Stop method. Once the thread has stopped, it can be restarted by calling :Start. As long as the thread is active, repeated calls to :Start are ignored. :Stop([nTimeOut]) -> lSuccess Close socket and signal socket thread to terminate. nTimeOut is an optional parameter specifying the maximum amount of time, in 1/100ths of a second, to wait for the xbHTTPThread thread to terminate. The default value of zero causes the current thread (where :Stop was called) to wait indefinitely until the xbHTTPThread thread has terminated. The method returns .F. if the thread could not be terminated within the specified time interval, otherwise it returns .T. Send Reply :NotFound() -> nBytesSent | SOCKET_ERROR Send default HTTP 404 error message to client. :Send([cBuffer], [nFlag], [xToAddr], [nToPort]) -> nBytesSent | SOCKET_ERROR Transmit data provided in cBuffer to connected client. If cBuffer is NIL or not specified, the method will send the data contained in the :HTTPResponse object (the other parameters are ignored). In most cases, there is no need to call this method since it will be called automatically by the xbHTTPThread object. For a detailed explanation of all parameters, see xbSocket:Send() :SendBusy() -> self Send default server busy response to client and close connection. :SendError(xError) -> self Send error message to client and close connection. xError can be either a string or an Xbase++ error object. :SendFile(cFile) -> nBytesSent | SOCKET_ERROR This method transmits a file to the client. The file path must be relative to the directory where the HTTP server application is running. If cFile is not found, then an HTTP 404 status code will be sent instead. State Management

    Session or state management involves saving persistent data across multiple HTTP requests. The automatic session management performed by the xbHTTPServer class relies on one "session" cookie containing a session ID which is passed to the client. Please note that session cookies are not permanent, they are removed from the client's browser cache when the last browser window (within the same process) is closed.

    Automatic session management using cookies is simple to implement since it requires no additional coding by the programmer. However if cookie support is turned off on the client side, then the session ID will be lost. To overcome this problem, some additional code will need to be added to the web application to keep track of the session ID. This is fairly easy to implement but unfortunately it cannot be done automatically by Xb2.NET. To keep track of the session ID without using cookies do this:

      1. Make sure to open a session at the start of each request. Sessions are opened by using one of the following methods:
        ThreadObject():OpenSession()
        ThreadObject():NewSession()
        ThreadObject():SetCargo()
        ThreadObject():GetCargo()
      2. Get the session ID by using ThreadObject():GetSessionHandle()
      3. Add a variable with the name "_SID" and a value returned by