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 * - Start tcpsvcs as a service.
17 * - write debugging function and print all dbg info via that.
30 static SERVICE_STATUS hServStatus
;
31 static SERVICE_STATUS_HANDLE hSStat
;
33 BOOL bLogEvents
= TRUE
;
34 BOOL ShutDown
, PauseFlag
;
35 LPCTSTR LogFileName
= "tcpsvcs_log.log";
37 static SERVICE_TABLE_ENTRY
40 {_T("tcpsvcs"), ServiceMain
},
46 Services
[NUM_SERVICES
] =
48 {ECHO_PORT
, _T("Echo"), EchoHandler
},
49 {DISCARD_PORT
, _T("Discard"), DiscardHandler
},
50 {DAYTIME_PORT
, _T("Daytime"), DaytimeHandler
},
51 {QOTD_PORT
, _T("QOTD"), QotdHandler
},
52 {CHARGEN_PORT
, _T("Chargen"), ChargenHandler
}
58 DWORD dwThreadId
[NUM_SERVICES
];
59 HANDLE hThread
[NUM_SERVICES
];
64 if ((RetVal
= WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0)
66 _tprintf(_T("WSAStartup() failed : %lu\n"), RetVal
);
70 /* Create MAX_THREADS worker threads. */
71 for( i
=0; i
<NUM_SERVICES
; i
++ )
73 _tprintf(_T("Starting %s server....\n"), Services
[i
].Name
);
75 hThread
[i
] = CreateThread(
76 NULL
, // default security attributes
77 0, // use default stack size
78 StartServer
, // thread function
79 &Services
[i
], // argument to thread function
80 0, // use default creation flags
81 &dwThreadId
[i
]); // returns the thread identifier
83 /* Check the return value for success. */
84 if (hThread
[i
] == NULL
)
86 _tprintf(_T("Failed to start %s server....\n"), Services
[i
].Name
);
91 /* Wait until all threads have terminated. */
92 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
94 /* Close all thread handles upon completion. */
95 for(i
=0; i
<NUM_SERVICES
; i
++)
97 CloseHandle(hThread
[i
]);
104 /* code to run tcpsvcs as a service through services.msc */
107 main(int argc
, char *argv
[])
109 //DPRINT("tcpsvcs: main() started. See tcpsvcs_log.txt for info\n");
111 if (!StartServiceCtrlDispatcher(ServiceTable
))
112 _tprintf(_T("failed to start the service control dispatcher\n"));
114 //DPRINT("tcpsvcs: main() done\n");
121 ServiceMain(DWORD argc
, LPTSTR argv
[])
125 hLogFile
= fopen(LogFileName
, _T("w+"));
126 if (hLogFile
== NULL
)
129 LogEvent(_T("Entering ServiceMain"), 0, FALSE
);
131 hServStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
132 hServStatus
.dwCurrentState
= SERVICE_START_PENDING
;
133 hServStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|
134 SERVICE_ACCEPT_SHUTDOWN
| SERVICE_ACCEPT_PAUSE_CONTINUE
;
135 hServStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
136 hServStatus
.dwServiceSpecificExitCode
= 0;
137 hServStatus
.dwCheckPoint
= 0;
138 hServStatus
.dwWaitHint
= 2*CS_TIMEOUT
;
140 hSStat
= RegisterServiceCtrlHandler("tcpsvcs", ServerCtrlHandler
);
142 LogEvent(_T("Failed to register service\n"), 100, TRUE
);
144 LogEvent(_T("Control handler registered successfully"), 0, FALSE
);
145 SetServiceStatus (hSStat
, &hServStatus
);
146 LogEvent(_T("Service status set to SERVICE_START_PENDING"), 0, FALSE
);
148 if (CreateServers() != 0)
150 hServStatus
.dwCurrentState
= SERVICE_STOPPED
;
151 hServStatus
.dwServiceSpecificExitCode
= 1;
152 SetServiceStatus(hSStat
, &hServStatus
);
156 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status"), 0, FALSE
);
157 /* We will only return here when the ServiceSpecific function
158 completes, indicating system shutdown. */
159 UpdateStatus (SERVICE_STOPPED
, 0);
160 LogEvent(_T("Service status set to SERVICE_STOPPED"), 0, FALSE
);
161 fclose(hLogFile
); /* Clean up everything, in general */
167 ServerCtrlHandler(DWORD Control
)
171 case SERVICE_CONTROL_SHUTDOWN
: /* fall through */
172 case SERVICE_CONTROL_STOP
:
174 UpdateStatus(SERVICE_STOP_PENDING
, -1);
176 case SERVICE_CONTROL_PAUSE
:
179 case SERVICE_CONTROL_CONTINUE
:
182 case SERVICE_CONTROL_INTERROGATE
:
185 if (Control
> 127 && Control
< 256) /* user defined */
188 UpdateStatus(-1, -1); /* increment checkpoint */
193 void UpdateStatus (int NewStatus
, int Check
)
194 /* Set a new service status and checkpoint (either specific value or increment) */
196 if (Check
< 0 ) hServStatus
.dwCheckPoint
++;
197 else hServStatus
.dwCheckPoint
= Check
;
198 if (NewStatus
>= 0) hServStatus
.dwCurrentState
= NewStatus
;
199 if (!SetServiceStatus (hSStat
, &hServStatus
))
200 LogEvent (_T("Cannot set service status"), 101, TRUE
);
207 DWORD dwThreadId
[NUM_SERVICES
];
208 HANDLE hThread
[NUM_SERVICES
];
211 UpdateStatus(-1, -1); /* increment checkpoint */
213 /* Create MAX_THREADS worker threads. */
214 for( i
=0; i
<NUM_SERVICES
; i
++ )
216 _tprintf(_T("Starting %s server....\n"), Services
[i
].Name
);
218 hThread
[i
] = CreateThread(
219 NULL
, // default security attributes
220 0, // use default stack size
221 StartServer
, // thread function
222 &Services
[i
], // argument to thread function
223 0, // use default creation flags
224 &dwThreadId
[i
]); // returns the thread identifier
226 /* Check the return value for success. */
227 if (hThread
[i
] == NULL
)
229 _tprintf(_T("Failed to start %s server....\n"), Services
[i
].Name
);
234 /* Wait until all threads have terminated. */
235 WaitForMultipleObjects(NUM_SERVICES
, hThread
, TRUE
, INFINITE
);
237 /* Close all thread handles upon completion. */
238 for(i
=0; i
<NUM_SERVICES
; i
++)
240 CloseHandle(hThread
[i
]);
246 /* LogEvent is similar to the ReportError function used elsewhere
247 For a service, however, we ReportEvent rather than write to standard
248 error. Eventually, this function should go into the utility
251 LogEvent (LPCTSTR UserMessage
, DWORD ExitCode
, BOOL PrintErrorMsg
)
253 DWORD eMsgLen
, ErrNum
= GetLastError ();
255 TCHAR MessageBuffer
[512];
258 eMsgLen
= FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER
|
259 FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
260 ErrNum
, MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
261 (LPTSTR
)&lpvSysMsg
, 0, NULL
);
263 _stprintf (MessageBuffer
, _T("\n%s %s ErrNum = %d. ExitCode = %d."),
264 UserMessage
, lpvSysMsg
, ErrNum
, ExitCode
);
265 HeapFree (GetProcessHeap (), 0, lpvSysMsg
);
267 _stprintf (MessageBuffer
, _T("\n%s ExitCode = %d."),
268 UserMessage
, ExitCode
);
271 fputs (MessageBuffer
, hLogFile
);
274 ExitProcess (ExitCode
);