Announcement

Collapse
No announcement yet.

SocketTools 6.0 Server API

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • SocketTools 6.0 Server API

    If there's any folks out there who are interested in developing TCP/IP servers, and would be interested in beta testing some code, we're looking for folks to work with our new server API.

    Basically, the idea is that it provides a very high level interface that makes it simple to create a scalable, event-driven, multi-threaded TCP/IP server. You don't need to worry about understanding how TCP works, how to create and manage threads, etc. The API takes care of all of that, and all you need to do is write code that responds to specific events. You could do the same sort of thing previous versions of our libraries, but it required that you implement a lot of "glue" code and have a good understanding of how threading works, synchronization functions, events and so on. With this new version, you generally just need to focus on the program logic, and not the networking stuff.

    The code to start a server is pretty simple, it's done with a single function call called InetServerStart. It would look something like this:

    Code:
    hServer = InetServerStart(szLocalAddress, _
                              nLocalPort, _
                              %INET_BACKLOG, _
                              nMaxClients, _
                              %INET_TIMEOUT, _
                              %INET_PRIORITY_DEFAULT, _
                              %INET_OPTION_REUSEADDR, _
                              CODEPTR(EventHandler), _
                              hDlg, _
                              0)
    Then, to actually do something with the server, you'd put that code in a function called EventHandler (or whatever you want to name it):

    Code:
    SUB EventHandler STDCALL (BYVAL hSocket AS LONG, BYVAL nEventId AS LONG, BYVAL dwError AS DWORD, BYVAL dwParam AS DWORD)
        IF dwError > 0 THEN
            ' Some error has occurred
            EXIT SUB
        END IF
    
        SELECT CASE nEventId
            CASE %INET_EVENT_READ
                LOCAL nBytesRead AS LONG
                LOCAL nBytesWritten AS LONG
                DIM ioBuffer(%BUFFERSIZE) AS LOCAL BYTE
    
                nBytesRead = InetRead(hSocket, ioBuffer(0), %BUFFERSIZE)
                IF nBytesRead > 0 THEN
                    nBytesWritten = InetWrite(hSocket, ioBuffer(0), nBytesRead)
                END IF
        END SELECT
    END SUB
    In this example, it just echoes back whatever the client has sent to it. Each client session is identified by a socket handle (hSocket), which is what you pass to other functions to do things like and read and write data. The event handler executes in the context of the thread that manages that particular client session, so you can perform blocking network operations and so on without worrying about interfering with other threads.

    You can also do things like tell the server to suspend accepting client connections, get status information, enumerate the connected clients, and so on. You can also tell the server to limit the maximum number of clients that can connect, the maximum number of connections per IP address, and throttle the rate at which the server will accept connections (to help mitigate things like DoS attacks).

    In any case, if you're interested in testing the API, just send me a PM over the next few days. Thanks!
    Mike Stefanik
    sockettools.com

  • #2
    Hi Mike,

    I'm very interested in this product. Although I lack the time to test this thoroughly, I would be very interested in purchasing this product if the price is right ;-) So... any price setting yet for this ?

    Kind regards

    Steven
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

    Comment


    • #3
      Originally posted by Steven Pringels 3 View Post
      Hi Mike,

      I'm very interested in this product. Although I lack the time to test this thoroughly, I would be very interested in purchasing this product if the price is right ;-) So... any price setting yet for this ?

      Kind regards

      Steven
      It's part of our SocketWrench package, with a regular price of $95. Folks who have a previous version will get upgrade pricing, but I'm not sure that's been finalized. Of course, it's also part of our larger SocketTools product, but if you're just interested in the server stuff, SocketWrench is all you'd need. If you have any other questions, just let me know.
      Mike Stefanik
      sockettools.com

      Comment


      • #4
        hi Mike,
        i did some testing of your products because there are probably some services i am going to have to program for but stopped for the learning curve(too many irons in the fire), but i as well am short of time.
        but if you have the price, i will consider just purchasing your product during beta. it sounds like it will save me a lot of time on the developmental of the server side, which i find much harder to write code for.

        i know that your new beta code is for a server, i am testing some email servers, which product would help me in the way of creating a client for POP3S.
        Last edited by Paul Purvis; 30 Jun 2008, 08:11 PM.
        p purvis

        Comment


        • #5
          Originally posted by paul d purvis View Post
          i know that your new beta code is for a server, i am testing some email servers, which product would help me in the way of creating a client for POP3S.
          For secure POP3 (I'm guessing you're looking to talk to GMail?) you'd want the SocketTools Secure Library Edition. You can download an evaluation version here to take a look and see if it meets your needs. And of course, if you have any questions just let me know here, or on our forums.
          Mike Stefanik
          sockettools.com

          Comment


          • #6
            thanks Mike for the response,

            i guess it is gmail, it is inside sme server.
            i have been window shopping, i use sme server as a file server and it has email services built in but i am not that committed for various reasons.
            for one reason, i would like virtual email accounts which sme server does not have, although it does have alias user names.

            i like to have documentation, stability, easy management, no fuss and future flexibility in a email system. i guess it is just a matter of time before all email will be encrypted
            while being transferred and authenticated logins, might as well go ahead and start that upfront.

            i was thinking about maybe having all email messages sent to one location using a standalone in house written windows server program to receive those messages in its own format, then having another program send the message out using the email server. this way i could control what goes out of my offices, and have a record of what takes place and possibly it would give me a lot of flexibility on programs written in house that may generate emails.
            it was very alarming to see all the activity from the internet, and my own internal program would filter internet connections.
            basically the program can be standard way of transferring messages and i would only need one interface for sending email and one interface for receiving and processing email.



            paul
            Last edited by Paul Purvis; 1 Jul 2008, 01:37 AM.
            p purvis

            Comment


            • #7
              Just to give you an idea of what a complete server application would look like, here's the code for a simple TCP/IP echo server:

              Code:
              #PBFORMS CREATED V1.51
              '------------------------------------------------------------------------------
              ' The first line in this file is a PB/Forms metastatement.
              ' It should ALWAYS be the first line of the file. Other
              ' PB/Forms metastatements are placed at the beginning and
              ' end of "Named Blocks" of code that should be edited
              ' with PBForms only. Do not manually edit or delete these
              ' metastatements or PB/Forms will not be able to reread
              ' the file correctly.  See the PB/Forms documentation for
              ' more information.
              ' Named blocks begin like this:    #PBFORMS BEGIN ...
              ' Named blocks end like this:      #PBFORMS END ...
              ' Other PB/Forms metastatements such as:
              '     #PBFORMS DECLARATIONS
              ' are used by PB/Forms to insert additional code.
              ' Feel free to make changes anywhere else in the file.
              '------------------------------------------------------------------------------
              
              #COMPILE EXE
              #DIM ALL
              
              '------------------------------------------------------------------------------
              '   ** Includes **
              '------------------------------------------------------------------------------
              #PBFORMS BEGIN INCLUDES
              #IF NOT %DEF(%WINAPI)
                  #INCLUDE "WIN32API.INC"
              #ENDIF
              #PBFORMS END INCLUDES
              #INCLUDE "CSTOOLS6.INC"
              
              '------------------------------------------------------------------------------
              
              '------------------------------------------------------------------------------
              '   ** Constants **
              '------------------------------------------------------------------------------
              #PBFORMS BEGIN CONSTANTS
              %IDD_DIALOG1      =  101
              %IDC_LABEL1       = 1001
              %IDC_LOCALADDRESS = 1002
              %IDC_LABEL2       = 1003
              %IDC_LOCALPORT    = 1004
              %IDC_LABEL3       = 1005
              %IDC_MAXCLIENTS   = 1006
              %IDC_BUTTON1      = 1007
              %IDC_BUTTON2      = 1008
              %IDC_BUTTON3      = 1009
              %IDC_BUTTON4      = 1010
              %IDC_TEXTBOX1     = 1011    '*
              %IDC_LISTBOX1     = 1012
              #PBFORMS END CONSTANTS
              
              %BUFFERSIZE = 4096
              
              '------------------------------------------------------------------------------
              
              '------------------------------------------------------------------------------
              '   ** Globals **
              '------------------------------------------------------------------------------
              GLOBAL g_hServer AS LONG
              
              '------------------------------------------------------------------------------
              '   ** Declarations **
              '------------------------------------------------------------------------------
              DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
              DECLARE FUNCTION SampleListBox(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL _
                  lCount AS LONG) AS LONG
              DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
              #PBFORMS DECLARATIONS
              '------------------------------------------------------------------------------
              
              '------------------------------------------------------------------------------
              '   ** Main Application Entry Point **
              '------------------------------------------------------------------------------
              FUNCTION PBMAIN()
                  ' Initialize the SocketTools library using the runtime
                  ' license key. This key is created whenever a licensed
                  ' copy of SocketTools is installed.
                  IF ISFALSE(InetInitialize($CSTOOLS6_LICENSE_KEY)) THEN
                      MSGBOX "Unable to initialize SocketWrench library", %MB_ICONERROR, "SocketWrench"
                      EXIT FUNCTION
                  END IF
              
                  g_hServer = %INVALID_SOCKET
              
                  ShowDIALOG1 %HWND_DESKTOP
              
                  ' Uninitialize the library, terminating any client connections
                  ' that may be active at the time
                  InetUninitialize()
              
              END FUNCTION
              '------------------------------------------------------------------------------
              
              '------------------------------------------------------------------------------
              ' ShowError adds a line to the listbox with information about the
              ' specified error code. If the error code is omitted, then
              ' information about the last error returned by the library
              ' will be displayed
              '------------------------------------------------------------------------------
              SUB ShowError(BYVAL hDlg AS DWORD, OPTIONAL BYVAL dwError AS DWORD)
                  LOCAL szError AS ASCIIZ * 128
                  LOCAL nLength AS INTEGER
              
                  IF dwError = 0 THEN
                      dwError = InetGetLastError()
                  END IF
              
                  IF dwError <> 0 THEN
                      nLength = InetGetErrorString(dwError, szError, 128)
                      IF nLength = 0 THEN
                          szError = "Undefined error 0x" + HEX$(dwError)
                      END IF
                      LISTBOX ADD hDlg, %IDC_LISTBOX1, szError
                  END IF
              END SUB
              
              '------------------------------------------------------------------------------
              ' EventHandler is the function that each client thread calls when there
              ' is a network event to process. It tells the application when a client
              ' connects, sends data to the server and disconnects from the server.
              ' In this case, we simply read whatever the client has sent us and
              ' we send it back to them.
              '------------------------------------------------------------------------------
              SUB EventHandler STDCALL (BYVAL hSocket AS LONG, BYVAL nEventId AS LONG, BYVAL dwError AS DWORD, BYVAL hDlg AS DWORD)
                  LOCAL szMessage AS ASCIIZ * 128
              
                  IF dwError > 0 THEN
                      ShowError hDlg, dwError
                      EXIT SUB
                  END IF
              
                  SELECT CASE nEventId
                      '
                      ' The %INET_EVENT_CONNECT event is fired whenever the client first
                      ' establishes its connection with the server. We just update our
                      ' listbox to show that a client has connected and the IP address
                      ' that it has connected from.
                      '
                      CASE %INET_EVENT_CONNECT
                          LOCAL dwPeerAddress AS DWORD
                          LOCAL nPeerPort AS LONG
                          LOCAL szPeerAddress AS ASCIIZ * 64
              
                          InetGetPeerAddress(hSocket, dwPeerAddress, nPeerPort)
                          InetFormatAddress(dwPeerAddress, szPeerAddress, 64)
              
                          szMessage = "Client" + STR$(hSocket) + " connected to server from address " + szPeerAddress
                          LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
              
                      '
                      ' The %INET_EVENT_READ event is fired whenever the client sends data
                      ' for us to read. In this case, we'll simply read in a block of data
                      ' and send that back to the client. If there is more data to read,
                      ' this event will fire again.
                      '
                      CASE %INET_EVENT_READ
                          LOCAL nBytesRead AS LONG
                          LOCAL nBytesWritten AS LONG
                          DIM ioBuffer(%BUFFERSIZE) AS LOCAL BYTE
              
                          nBytesRead = InetRead(hSocket, ioBuffer(0), %BUFFERSIZE)
                          IF nBytesRead > 0 THEN
                              nBytesWritten = InetWrite(hSocket, ioBuffer(0), nBytesRead)
                          END IF
              
                      '
                      ' The %INET_EVENT_DISCONNECT event is fired whenever the client has
                      ' closed its connection to the server, or when the server disconnects
                      ' the client. At this point the thread that manages the client session
                      ' is about to terminate, and the program shouldn't attempt to send
                      ' or receive data because the client is no longer interacting with
                      ' the server. Any cleanup code for this specific client session can
                      ' be done here.
                      '
                      CASE %INET_EVENT_DISCONNECT
                          szMessage = "Client" + STR$(hSocket) + " disconnected from server"
                          LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
              
                  END SELECT
              END SUB
              
              '------------------------------------------------------------------------------
              ' This function is called when %IDC_BUTTON1 is clicked by the user, and
              ' it either starts or stops the server. If the global server handle g_hServer
              ' has the value %INVALID_SOCKET then this means no server has been started,
              ' so we call the InetServerStart function with the values the user has
              ' provided. If the server's socket handle is defined, then we call InetServerStop
              ' instead, which terminates all of the client sessions and closes the listening
              ' socket.
              '------------------------------------------------------------------------------
              SUB OnClickButton1(BYVAL hDlg AS DWORD)
                  LOCAL szMessage AS ASCIIZ * 128
                  LOCAL szValue AS ASCIIZ * 32
                  LOCAL szLocalAddress AS ASCIIZ * 64
                  LOCAL nLocalPort AS LONG
                  LOCAL nMaxClients AS LONG
              
                  ' This can either be an empty string or an IP address. If it's
                  ' an empty string, then the server will accept connections on
                  ' any valid network interface configured for the system.
                  CONTROL GET TEXT hDlg, %IDC_LOCALADDRESS TO szLocalAddress
                  szLocalAddress = TRIM$(szLocalAddress)
              
                  ' Port number have to be in the range of 1-65535
                  CONTROL GET TEXT hDlg, %IDC_LOCALPORT TO szValue
                  nLocalPort = VAL(TRIM$(szValue))
                  IF nLocalPort < 1 OR nLocalPort > 65535 THEN
                      MSGBOX "Please enter a valid port number", %MB_OK, "Error"
                      CONTROL SET TEXT hDlg, %IDC_LOCALPORT, ""
                      CONTROL SET FOCUS hDlg, %IDC_LOCALPORT
                      EXIT SUB
                  END IF
              
                  ' A value of zero means there's not fixed limit to the number
                  ' of client sessions the server will accept
                  CONTROL GET TEXT hDlg, %IDC_MAXCLIENTS TO szValue
                  nMaxClients = VAL(TRIM$(szValue))
              
                  IF g_hServer = %INVALID_SOCKET THEN
                      '
                      ' Start the server with the values provided by the caller and a
                      ' reasonable set of defaults. The handle that's returned is used
                      ' by the other server API functions.
                      '
                      g_hServer = InetServerStart(szLocalAddress, _
                                                  nLocalPort, _
                                                  %INET_BACKLOG, _
                                                  nMaxClients, _
                                                  %INET_TIMEOUT, _
                                                  %INET_PRIORITY_DEFAULT, _
                                                  %INET_OPTION_REUSEADDR, _
                                                  CODEPTR(EventHandler), _
                                                  hDlg, _
                                                  0)
              
                      IF g_hServer = %INVALID_SOCKET THEN
                          ' There was a problem starting the server, so display the error
                          ' in our listbox
                          ShowError hDlg
                      ELSE
                          szMessage = "Server listening for connections on " + szLocalAddress + " port" + STR$(nLocalPort)
                          LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                          CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Stop"
                      END IF
                  ELSE
                      '
                      ' A server has been started, so we will stop it and reset the global
                      ' handle value. Note that InetServerStop operates asynchronously,
                      ' singnalling the server thread that it should terminate the client
                      ' connections, close the listening socket and release the resources
                      ' that it has allocated. It's possible that client events will fire
                      ' after this function is called as each client thread terminates.
                      '
                      IF ISFALSE(InetServerStop(g_hServer)) THEN
                          ShowError hDlg
                          EXIT SUB
                      END IF
              
                      g_hServer = %INVALID_SOCKET
              
                      szMessage = "Server stopped listening for connections, all clients terminated"
                      LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                      CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Start"
                  END IF
              END SUB
              
              '------------------------------------------------------------------------------
              ' This function is called when %IDC_BUTTON2 is clicked by the user, and
              ' depending on the status of the server, it either tells the server to
              ' suspend accepting client connections, or to resume accepting connections.
              ' When the server is suspended the listening socket is still active, but
              ' any incoming client connections will be queued until the server is resumed.
              '------------------------------------------------------------------------------
              SUB OnClickButton2(BYVAL hDlg AS DWORD)
                  IF g_hServer = %INVALID_SOCKET THEN
                      MSGBOX "The server has not been started", %MB_ICONEXCLAMATION, "Error"
                      EXIT SUB
                  END IF
              
                  SELECT CASE InetGetServerStatus(g_hServer)
                      CASE %INET_SERVER_LISTENING
                          IF ISFALSE(InetServerSuspend(g_hServer)) THEN
                              ShowError hDlg
                              EXIT SUB
                          END IF
                          LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has suspended accepting client connections"
                          CONTROL SET TEXT hDlg, %IDC_BUTTON2, "Resume"
              
                      CASE %INET_SERVER_SUSPENDED
                          IF ISFALSE(InetServerResume(g_hServer)) THEN
                              ShowError hDlg
                              EXIT SUB
                          END IF
                          LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has resumed accepting client connections"
                          CONTROL SET TEXT hDlg, %IDC_BUTTON2, "Suspend"
                  END SELECT
              END SUB
              
              '------------------------------------------------------------------------------
              ' This function is called when %IDC_BUTTON3 is clicked by the user, and
              ' the server is restarted by calling InetServerRestart. Because this creates
              ' a new listening socket, the new handle value is returned by the function.
              '------------------------------------------------------------------------------
              SUB OnClickButton3(BYVAL hDlg AS DWORD)
                  ' Make sure that the server has been started
                  IF g_hServer = %INVALID_SOCKET THEN
                      MSGBOX "The server has not been started", %MB_ICONEXCLAMATION, "Error"
                      EXIT SUB
                  END IF
              
                  g_hServer = InetServerRestart(g_hServer)
              
                  IF g_hServer = %INVALID_SOCKET THEN
                      ' Something has gone wrong, the server was stopped but it could
                      ' not be restarted and the server handle is no longer valid
                      ShowError hDlg
                      CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Start"
                      EXIT SUB
                  END IF
              
                  LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has been restarted"
              END SUB
              
              '------------------------------------------------------------------------------
              '   ** CallBacks **
              '------------------------------------------------------------------------------
              CALLBACK FUNCTION ShowDIALOG1Proc()
              
                  SELECT CASE AS LONG CBMSG
                      CASE %WM_INITDIALOG
                          ' Initialization handler
              
                      CASE %WM_NCACTIVATE
                          STATIC hWndSaveFocus AS DWORD
                          IF ISFALSE CBWPARAM THEN
                              ' Save control focus
                              hWndSaveFocus = GetFocus()
                          ELSEIF hWndSaveFocus THEN
                              ' Restore control focus
                              SetFocus(hWndSaveFocus)
                              hWndSaveFocus = 0
                          END IF
              
                      CASE %WM_COMMAND
                          ' Process control notifications
                          SELECT CASE AS LONG CBCTL
                              CASE %IDC_BUTTON1
                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                      OnClickButton1 CBHNDL
                                  END IF
              
                              CASE %IDC_BUTTON2
                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                      OnClickButton2 CBHNDL
                                  END IF
              
                              CASE %IDC_BUTTON3
                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                      OnClickButton3 CBHNDL
                                  END IF
              
                              CASE %IDC_BUTTON4
                                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                      DIALOG END CBHNDL
                                  END IF
              
                              CASE %IDC_LISTBOX1
                          END SELECT
                  END SELECT
              END FUNCTION
              '------------------------------------------------------------------------------
              
              '------------------------------------------------------------------------------
              '   ** Dialogs **
              '------------------------------------------------------------------------------
              FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                  LOCAL lRslt AS LONG
              
              #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
                  LOCAL hDlg  AS DWORD
              
                  DIALOG NEW hParent, "SocketTools Echo Server ", 350, 207, 350, 192, _
                      %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR _
                      %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _
                      %DS_MODALFRAME OR %DS_CENTER OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
                      %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
                      %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                  CONTROL ADD LABEL,   hDlg, %IDC_LABEL1, "Server:", 5, 11, 30, 9
                  CONTROL ADD TEXTBOX, hDlg, %IDC_LOCALADDRESS, "127.0.0.1", 30, 10, 80, 12
                  CONTROL ADD LABEL,   hDlg, %IDC_LABEL2, "Port:", 123, 11, 25, 10
                  CONTROL ADD TEXTBOX, hDlg, %IDC_LOCALPORT, "7", 140, 10, 30, 12
                  CONTROL ADD LABEL,   hDlg, %IDC_LABEL3, "Clients:", 181, 11, 30, 10
                  CONTROL ADD TEXTBOX, hDlg, %IDC_MAXCLIENTS, "100", 206, 10, 30, 12
                  CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON1, "Start", 285, 10, 55, 15, _
                      %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR _
                      %BS_DEFPUSHBUTTON OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, _
                      %WS_EX_LEFT OR %WS_EX_LTRREADING
                  DIALOG  SEND         hDlg, %DM_SETDEFID, %IDC_BUTTON1, 0
                  CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON2, "Suspend", 285, 30, 55, 15
                  CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON3, "Restart", 285, 50, 55, 15
                  CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON4, "Close", 285, 70, 55, 15
                  CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX1, , 5, 26, 270, 155, %WS_CHILD OR _
                      %WS_VISIBLE OR %WS_VSCROLL OR %LBS_NOSEL, %WS_EX_CLIENTEDGE OR _
                      %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
              #PBFORMS END DIALOG
              
                  DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
              
              #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
              #PBFORMS END CLEANUP
              
                  FUNCTION = lRslt
              END FUNCTION
              '------------------------------------------------------------------------------
              Mike Stefanik
              sockettools.com

              Comment


              • #8
                I am *very* interested in this product. Unfortunately I'm in the middle of another project that is consuming my time like a black hole consumes matter. So I can't help you in the testing. BUT I have a future project that this product will make child's play of! I'll be watching this closely.

                Comment


                • #9
                  Follow up question

                  It seems like this supports POST content relatively readily. Can you tell me if there is a limit to the data that can be passed this way? Also, how could this be setup to support a GET or POST in the same program (echo the GET querystring as well as the POST content)?

                  Thank you.
                  Mac Application Reviews and More

                  Comment


                  • #10
                    Originally posted by Ken Myers View Post
                    It seems like this supports POST content relatively readily. Can you tell me if there is a limit to the data that can be passed this way? Also, how could this be setup to support a GET or POST in the same program (echo the GET querystring as well as the POST content)?

                    Thank you.
                    The example isn't a webserver, it's an echo server (it sends back whatever it receives from the client). You couldn't just use this to "echo" the data browser sends because you would actually need to parse the commands and send back valid HTTP responses, or the browser would think there was an error. That said, there's no limitation on the amount of data that can be exchanged using our API.
                    Mike Stefanik
                    sockettools.com

                    Comment


                    • #11
                      I actually bought your original product and for the price expected it to do this...only to find it being wrappers for the API and it has collected "dust" so to speak being unused since. The best use of this would be one product that does both.
                      sigpic
                      Mobile Solutions
                      Sys Analyst and Development

                      Comment


                      • #12
                        Okay...

                        Before this thread gets away from me, I want to clarify my question. I am using a sockettools 5.0 client application and performing both a GET and then a POST to the echo server example in 6.0. I see the request when I perform a POST, but not when I perform a GET. Let's assume that I know how to parse the headers and properly construct a HTTP response. I don't understand why the echo server doesn't even get the request at all. Is that a different event and/or just simply not available in this implementation?

                        -Ken
                        Mac Application Reviews and More

                        Comment


                        • #13
                          So after researching your API, I see no good way to use this as a basis for a simple web server. That's okay, but I was hoping I could do that. Mainly I see no way to get the original request content for a GET. That just doesn't seem to be exposed.

                          -Ken
                          Mac Application Reviews and More

                          Comment


                          • #14
                            That was my exact issue. PB's TCP commands don't work well in creating a Web Server, so I saw this and tried it out only to have the same issues.
                            sigpic
                            Mobile Solutions
                            Sys Analyst and Development

                            Comment


                            • #15
                              Originally posted by Ken Myers View Post
                              So after researching your API, I see no good way to use this as a basis for a simple web server. That's okay, but I was hoping I could do that. Mainly I see no way to get the original request content for a GET. That just doesn't seem to be exposed.

                              -Ken
                              I'm not even sure what you're specifically talking about here. If you want to implement a simple web server, then you listen on port 80, you parse the command (e.g.: "GET /index.html HTTP/1.0"), any headers that are included, open the file "index.html" on the system relative to whatever root folder you have, and write back a response code (e.g.: "200 OK"), header block, followed by the file data. Close the connection when you're done.

                              The server API isn't a HTTP server in a box (or any other particular type of Internet server); it's a framework for developing your own custom, multi-threaded server. Alone, the framework doesn't "do" anything, you need provide the code to implement the protocol (or create your own custom protocol) on the backend.
                              Mike Stefanik
                              sockettools.com

                              Comment


                              • #16
                                Originally posted by Roger Garstang View Post
                                That was my exact issue. PB's TCP commands don't work well in creating a Web Server, so I saw this and tried it out only to have the same issues.
                                That's pretty vague, what issues are you specifically having?
                                Mike Stefanik
                                sockettools.com

                                Comment


                                • #17
                                  Originally posted by Mike Stefanik View Post
                                  I'm not even sure what you're specifically talking about here. If you want to implement a simple web server, then you listen on port 80, you parse the command (e.g.: "GET /index.html HTTP/1.0"), any headers that are included, open the file "index.html" on the system relative to whatever root folder you have, and write back a response code (e.g.: "200 OK"), header block, followed by the file data. Close the connection when you're done.
                                  Right... and you cannot do the above with sockettools 6.0. Roger and I are on the same page not sure why that is hard for you to understand.
                                  Mac Application Reviews and More

                                  Comment


                                  • #18
                                    Here's an example of how a very simple web server would be implemented using our server API. This is something that I put together based on our echo server example. It has some limitations (simply because of time, since it's 1:30 AM), such as only supporting the GET command for HTML files and limited error reporting. However, the basics are there such as processing a request, returning a result code and headers and sending back the requested file; it should be fairly easy to follow and extend.

                                    Edit: By the way, if you want to test this, make sure that you change the value of g_strRootPath to point to a valid directory on your system, and put an "index.html" file in there with some kind of content. You'll be able to then connect to localhost on port 80 and request it. Also keep in mind that this is just an example; production code would need a lot more stringent checks on the resource paths, more complete status code reporting, determining the actual MIME content type (since it's basically hard-coded to "text/html" in the example) and so on.

                                    WebServer.bas
                                    Code:
                                    #PBFORMS CREATED V1.51
                                    '------------------------------------------------------------------------------
                                    ' The first line in this file is a PB/Forms metastatement.
                                    ' It should ALWAYS be the first line of the file. Other
                                    ' PB/Forms metastatements are placed at the beginning and
                                    ' end of "Named Blocks" of code that should be edited
                                    ' with PBForms only. Do not manually edit or delete these
                                    ' metastatements or PB/Forms will not be able to reread
                                    ' the file correctly.  See the PB/Forms documentation for
                                    ' more information.
                                    ' Named blocks begin like this:    #PBFORMS BEGIN ...
                                    ' Named blocks end like this:      #PBFORMS END ...
                                    ' Other PB/Forms metastatements such as:
                                    '     #PBFORMS DECLARATIONS
                                    ' are used by PB/Forms to insert additional code.
                                    ' Feel free to make changes anywhere else in the file.
                                    '------------------------------------------------------------------------------
                                    
                                    #COMPILE EXE
                                    #DIM ALL
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Includes **
                                    '------------------------------------------------------------------------------
                                    #RESOURCE "WebServer.pbr"
                                    #PBFORMS BEGIN INCLUDES
                                    #IF NOT %DEF(%WINAPI)
                                        #INCLUDE "WIN32API.INC"
                                    #ENDIF
                                    #PBFORMS END INCLUDES
                                    #INCLUDE "CSTOOLS6.INC"
                                    
                                    ' An alternate declaration of the InetWrite function, passing a pointer
                                    ' to an null-terminated string instead of a byte array
                                    
                                    DECLARE FUNCTION InetWriteText STDCALL LIB "cswskav6.dll" ALIAS "InetWrite" ( _
                                            BYVAL hSocket AS LONG, _
                                            BYREF lpszBuffer AS ASCIIZ, _
                                            BYVAL cbBuffer AS LONG _
                                            ) AS LONG
                                    
                                    '------------------------------------------------------------------------------
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Constants **
                                    '------------------------------------------------------------------------------
                                    #PBFORMS BEGIN CONSTANTS
                                    %IDD_DIALOG1      =  101
                                    %IDC_LABEL1       = 1001
                                    %IDC_LOCALADDRESS = 1002
                                    %IDC_LABEL2       = 1003
                                    %IDC_LOCALPORT    = 1004
                                    %IDC_LABEL3       = 1005
                                    %IDC_MAXCLIENTS   = 1006
                                    %IDC_BUTTON1      = 1007
                                    %IDC_BUTTON2      = 1008
                                    %IDC_BUTTON3      = 1009
                                    %IDC_BUTTON4      = 1010
                                    %IDC_TEXTBOX1     = 1011    '*
                                    %IDC_LISTBOX1     = 1012
                                    #PBFORMS END CONSTANTS
                                    
                                    %BUFFERSIZE = 4096
                                    
                                    '------------------------------------------------------------------------------
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Globals **
                                    '------------------------------------------------------------------------------
                                    GLOBAL g_hServer AS LONG
                                    GLOBAL g_strRootPath AS STRING
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Declarations **
                                    '------------------------------------------------------------------------------
                                    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                                    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                                    #PBFORMS DECLARATIONS
                                    '------------------------------------------------------------------------------
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Main Application Entry Point **
                                    '------------------------------------------------------------------------------
                                    FUNCTION PBMAIN()
                                        ' Initialize the SocketTools library using the runtime
                                        ' license key. This key is created whenever a licensed
                                        ' copy of SocketTools is installed.
                                        IF ISFALSE(InetInitialize($CSTOOLS6_LICENSE_KEY)) THEN
                                            MSGBOX "Unable to initialize SocketWrench library", %MB_ICONERROR, "SocketWrench"
                                            EXIT FUNCTION
                                        END IF
                                    
                                        ' Initialize the handle to the server
                                        g_hServer = %INVALID_SOCKET
                                    
                                        ' This points to the directory that will serve as the root of
                                        ' all document requests
                                        g_strRootPath = "C:\Temp\WebServer"
                                    
                                        ShowDIALOG1 %HWND_DESKTOP
                                    
                                        ' Uninitialize the library, terminating any client connections
                                        ' that may be active at the time
                                        InetUninitialize()
                                    
                                    END FUNCTION
                                    '------------------------------------------------------------------------------
                                    
                                    '------------------------------------------------------------------------------
                                    ' ShowError adds a line to the listbox with information about the
                                    ' specified error code. If the error code is omitted, then
                                    ' information about the last error returned by the library
                                    ' will be displayed
                                    '------------------------------------------------------------------------------
                                    SUB ShowError(BYVAL hDlg AS DWORD, OPTIONAL BYVAL dwError AS DWORD)
                                        LOCAL szError AS ASCIIZ * 128
                                        LOCAL nLength AS INTEGER
                                    
                                        IF dwError = 0 THEN
                                            dwError = InetGetLastError()
                                        END IF
                                    
                                        IF dwError <> 0 THEN
                                            nLength = InetGetErrorString(dwError, szError, 128)
                                            IF nLength = 0 THEN
                                                szError = "Undefined error 0x" + HEX$(dwError)
                                            END IF
                                            LISTBOX ADD hDlg, %IDC_LISTBOX1, szError
                                        END IF
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' SendResponse sends a response back to the client that consists of the
                                    ' result code and message, along with response headers such as the content
                                    ' type and length
                                    '------------------------------------------------------------------------------
                                    SUB SendResponse(BYVAL hSocket AS LONG, _
                                                     BYVAL nResultCode AS LONG, _
                                                     BYVAL strMessage AS STRING, _
                                                     BYVAL strContentType AS STRING, _
                                                     BYVAL nContentLength AS LONG _
                                                     )
                                        LOCAL szBuffer AS ASCIIZ * 1024
                                        LOCAL szError AS ASCIIZ * 1024
                                        LOCAL nLength AS LONG
                                    
                                        ' Send the result code and message to the client
                                        szBuffer = "HTTP/1.0 " + TRIM$(STR$(nResultCode)) + " " + strMessage
                                        InetWriteLine(hSocket, szBuffer, nLength)
                                    
                                        ' If the content type is not specified, then default to HTML
                                        IF LEN(strContentType) = 0 THEN
                                            strContentType = "text/html"
                                        END IF
                                    
                                        ' If the content length is zero, then we'll create an HTML error message
                                        ' based on the result code and message provided by the caller
                                        IF nContentLength = 0 THEN
                                            szError = "<html><head><title>" + strMessage + "</title></head><body>" + CHR$(13) + CHR$(10)
                                            szError = szError + "<h2>" + TRIM$(STR$(nResultCode)) + " " + strMessage + "</h2>" + CHR$(13) + CHR$(10)
                                            szError = szError + "</body></html>" + CHR$(13) + CHR$(10)
                                            nContentLength = LEN(szError)
                                        END IF
                                    
                                        ' Send standard response headers to the client
                                        szBuffer = "Content-Type: " + strContentType
                                        InetWriteLine(hSocket, szBuffer, nLength)
                                    
                                        szBuffer = "Content-Length: " + TRIM$(STR$(nContentLength))
                                        InetWriteLine(hSocket, szBuffer, nLength)
                                    
                                        szBuffer = "Connection: close"
                                        InetWriteLine(hSocket, szBuffer, nLength)
                                    
                                        ' An empty line signifies the end of the response header block
                                        szBuffer = ""
                                        InetWriteLine(hSocket, szBuffer, nLength)
                                    
                                        ' Write out the HTML version of the error message
                                        IF LEN(szError) > 0 THEN
                                            InetWriteText(hSocket, szError, LEN(szError))
                                        END IF
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' ProcessRequest reads the request from the client, along with any headers,
                                    ' and sends back the requested resource. In this example, only HTML files are
                                    ' returned, but it could be modified fairly easily to support image files and
                                    ' other types of content; this would require determining the MIME content
                                    ' type of the resource that was requested and specifying that in the response.
                                    '
                                    ' It is important to remember that this function will be called in the context
                                    ' of the thread that is managing the client session, so any modification of
                                    ' a static or global variable must be synchronized.
                                    '------------------------------------------------------------------------------
                                    SUB ProcessRequest(BYVAL hDlg AS DWORD, BYVAL hSocket AS LONG)
                                        LOCAL szBuffer AS ASCIIZ * 1024
                                        LOCAL strCommand AS STRING
                                        LOCAL strResource AS STRING
                                        LOCAL strProtocol AS STRING
                                        LOCAL strFileName AS STRING
                                        LOCAL dwAttributes AS DWORD
                                        LOCAL nLength AS LONG
                                        LOCAL nOffset AS LONG
                                        LOCAL nParams AS LONG
                                        LOCAL bResult AS LONG
                                        LOCAL hFile AS INTEGER
                                        DIM ioBuffer(%BUFFERSIZE) AS LOCAL BYTE
                                    
                                        ' Read the command issued by the client
                                        nLength = 1024
                                        bResult = InetReadLine(hSocket, szBuffer, nLength)
                                    
                                        ' If we are unable to read a complete line, then something is
                                        ' wrong with the client, terminate the connection
                                        IF ISFALSE(bResult) THEN
                                            InetDisconnect(hSocket)
                                            EXIT SUB
                                        END IF
                                    
                                        ' Parse the command issued by the client; note that this requires
                                        ' a standard HTTP 1.0 or 1.1 request in a format such as:
                                        '
                                        ' GET /index.html HTTP/1.0
                                        '
                                        ' This example doesn't support the deprecated HTTP 0.9 protocol
                                        ' where request and response headers are not used
                                        '
                                        nParams = PARSECOUNT(szBuffer, " ")
                                        IF nParams > 2 THEN
                                            strCommand = UCASE$(TRIM$(PARSE$(szBuffer, " ", 1)))
                                            strResource = TRIM$(PARSE$(szBuffer, " ", 2))
                                            strProtocol = UCASE$(TRIM$(PARSE$(szBuffer, " ", 3)))
                                        END IF
                                    
                                        ' The client will send one or more request headers, terminated
                                        ' by an empty line; we don't actually do anything with these
                                        ' header values in the example, but we must read them
                                        DO
                                            nLength = 1024
                                            bResult = InetReadLine(hSocket, szBuffer, nLength)
                                        LOOP UNTIL ISFALSE(bResult) OR nLength = 0
                                    
                                        ' Something went wrong trying to read the request header block
                                        ' from the client, so report an error and disconnect
                                        IF ISFALSE(bResult) THEN
                                            SendResponse(hSocket, 400, "Bad Request", "text/html", 0)
                                            InetDisconnect(hSocket)
                                        END IF
                                    
                                        ' Process the command that was specified by the client
                                        IF LEN(strCommand) = 0 OR LEN(strProtocol) = 0 THEN
                                            SendResponse(hSocket, 400, "Bad Request", "text/html", 0)
                                            InetDisconnect(hSocket)
                                            EXIT SUB
                                        END IF
                                    
                                        ' This example only supports the GET command
                                        IF strCommand <> "GET" THEN
                                            SendResponse(hSocket, 501, "Command Not Implemented", "text/html", 0)
                                            InetDisconnect(hSocket)
                                            EXIT SUB
                                        END IF
                                    
                                        ' Compose the name of the file based on the root folder
                                        IF strResource = "/" THEN
                                            strResource = "/index.html"
                                        END IF
                                    
                                        ' Normalize the path name
                                        strFileName = g_strRootPath + strResource
                                        REPLACE "/" WITH "\" IN strFileName
                                    
                                        ' Update the UI to specify what file was requested by the client
                                        szBuffer = "Client" + STR$(hSocket) + " requested file " + strFileName
                                        LISTBOX ADD hDlg, %IDC_LISTBOX1, szBuffer
                                    
                                        TRY
                                            ' Get the attributes of the file; if the file does not exist,
                                            ' an exception will be thrown
                                            dwAttributes = GETATTR(strFileName)
                                    
                                            ' If the resource specified is actually a subdirectory, then
                                            ' throw an exception; alternatively, we could indicate to the
                                            ' client that the resource has been redirected to an index
                                            ' file in that subdirectory
                                            IF (dwAttributes AND %SUBDIR) <> 0 THEN
                                                ERROR 52
                                            END IF
                                    
                                            ' Allocate a free file handle and initialize the offset
                                            hFile = FREEFILE
                                            nOffset = 0
                                    
                                            ' Open the file for read access
                                            OPEN strFileName FOR BINARY ACCESS READ LOCK WRITE AS #hFile BASE = 0
                                    
                                            ' Send a 200 result code to the client letting them know that
                                            ' the URL is valid, and the size of the file
                                            SendResponse(hSocket, 200, "OK", "text/html", LOF(hFile))
                                    
                                            ' Read the contents of the file, sending it to the client
                                            DO WHILE ISFALSE EOF(hFile)
                                                GET #hFile, nOffset, ioBuffer() TO nLength
                                                InetWrite(hSocket, ioBuffer(0), nLength)
                                                nOffset = nOffset + nLength
                                            LOOP
                                        CATCH
                                            ' An error has occurred, so return an error status code back
                                            ' to the client
                                            SendResponse(hSocket, 404, "Not Found", "text/html", 0)
                                        FINALLY
                                            ' Close the open file
                                            CLOSE #hFile
                                        END TRY
                                    
                                        ' Disconnect the client session
                                        InetDisconnect(hSocket)
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' EventHandler is the function that each client thread calls when there
                                    ' is a network event to process. It tells the application when a client
                                    ' connects, sends data to the server and disconnects from the server.
                                    ' In this case, we simply read whatever the client has sent us and
                                    ' we send it back to them.
                                    '------------------------------------------------------------------------------
                                    SUB EventHandler STDCALL (BYVAL hSocket AS LONG, BYVAL nEventId AS LONG, BYVAL dwError AS DWORD, BYVAL hDlg AS DWORD)
                                        LOCAL szMessage AS ASCIIZ * 128
                                    
                                        IF dwError > 0 THEN
                                            ShowError hDlg, dwError
                                            EXIT SUB
                                        END IF
                                    
                                        SELECT CASE nEventId
                                            '
                                            ' The %INET_EVENT_CONNECT event is fired whenever the client first
                                            ' establishes its connection with the server. We just update our
                                            ' listbox to show that a client has connected and the IP address
                                            ' that it has connected from.
                                            '
                                            CASE %INET_EVENT_CONNECT
                                                LOCAL dwPeerAddress AS DWORD
                                                LOCAL nPeerPort AS LONG
                                                LOCAL szPeerAddress AS ASCIIZ * 64
                                    
                                                InetGetPeerAddress(hSocket, dwPeerAddress, nPeerPort)
                                                InetFormatAddress(dwPeerAddress, szPeerAddress, 64)
                                    
                                                szMessage = "Client" + STR$(hSocket) + " connected to server from address " + szPeerAddress
                                                LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                                    
                                            '
                                            ' The %INET_EVENT_READ event is fired whenever the client sends data
                                            ' for us to read. For a web server, it will be a command that requests
                                            ' a resource, followed by one or more optional headers.
                                            '
                                            CASE %INET_EVENT_READ
                                                ProcessRequest(hDlg, hSocket)
                                    
                                            '
                                            ' The %INET_EVENT_DISCONNECT event is fired whenever the client has
                                            ' closed its connection to the server, or when the server disconnects
                                            ' the client. At this point the thread that manages the client session
                                            ' is about to terminate, and the program shouldn't attempt to send
                                            ' or receive data because the client is no longer interacting with
                                            ' the server. Any cleanup code for this specific client session can
                                            ' be done here.
                                            '
                                            CASE %INET_EVENT_DISCONNECT
                                                szMessage = "Client" + STR$(hSocket) + " disconnected from server"
                                                LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                                    
                                        END SELECT
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' This function is called when %IDC_BUTTON1 is clicked by the user, and
                                    ' it either starts or stops the server. If the global server handle g_hServer
                                    ' has the value %INVALID_SOCKET then this means no server has been started,
                                    ' so we call the InetServerStart function with the values the user has
                                    ' provided. If the server's socket handle is defined, then we call InetServerStop
                                    ' instead, which terminates all of the client sessions and closes the listening
                                    ' socket.
                                    '------------------------------------------------------------------------------
                                    SUB OnClickButton1(BYVAL hDlg AS DWORD)
                                        LOCAL szMessage AS ASCIIZ * 128
                                        LOCAL szValue AS ASCIIZ * 32
                                        LOCAL szLocalAddress AS ASCIIZ * 64
                                        LOCAL nLocalPort AS LONG
                                        LOCAL nMaxClients AS LONG
                                    
                                        ' This can either be an empty string or an IP address. If it's
                                        ' an empty string, then the server will accept connections on
                                        ' any valid network interface configured for the system.
                                        CONTROL GET TEXT hDlg, %IDC_LOCALADDRESS TO szLocalAddress
                                        szLocalAddress = TRIM$(szLocalAddress)
                                    
                                        ' Port number have to be in the range of 1-65535
                                        CONTROL GET TEXT hDlg, %IDC_LOCALPORT TO szValue
                                        nLocalPort = VAL(TRIM$(szValue))
                                        IF nLocalPort < 1 OR nLocalPort > 65535 THEN
                                            MSGBOX "Please enter a valid port number", %MB_OK, "Error"
                                            CONTROL SET TEXT hDlg, %IDC_LOCALPORT, ""
                                            CONTROL SET FOCUS hDlg, %IDC_LOCALPORT
                                            EXIT SUB
                                        END IF
                                    
                                        ' A value of zero means there's not fixed limit to the number
                                        ' of client sessions the server will accept
                                        CONTROL GET TEXT hDlg, %IDC_MAXCLIENTS TO szValue
                                        nMaxClients = VAL(TRIM$(szValue))
                                    
                                        IF g_hServer = %INVALID_SOCKET THEN
                                            '
                                            ' Start the server with the values provided by the caller and a
                                            ' reasonable set of defaults. The handle that's returned is used
                                            ' by the other server API functions.
                                            '
                                            g_hServer = InetServerStart(szLocalAddress, _
                                                                        nLocalPort, _
                                                                        %INET_BACKLOG, _
                                                                        nMaxClients, _
                                                                        %INET_TIMEOUT, _
                                                                        %INET_PRIORITY_DEFAULT, _
                                                                        %INET_OPTION_REUSEADDR, _
                                                                        CODEPTR(EventHandler), _
                                                                        hDlg, _
                                                                        0)
                                    
                                            IF g_hServer = %INVALID_SOCKET THEN
                                                ' There was a problem starting the server, so display the error
                                                ' in our listbox
                                                ShowError hDlg
                                            ELSE
                                                szMessage = "Server listening for connections on " + szLocalAddress + " port" + STR$(nLocalPort)
                                                LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                                                CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Stop"
                                            END IF
                                        ELSE
                                            '
                                            ' A server has been started, so we will stop it and reset the global
                                            ' handle value. Note that InetServerStop operates asynchronously,
                                            ' singnalling the server thread that it should terminate the client
                                            ' connections, close the listening socket and release the resources
                                            ' that it has allocated. It's possible that client events will fire
                                            ' after this function is called as each client thread terminates.
                                            '
                                            IF ISFALSE(InetServerStop(g_hServer)) THEN
                                                ShowError hDlg
                                                EXIT SUB
                                            END IF
                                    
                                            g_hServer = %INVALID_SOCKET
                                    
                                            szMessage = "Server stopped listening for connections, all clients terminated"
                                            LISTBOX ADD hDlg, %IDC_LISTBOX1, szMessage
                                            CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Start"
                                        END IF
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' This function is called when %IDC_BUTTON2 is clicked by the user, and
                                    ' depending on the status of the server, it either tells the server to
                                    ' suspend accepting client connections, or to resume accepting connections.
                                    ' When the server is suspended the listening socket is still active, but
                                    ' any incoming client connections will be queued until the server is resumed.
                                    '------------------------------------------------------------------------------
                                    SUB OnClickButton2(BYVAL hDlg AS DWORD)
                                        IF g_hServer = %INVALID_SOCKET THEN
                                            MSGBOX "The server has not been started", %MB_ICONEXCLAMATION, "Error"
                                            EXIT SUB
                                        END IF
                                    
                                        SELECT CASE InetGetServerStatus(g_hServer)
                                            CASE %INET_SERVER_LISTENING
                                                IF ISFALSE(InetServerSuspend(g_hServer)) THEN
                                                    ShowError hDlg
                                                    EXIT SUB
                                                END IF
                                                LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has suspended accepting client connections"
                                                CONTROL SET TEXT hDlg, %IDC_BUTTON2, "Resume"
                                    
                                            CASE %INET_SERVER_SUSPENDED
                                                IF ISFALSE(InetServerResume(g_hServer)) THEN
                                                    ShowError hDlg
                                                    EXIT SUB
                                                END IF
                                                LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has resumed accepting client connections"
                                                CONTROL SET TEXT hDlg, %IDC_BUTTON2, "Suspend"
                                        END SELECT
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    ' This function is called when %IDC_BUTTON3 is clicked by the user, and
                                    ' the server is restarted by calling InetServerRestart. Because this creates
                                    ' a new listening socket, the new handle value is returned by the function.
                                    '------------------------------------------------------------------------------
                                    SUB OnClickButton3(BYVAL hDlg AS DWORD)
                                        ' Make sure that the server has been started
                                        IF g_hServer = %INVALID_SOCKET THEN
                                            MSGBOX "The server has not been started", %MB_ICONEXCLAMATION, "Error"
                                            EXIT SUB
                                        END IF
                                    
                                        g_hServer = InetServerRestart(g_hServer)
                                    
                                        IF g_hServer = %INVALID_SOCKET THEN
                                            ' Something has gone wrong, the server was stopped but it could
                                            ' not be restarted and the server handle is no longer valid
                                            ShowError hDlg
                                            CONTROL SET TEXT hDlg, %IDC_BUTTON1, "Start"
                                            EXIT SUB
                                        END IF
                                    
                                        LISTBOX ADD hDlg, %IDC_LISTBOX1, "The server has been restarted"
                                    END SUB
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** CallBacks **
                                    '------------------------------------------------------------------------------
                                    CALLBACK FUNCTION ShowDIALOG1Proc()
                                    
                                        SELECT CASE AS LONG CBMSG
                                            CASE %WM_INITDIALOG
                                                ' Initialization handler
                                    
                                            CASE %WM_NCACTIVATE
                                                STATIC hWndSaveFocus AS DWORD
                                                IF ISFALSE CBWPARAM THEN
                                                    ' Save control focus
                                                    hWndSaveFocus = GetFocus()
                                                ELSEIF hWndSaveFocus THEN
                                                    ' Restore control focus
                                                    SetFocus(hWndSaveFocus)
                                                    hWndSaveFocus = 0
                                                END IF
                                    
                                            CASE %WM_COMMAND
                                                ' Process control notifications
                                                SELECT CASE AS LONG CBCTL
                                                    CASE %IDC_BUTTON1
                                                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                            OnClickButton1 CBHNDL
                                                        END IF
                                    
                                                    CASE %IDC_BUTTON2
                                                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                            OnClickButton2 CBHNDL
                                                        END IF
                                    
                                                    CASE %IDC_BUTTON3
                                                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                            OnClickButton3 CBHNDL
                                                        END IF
                                    
                                                    CASE %IDC_BUTTON4
                                                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                            DIALOG END CBHNDL
                                                        END IF
                                    
                                                    CASE %IDC_LISTBOX1
                                                END SELECT
                                        END SELECT
                                    END FUNCTION
                                    '------------------------------------------------------------------------------
                                    
                                    '------------------------------------------------------------------------------
                                    '   ** Dialogs **
                                    '------------------------------------------------------------------------------
                                    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                                        LOCAL lRslt AS LONG
                                    
                                    #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
                                        LOCAL hDlg  AS DWORD
                                    
                                        DIALOG NEW hParent, "SocketTools Echo Server ", 350, 207, 350, 192, _
                                            %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR _
                                            %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _
                                            %DS_MODALFRAME OR %DS_CENTER OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
                                            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
                                            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                                        CONTROL ADD LABEL,   hDlg, %IDC_LABEL1, "Server:", 5, 11, 30, 9
                                        CONTROL ADD TEXTBOX, hDlg, %IDC_LOCALADDRESS, "127.0.0.1", 30, 10, 80, 12
                                        CONTROL ADD LABEL,   hDlg, %IDC_LABEL2, "Port:", 123, 11, 25, 10
                                        CONTROL ADD TEXTBOX, hDlg, %IDC_LOCALPORT, "80", 140, 10, 30, 12
                                        CONTROL ADD LABEL,   hDlg, %IDC_LABEL3, "Clients:", 181, 11, 30, 10
                                        CONTROL ADD TEXTBOX, hDlg, %IDC_MAXCLIENTS, "100", 206, 10, 30, 12
                                        CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON1, "Start", 285, 10, 55, 15, _
                                            %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_TEXT OR _
                                            %BS_DEFPUSHBUTTON OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, _
                                            %WS_EX_LEFT OR %WS_EX_LTRREADING
                                        DIALOG  SEND         hDlg, %DM_SETDEFID, %IDC_BUTTON1, 0
                                        CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON2, "Suspend", 285, 30, 55, 15
                                        CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON3, "Restart", 285, 50, 55, 15
                                        CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON4, "Close", 285, 70, 55, 15
                                        CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX1, , 5, 26, 270, 155, %WS_CHILD OR _
                                            %WS_VISIBLE OR %WS_VSCROLL OR %LBS_NOSEL, %WS_EX_CLIENTEDGE OR _
                                            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
                                    #PBFORMS END DIALOG
                                    
                                        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                                    
                                    #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
                                    #PBFORMS END CLEANUP
                                    
                                        FUNCTION = lRslt
                                    END FUNCTION
                                    '------------------------------------------------------------------------------
                                    WebServer.rc
                                    Code:
                                    //#PBForms Created v1.51
                                    //-----------------------------------------------------------------------------
                                    // The first line in this file is a PB/Forms comment. It   
                                    // should ALWAYS be the first line of the file.  Other     
                                    // PB/Forms comments are placed at the beginning and end   
                                    // of "Named Blocks" of code that should be edited within  
                                    // PB/Forms only.  Do not edit or delete these comments or 
                                    // PB/Forms will not be able to reread the file correctly. 
                                    // See the PB/Forms documentation for more information.    
                                    // Named blocks begin like this:    //#PBFORMS BEGIN ...   
                                    // Named blocks end like this:      //#PBFORMS END ...     
                                    // Feel free to make changes anywhere else in the file.    
                                    //-----------------------------------------------------------------------------
                                    
                                    #include "Resource.h"
                                    
                                    //-----------------------------------------------------------------------------
                                    //  ** Constants **
                                    //-----------------------------------------------------------------------------
                                    //#PBForms Begin Constants
                                    //#PBForms End Constants
                                    //-----------------------------------------------------------------------------
                                    
                                    #define RT_MANIFEST 24 
                                    #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 
                                    
                                    CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "WebServer.manifest"
                                    
                                    //-------------------------------------------------------------------------
                                    //  ** Version Info **
                                    //-------------------------------------------------------------------------
                                    //#PBForms Begin VersionInfo
                                    VS_VERSION_INFO VERSIONINFO
                                     FILEVERSION 6,0,6000,0
                                     PRODUCTVERSION 6,0,6000,0
                                     FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
                                     FILEFLAGS 0x0
                                     FILEOS VOS_WINDOWS32
                                     FILETYPE VFT_APP
                                     FILESUBTYPE VFT2_UNKNOWN
                                    BEGIN
                                        BLOCK "StringFileInfo"
                                        BEGIN
                                            BLOCK "040904B0"
                                            BEGIN
                                                VALUE "CompanyName", "Catalyst Development Corporation\0"
                                                VALUE "FileVersion", "6.0.6000.0\0"
                                                VALUE "InternalName", "WebServer\0"
                                                VALUE "LegalCopyright", "Copyright \251 2008 Catalyst Development Corporation\0"
                                                VALUE "OriginalFilename", "WebServer.exe\0"
                                                VALUE "ProductName", "SocketTools\0"
                                                VALUE "ProductVersion", "6.0.6000.0\0"
                                            END
                                        END
                                        BLOCK "VarFileInfo"
                                        BEGIN
                                            VALUE "Translation", 0x409, 1200
                                        END
                                    END
                                    //#PBForms End VersionInfo
                                    //-------------------------------------------------------------------------
                                    WebServer.manifest
                                    Code:
                                    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
                                    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
                                        <assemblyIdentity 
                                            version="6.0.6000.0" 
                                            processorArchitecture="X86" 
                                            name="SocketTools.Example.WebServer" 
                                            type="win32" />
                                        <description>SocketTools Example</description>
                                        <dependency>
                                            <dependentAssembly>
                                                <assemblyIdentity 
                                                    type="win32" 
                                                    name="Microsoft.Windows.Common-Controls" 
                                                    version="6.0.0.0" 
                                                    processorArchitecture="X86" 
                                                    publicKeyToken="6595b64144ccf1df" 
                                                    language="*" />
                                            </dependentAssembly>
                                        </dependency>
                                    </assembly>
                                    Last edited by Mike Stefanik; 17 Oct 2008, 04:54 AM.
                                    Mike Stefanik
                                    sockettools.com

                                    Comment

                                    Working...
                                    X