- Don't call winsock initialiser for each seperate server thread
- Add more code for tcpsvcs to be controled via services. Still #if 0'd out until fully implemented.
- Make server more informative with what is happening. (this info will be output to a log file once implemented as a service.
Modified: trunk/reactos/apps/utils/net/tcpsvcs/chargen.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/daytime.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/discard.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/echo.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/qotd.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/skelserver.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.c
Modified: trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.h

Modified: trunk/reactos/apps/utils/net/tcpsvcs/chargen.c
--- trunk/reactos/apps/utils/net/tcpsvcs/chargen.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/chargen.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -22,7 +22,7 @@
         _tprintf(_T("Connection shutdown failed\n"));
         Retval = 3;
     }
-    _tprintf(_T("Terminating thread\n"));
+    _tprintf(_T("Terminating chargen thread\n"));
     ExitThread(0);
 
     return Retval;

Modified: trunk/reactos/apps/utils/net/tcpsvcs/daytime.c
--- trunk/reactos/apps/utils/net/tcpsvcs/daytime.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/daytime.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -26,7 +26,7 @@
         _tprintf(_T("Connection shutdown failed\n"));
         Retval = 3;
     }
-    _tprintf(_T("Terminating thread\n"));
+    _tprintf(_T("Terminating daytime thread\n"));
     ExitThread(0);
 
     return Retval;

Modified: trunk/reactos/apps/utils/net/tcpsvcs/discard.c
--- trunk/reactos/apps/utils/net/tcpsvcs/discard.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/discard.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -24,7 +24,7 @@
         _tprintf(_T("Connection shutdown failed\n"));
         Retval = 3;
     }
-    _tprintf(_T("Terminating thread\n"));
+    _tprintf(_T("Terminating discard thread\n"));
     ExitThread(0);
 
     return Retval;

Modified: trunk/reactos/apps/utils/net/tcpsvcs/echo.c
--- trunk/reactos/apps/utils/net/tcpsvcs/echo.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/echo.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -22,7 +22,7 @@
         _tprintf(_T("Connection shutdown failed\n"));
         Retval = 3;
     }
-    _tprintf(_T("Terminating thread\n"));
+    _tprintf(_T("Terminating echo thread\n"));
     ExitThread(0);
 
     return Retval;

Modified: trunk/reactos/apps/utils/net/tcpsvcs/qotd.c
--- trunk/reactos/apps/utils/net/tcpsvcs/qotd.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/qotd.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -33,7 +33,7 @@
         _tprintf(_T("Connection shutdown failed\n"));
         Retval = 3;
     }
-    _tprintf(_T("Terminating thread\n"));
+    _tprintf(_T("Terminating qotd thread\n"));
     ExitThread(0);
 
     return Retval;

Modified: trunk/reactos/apps/utils/net/tcpsvcs/skelserver.c
--- trunk/reactos/apps/utils/net/tcpsvcs/skelserver.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/skelserver.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -7,18 +7,10 @@
 DWORD WINAPI StartServer(LPVOID lpParam)
 {
     const TCHAR* HostIP = "127.0.0.1";
-    DWORD RetVal;
-    WSADATA wsaData;
     PSERVICES pServices;
 
     pServices = (PSERVICES)lpParam;
 
-    if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
-    {
-        _tprintf(_T("WSAStartup() failed : %lu\n"), RetVal);
-        return -1;
-    }
-
     SOCKET ListeningSocket = SetUpListener(HostIP, htons(pServices->Port));
     if (ListeningSocket == INVALID_SOCKET)
     {
@@ -26,10 +18,11 @@
         return 3;
     }
 
-    _tprintf(_T("Waiting for connections...\n"));
+    _tprintf(_T("%s is waiting for connections on port %d...\n"),
+        pServices->Name, pServices->Port);
     while (1)
     {
-        AcceptConnections(ListeningSocket, pServices->Service);
+        AcceptConnections(ListeningSocket, pServices->Service, pServices->Name);
         printf("Acceptor restarting...\n");
     }
 
@@ -66,7 +59,8 @@
 
 
 
-VOID AcceptConnections(SOCKET ListeningSocket, LPTHREAD_START_ROUTINE Service)
+VOID AcceptConnections(SOCKET ListeningSocket,
+    LPTHREAD_START_ROUTINE Service, TCHAR *Name)
 {
     SOCKADDR_IN Client;
     SOCKET Sock;
@@ -78,9 +72,9 @@
         Sock = accept(ListeningSocket, (SOCKADDR*)&Client, &nAddrSize);
         if (Sock != INVALID_SOCKET)
         {
-            _tprintf(_T("Accepted connection from %s:%d\n"),
-                inet_ntoa(Client.sin_addr), ntohs(Client.sin_port));
-            _tprintf(_T("About to create thread\n"));
+            _tprintf(_T("Accepted connection to %s server from %s:%d\n"),
+                Name, inet_ntoa(Client.sin_addr), ntohs(Client.sin_port));
+            _tprintf(_T("Creating new thread for %s\n"), Name);
             CreateThread(0, 0, Service, (void*)Sock, 0, &ThreadID);
         }
         else

Modified: trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.c
--- trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.c	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.c	2005-10-03 18:32:30 UTC (rev 18248)
@@ -3,68 +3,67 @@
 #include <tchar.h>
 #include "tcpsvcs.h"
 
-static
-LPTHREAD_START_ROUTINE
-ServiceHandler[NUM_SERVICES] =
-{
-    EchoHandler,
-    DiscardHandler,
-    DaytimeHandler,
-    QotdHandler,
-    ChargenHandler
-};
+#if 0
+/*
+ * globals
+ */
+static SERVICE_STATUS hServStatus;
+static SERVICE_STATUS_HANDLE hSStat;
+FILE *hLogFile;
+BOOL bLogEvents = TRUE;
+BOOL ShutDown, PauseFlag;
+LPTSTR LogFileName = "tcpsvcs_log.txt";
 
-static int
-ServicePort[NUM_SERVICES] =
-{
-    ECHO_PORT,
-    DISCARD_PORT,
-    DAYTIME_PORT,
-    QOTD_PORT,
-    CHARGEN_PORT
-};
-
-#if 0
-static
-SERVICE_TABLE_ENTRY
+static SERVICE_TABLE_ENTRY
 ServiceTable[2] =
 {
-    {TEXT("tcpsvcs"), ServiceMain},
+    {_T("tcpsvcs"), ServiceMain},
     {NULL, NULL}
 };
 #endif
 
+static SERVICES
+Services[NUM_SERVICES] =
+{
+    {ECHO_PORT, _T("Echo"), EchoHandler},
+    {DISCARD_PORT, _T("Discard"), DiscardHandler},
+    {DAYTIME_PORT, _T("Daytime"), DaytimeHandler},
+    {QOTD_PORT, _T("QOTD"), QotdHandler},
+    {CHARGEN_PORT, _T("Chargen"), ChargenHandler}
+};
+
+
 int main(void)
 {
-    PSERVICES pServices[NUM_SERVICES];
     DWORD dwThreadId[NUM_SERVICES];
     HANDLE hThread[NUM_SERVICES];
+    WSADATA wsaData;
+    DWORD RetVal;
     INT i;
 
+    if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
+    {
+        _tprintf(_T("WSAStartup() failed : %lu\n"), RetVal);
+        return -1;
+    }
+
     /* Create MAX_THREADS worker threads. */
     for( i=0; i<NUM_SERVICES; i++ )
     {
-        /* Allocate memory for thread data. */
-        pServices[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICES));
+        _tprintf(_T("Starting %s server....\n"), Services[i].Name);
 
-        if( pServices[i] == NULL )
-            ExitProcess(2);
-
-        /* Generate unique data for each thread. */
-        pServices[i]->Service = ServiceHandler[i];
-        pServices[i]->Port = ServicePort[i];
-
         hThread[i] = CreateThread(
             NULL,              // default security attributes
             0,                 // use default stack size
             StartServer,       // thread function
-            pServices[i],      // argument to thread function
+            &Services[i],     // argument to thread function
             0,                 // use default creation flags
             &dwThreadId[i]);   // returns the thread identifier
 
         /* Check the return value for success. */
         if (hThread[i] == NULL)
         {
+            _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
             ExitProcess(i);
         }
     }
@@ -80,39 +79,134 @@
     return 0;
 }
 
+
+
+/* code to run tcpsvcs as a service */
 #if 0
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv)
+int
+main(int argc, char *argv[])
 {
-    PSERVICES pServices[NUM_SERVICES];
+    //DPRINT("tcpsvcs: main() started. See tcpsvcs_log.txt for info\n");
+
+    if (!StartServiceCtrlDispatcher(ServiceTable))
+        _tprintf(_T("failed to start the service control dispatcher\n"));
+
+    //DPRINT("tcpsvcs: main() done\n");
+
+    return 0;
+}
+
+
+static VOID WINAPI
+ServiceMain(DWORD argc, LPTSTR argv[])
+{
+    DWORD i;
+
+    hLogFile = fopen(LogFileName, _T("w+"));
+    if (hLogFile == NULL)
+        return;
+
+    LogEvent(_T("Entering ServiceMain"), 0, FALSE);
+
+    hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    hServStatus.dwCurrentState = SERVICE_START_PENDING;
+    hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+        SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
+    hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+    hServStatus.dwServiceSpecificExitCode = 0;
+    hServStatus.dwCheckPoint = 0;
+    hServStatus.dwWaitHint = 2*CS_TIMEOUT;
+
+    hSStat = RegisterServiceCtrlHandler("tcpsvcs", ServerCtrlHandler);
+    if (hSStat == 0)
+        LogEvent(_T("Failed to register service\n"), 100, TRUE);
+
+    LogEvent(_T("Control handler registered successfully"), 0, FALSE);
+    SetServiceStatus (hSStat, &hServStatus);
+    LogEvent(_T("Service status set to SERVICE_START_PENDING"), 0, FALSE);
+
+    if (CreateServers() != 0)
+    {
+        hServStatus.dwCurrentState = SERVICE_STOPPED;
+        hServStatus.dwServiceSpecificExitCode = 1;
+        SetServiceStatus(hSStat, &hServStatus);
+        return;
+    }
+
+    LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status"), 0, FALSE);
+    /*  We will only return here when the ServiceSpecific function
+        completes, indicating system shutdown. */
+    UpdateStatus (SERVICE_STOPPED, 0);
+    LogEvent(_T("Service status set to SERVICE_STOPPED"), 0, FALSE);
+    fclose(hLogFile);  /*  Clean up everything, in general */
+    return;
+
+}
+
+VOID WINAPI
+ServerCtrlHandler(DWORD Control)
+{
+    switch (Control)
+    {
+        case SERVICE_CONTROL_SHUTDOWN: /* fall through */
+        case SERVICE_CONTROL_STOP:
+            ShutDown = TRUE;
+            UpdateStatus(SERVICE_STOP_PENDING, -1);
+            break;
+        case SERVICE_CONTROL_PAUSE:
+            PauseFlag = TRUE;
+            break;
+        case SERVICE_CONTROL_CONTINUE:
+            PauseFlag = FALSE;
+            break;
+        case SERVICE_CONTROL_INTERROGATE:
+            break;
+        default:
+            if (Control > 127 && Control < 256) /* user defined */
+            break;
+    }
+    UpdateStatus(-1, -1); /* increment checkpoint */
+    return;
+}
+
+
+void UpdateStatus (int NewStatus, int Check)
+/*  Set a new service status and checkpoint (either specific value or increment) */
+{
+    if (Check < 0 ) hServStatus.dwCheckPoint++;
+    else            hServStatus.dwCheckPoint = Check;
+    if (NewStatus >= 0) hServStatus.dwCurrentState = NewStatus;
+    if (!SetServiceStatus (hSStat, &hServStatus))
+        LogEvent (_T("Cannot set service status"), 101, TRUE);
+    return;
+}
+
+INT
+CreateServers()
+{
     DWORD dwThreadId[NUM_SERVICES];
     HANDLE hThread[NUM_SERVICES];
     INT i;
 
+    UpdateStatus(-1, -1); /* increment checkpoint */
+
     /* Create MAX_THREADS worker threads. */
     for( i=0; i<NUM_SERVICES; i++ )
     {
-        /* Allocate memory for thread data. */
-        pServices[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICES));
+        _tprintf(_T("Starting %s server....\n"), Services[i].Name);
 
-        if( pServices[i] == NULL )
-            ExitProcess(2);
-
-        /* Generate unique data for each thread. */
-        pServices[i]->Service = ServiceHandler[i];
-        pServices[i]->Port = ServicePort[i];
-
         hThread[i] = CreateThread(
             NULL,              // default security attributes
             0,                 // use default stack size
             StartServer,       // thread function
-            pServices[i],      // argument to thread function
+            &Services[i],     // argument to thread function
             0,                 // use default creation flags
             &dwThreadId[i]);   // returns the thread identifier
 
         /* Check the return value for success. */
         if (hThread[i] == NULL)
         {
+            _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
             ExitProcess(i);
         }
     }
@@ -125,20 +219,42 @@
     {
         CloseHandle(hThread[i]);
     }
-
+    return 0;
 }
 
-int
-main(int argc, char *argv[])
+
+/*  LogEvent is similar to the ReportError function used elsewhere
+    For a service, however, we ReportEvent rather than write to standard
+    error. Eventually, this function should go into the utility
+    library.  */
+VOID
+LogEvent (LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg)
 {
-    DPRINT("tcpsvcs: main() started\n");
+    DWORD eMsgLen, ErrNum = GetLastError ();
+    LPTSTR lpvSysMsg;
+    TCHAR MessageBuffer[512];
 
-    StartServiceCtrlDispatcher(ServiceTable);
+    if (PrintErrorMsg) {
+        eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+            FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+            ErrNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+            (LPTSTR)&lpvSysMsg, 0, NULL);
 
-    DPRINT("Umpnpmgr: main() done\n");
+        _stprintf (MessageBuffer, _T("\n%s %s ErrNum = %d. ExitCode = %d."),
+            UserMessage, lpvSysMsg, ErrNum, ExitCode);
+        HeapFree (GetProcessHeap (), 0, lpvSysMsg);
+                /* Explained in Chapter 6. */
+    } else {
+        _stprintf (MessageBuffer, _T("\n%s ExitCode = %d."),
+            UserMessage, ExitCode);
+    }
 
-    ExitThread(0);
+    fputs (MessageBuffer, hLogFile);
 
-    return 0;
+    if (ExitCode > 0)
+        ExitProcess (ExitCode);
+    else
+        return;
 }
+
 #endif

Modified: trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.h
--- trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.h	2005-10-03 14:42:34 UTC (rev 18247)
+++ trunk/reactos/apps/utils/net/tcpsvcs/tcpsvcs.h	2005-10-03 18:32:30 UTC (rev 18248)
@@ -5,9 +5,10 @@
 #define QOTD_PORT 17
 #define CHARGEN_PORT 19
 
-#define NUM_SERVICES 6
+#define NUM_SERVICES 5
 #define BUF_SIZE 255
 #define BUF 1024
+#define CS_TIMEOUT 1000
 
 /* RFC865 states no more than 512 chars per line */
 #define MAX_QUOTE_BUF 512
@@ -22,16 +23,24 @@
 /* data structure to pass to threads */
 typedef struct _Services {
     INT Port;
+    TCHAR *Name;
     LPTHREAD_START_ROUTINE Service;
 } SERVICES, *PSERVICES;
 
-/* tcpsvcs functions */
-//static VOID CALLBACK ServiceMain(DWORD argc, LPTSTR *argv);
 
+/* tcpsvcs functions * /
+static VOID WINAPI ServiceMain(DWORD argc, LPTSTR argv[]);
+VOID WINAPI ServerCtrlHandler(DWORD control);
+INT CreateServers(VOID);
+VOID LogEvent (LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg);
+void UpdateStatus (int NewStatus, int Check);
+*/
+
 /* skelserver functions */
 DWORD WINAPI StartServer(LPVOID lpParam);
 SOCKET SetUpListener(const char* ServAddr, int Port);
-VOID AcceptConnections(SOCKET ListeningSocket, LPTHREAD_START_ROUTINE Service);
+VOID AcceptConnections(SOCKET ListeningSocket,
+    LPTHREAD_START_ROUTINE Service, TCHAR *Name);
 BOOL EchoIncomingPackets(SOCKET sd);
 BOOL ShutdownConnection(SOCKET Sock, BOOL bRec);