3 * Copyright (C) 2005 ReactOS Team
5 * LICENCE: GPL - See COPYING in the top level directory
6 * PROJECT: ReactOS simple TCP/IP services
7 * FILE: apps/utils/net/tcpsvcs/tcpsvcs.c
8 * PURPOSE: Provide CharGen, Daytime, Discard, Echo, and Qotd services
9 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
16 * - fix bug when terminating chargen server
17 * - log info in the event logger (when it's implemented)
30 VOID WINAPI
ServiceMain(DWORD argc
, LPTSTR argv
[]);
32 static SERVICE_STATUS hServStatus
;
33 static SERVICE_STATUS_HANDLE hSStat
;
36 BOOL bShutDown
= FALSE
;
39 LPCTSTR LogFileName
= "\\tcpsvcs_log.log";
40 LPTSTR ServiceName
= _T("Simp Tcp");
41 //LPTSTR DisplayName = _T("Simple TCP/IP Services");
44 Services
[NUM_SERVICES
] =
46 {ECHO_PORT
, _T("Echo"), EchoHandler
},
47 {DISCARD_PORT
, _T("Discard"), DiscardHandler
},
48 {DAYTIME_PORT
, _T("Daytime"), DaytimeHandler
},
49 {QOTD_PORT
, _T("QOTD"), QotdHandler
},
50 {CHARGEN_PORT
, _T("Chargen"), ChargenHandler
}
57 SERVICE_TABLE_ENTRY ServiceTable
[] =
59 {ServiceName
, ServiceMain
},
63 //DPRINT("Starting tcpsvcs service. See \system32%s for logs\n", LogFileName);
65 if (! StartServiceCtrlDispatcher(ServiceTable
))
66 LogEvent(_T("failed to start the service control dispatcher\n"), -1, TRUE
);
68 //DPRINT("Shutdown tcpsvcs service\n");
75 ServiceMain(DWORD argc
, LPTSTR argv
[])
77 TCHAR LogFilePath
[MAX_PATH
];
79 if(! GetSystemDirectory(LogFilePath
, MAX_PATH
))
82 _tcscat(LogFilePath
, LogFileName
);
84 hLogFile
= fopen(LogFilePath
, _T("a+"));
89 _stprintf(buf
, _T("Could not open log file: %s\n"), LogFilePath
);
90 MessageBox(NULL
, buf
, NULL
, MB_OK
);
95 LogEvent(_T("Entering ServiceMain\n"), 0, FALSE
);
97 hServStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
98 hServStatus
.dwCurrentState
= SERVICE_START_PENDING
;
99 hServStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|
100 SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_PAUSE_CONTINUE
;
101 hServStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
102 hServStatus
.dwServiceSpecificExitCode
= NO_ERROR
;
103 hServStatus
.dwCheckPoint
= 0;
104 hServStatus
.dwWaitHint
= 2*CS_TIMEOUT
;
106 hSStat
= RegisterServiceCtrlHandler(ServiceName
, ServerCtrlHandler
);
108 LogEvent(_T("Failed to register service\n"), -1, TRUE
);
110 LogEvent(_T("Control handler registered successfully\n"), 0, FALSE
);
111 SetServiceStatus (hSStat
, &hServStatus
);
112 LogEvent(_T("Service status set to SERVICE_START_PENDING\n"), 0, FALSE
);
114 if (CreateServers() != 0)
116 hServStatus
.dwCurrentState
= SERVICE_STOPPED
;
117 hServStatus
.dwServiceSpecificExitCode
= 1;
118 SetServiceStatus(hSStat
, &hServStatus
);
122 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status\n"), 0, FALSE
);
123 /* We will only return here when the ServiceSpecific function
124 completes, indicating system shutdown. */
125 UpdateStatus (SERVICE_STOPPED
, 0);
126 LogEvent(_T("Service status set to SERVICE_STOPPED\n"), 0, FALSE
);
127 LogEvent(_T("Leaving ServiceMain\n"), 0, FALSE
);
136 ServerCtrlHandler(DWORD Control
)
140 case SERVICE_CONTROL_SHUTDOWN
: /* fall through */
141 case SERVICE_CONTROL_STOP
:
142 LogEvent(_T("stopping service\n"), 0, FALSE
);
143 InterlockedExchange((LONG
*)&bShutDown
, TRUE
);
144 UpdateStatus(SERVICE_STOP_PENDING
, -1);
146 case SERVICE_CONTROL_PAUSE
: /* not yet implemented */
147 LogEvent(_T("pausing service\n"), 0, FALSE
);
148 InterlockedExchange((LONG
*)&bPause
, TRUE
);
150 case SERVICE_CONTROL_CONTINUE
:
151 LogEvent(_T("continuing service\n"), 0, FALSE
);
152 InterlockedExchange((LONG
*)&bPause
, FALSE
);
154 case SERVICE_CONTROL_INTERROGATE
:
157 if (Control
> 127 && Control
< 256) /* user defined */
160 UpdateStatus(-1, -1); /* increment checkpoint */
165 void UpdateStatus (int NewStatus
, int Check
)
166 /* Set a new service status and checkpoint (either specific value or increment) */
169 hServStatus
.dwCheckPoint
++;
171 hServStatus
.dwCheckPoint
= Check
;
174 hServStatus
.dwCurrentState
= NewStatus
;
176 if (! SetServiceStatus (hSStat
, &hServStatus
))
177 LogEvent(_T("Cannot set service status\n"), -1, TRUE
);
185 DWORD dwThreadId
[NUM_SERVICES
];
186 HANDLE hThread
[NUM_SERVICES
];
192 if ((RetVal
= WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0)
194 _stprintf(buf
, _T("WSAStartup() failed : %lu\n"), RetVal
);
195 LogEvent(buf
, RetVal
, TRUE
);
199 UpdateStatus(-1, -1); /* increment checkpoint */
201 LogEvent(_T("Creating server Threads\n"), 0, FALSE
);
203 /* Create MAX_THREADS worker threads. */
204 for( i
=0; i
<NUM_SERVICES
; i
++ )
206 _stprintf(buf
, _T("Starting %s server....\n"), Services
[i
].Name
);
207 LogEvent(buf
, 0, FALSE
);
209 hThread
[i
] = CreateThread(
210 NULL
, // default security attributes
211 0, // use default stack size
212 StartServer
, // thread function
213 &Services
[i
], // argument to thread function
214 0, // use default creation flags
215 &dwThreadId
[i
]); // returns the thread identifier
217 /* Check the return value for success. */
218 if (hThread
[i
] == NULL
)
220 _stprintf(buf
, _T("Failed to start %s server....\n"), Services
[i
].Name
);
221 /* don't exit process via LogEvent. We want to exit via the server
222 * which failed to start, which could mean i=0 */
223 LogEvent(buf
, 0, TRUE
);
228 LogEvent(_T("setting service status to running\n"), 0, FALSE
);
230 UpdateStatus(SERVICE_RUNNING
, 0);
232 /* Wait until all threads have terminated. */
233 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
235 /* Close all thread handles upon completion. */
236 for(i
=0; i
<NUM_SERVICES
; i
++)
238 CloseHandle(hThread
[i
]);
241 LogEvent(_T("Detaching Winsock2...\n"), 0, FALSE
);
248 /* This is a temperary log system until our eventlog is in place */
251 LogEvent (LPCTSTR UserMessage
, INT ExitCode
, BOOL PrintErrorMsg
)
253 DWORD eMsgLen
, ErrNum
= GetLastError ();
255 TCHAR MessageBuffer
[512];
261 eMsgLen
= FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
|
262 FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
263 ErrNum
, MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
264 (LPTSTR
)&lpvSysMsg
, 0, NULL
);
266 _stprintf(MessageBuffer
, _T("%s %s ErrNum = %lu. ExitCode = %d."),
267 UserMessage
, lpvSysMsg
, ErrNum
, ExitCode
);
268 HeapFree(GetProcessHeap (), 0, lpvSysMsg
);
272 _stprintf(MessageBuffer
, _T("%s"), UserMessage
);
275 fputs (MessageBuffer
, hLogFile
);
278 ExitProcess(ExitCode
);