wsinetd's ambition is to be the Windows NT's equivalent of the standard Unix inetd super daemon.
The wsinetd project is hosted at SourceForge, is maintained by Denis Bernard <wsinetd@wildservices.net> and is released under the terms of the GNU General Public License (see the COPYRIGHT section below).
For those who don't even know what is inetd (Internet Daemon):
"It listens for connections on certain internet sockets. When a connection is found on one of its sockets, it decides what service the socket corresponds to, and invokes a program to service the request. After the program is finished, it continues to listen on the socket. Essentially, inetd allows running one daemon to invoke several others, reducing load on the system." (excerpt from the inetd manpage, author unknown)
wsinetd runs as a Windows NT service under LocalSystem account, allowing for user authentication and impersonation by the invoked servers.
It is designed to run on Windows NT and its derivates: Windows 2000, and XP. The core module (socket
listening and pipe server) should be portable to Windows 9x/Me without changes in the core's code, but since I
didn't see the point in running such a software on Windows 9x, I've choosen not to support these platforms.
Having said that, any contributions are welcome (see the developpers notes section).
The invoked programs read commands from their stdin and answer to their stdout
with standard file I/O. It doesn't work with programs that expect a socket
descriptor for file I/O since unsing sockets as files isn't fully supported
under Windows (i.e. using it with Cygwin's inetutils won't work).
That's why this program was written: many unix server software are portable to
Windows, but they often need a "wrapper" to start them on a pre-established
connection with a client (as does inetd under unix); if the server software
doesn't perform socket specific operations on its stdio, wsinetd will do the
job.
wsinetd can also be used to create Windows native servers without worrying
about Windows Sockets programming: in your server, everything you have to do
(beside the server specific logic) is to read the client's commands from stdin and
output answers to stdout ! Implementing an Internet server is now so simple ;)
DO NOT USE wsinetd IN PRODUCTION ENVIRONMENTS - THIS IS STILL PRE-ALPHA SOFTWARE !!!
Actually, the sole protection resides in the possible limitation of the number
of concurent connections; but unlike inetd, the number of connections in the last minute isn't
monitored. Anyway, there is an hardcoded limitation of 2048 concurent connections per listened port.
I haven't been able to test it yet, but I'm pretty sure that any big server will be on
its knees before reaching this limit.
You should also be aware that the invoked servers will run as LocalSystem,
this means that if the server doesn't authenticate and impersonate the remote
user upon connection (like any pop/imap/ftp/etc. server does), depending of the
server software functionalities and/or holes, the remote user will be able to
do lots of nasty things on your machine... Have a look at the sample
configuration file below and you'll see what can be done...
See the TECHNICAL INFOS
wsinetd is downloadable from the download page hosted by SourceForge.
Microsoft Visual C++ 6.0 (sp3 ?) is required to build from the provided project
files. Anyway, porting to older versions of MSVC should be easy, as well as
porting to other Windows C compilers.
Load wsinetd.dsw in MSVC and compile the msgdll sub-project first. This will
create wsinetd.dll and eventlog.h (required to compile the main executable).
This dll contains message templates for NT's event log.
Then compile the main project, wsinetd. Note that to compile for Windows NT 4,
you should change the pre-processor options
In the configuration file, lines beginning with a # or left blank are ignored.
Each server is defined on a separate line:
where:
Here is a sample config file:
The last line of this sample configuration file is parsed by wsinetd like this:
Copy wsinetd.exe AND wsinetd.dll AND wsinetd.conf in any folder you like, then
in a shell, CD to that folder and type the command:
and you're off !
If you want the service to start automatically upon system startup, you can do
it by using NT's service control manager.
to start the service manually, type:
to stop it, type:
To uninstall the service, stop it first, then type:
NOTICE: when you change the config file, the service must be restarted.
Please read the TECHNICAL INFOS section once again.
I've tested wsinetd with a few servers:
The only problem I've encountered was with Microsoft Outlook 2000
and UW's imapd (native Win2k version, not the Cygwin's one): when I do a "Download all" in Outlook, the "Download
window" opens, but oulook deadlocks here... if it is terminated from the task
manager, the pipe-server, its child threads and the spawned process cleanup
gracefully... I've tested many things but with
no clue... (see developpers notes if you're interested). Anyway, it works very
well with MS Outlook Express 6 or with MS Outllok 2000 + imapd in its Cygwin version...
Any reports on success/failure stories with various client-server combinations are
welcome.
Contributions and/or enhancements are welcome !
You can start wsinetd with the -d option from within MSVC, wsinetd will then
start in a console. It will run on your user account (no LocalSystem
privileges, aren't you ?). To terminate it, hit return in the console window.
It outputs extensive debugging information to the active Windows debugger. You
can use DbMon from Microsoft's Platform SDK for example.
About the problem with MS Outlook 2000 & imapd Win2k: I thought that
Outlook was faulty, but from time to time, it worked fine or randomly...
For example, here is the old version of
which didn't work but, this one did:
Despite being theorically useless on byte-oriented anonymous pipes,
Note also that Unicode support is in progress but it hasn't been tested yet
(it shouldn't even compile).
The stack of each thread is allocated in the address space of the process.
With a maximum addressable momory of 2G per process, with the settings used in If necessary, this limit could be pushed up by:
The second and third topics, if done together would make wsinetd itself useless. Anyway wsinetd isn't
intended to run high duty servers. So, I'll probably focus only on the first and third ones.
I wish to thank Mark Crispin, author of the University
of Washinon's IMAP Toolkit, for granting me the permission to freely copy and paste huge parts
of code from inetlisn (not part of the IMAP Toolkit). In fact, wsinetd is completely build upon
Mark's work. I'm sorry Mark, I didn't use the Free Fork License, it was much too work for me to
adapt it, and I prefer granting privileges to the final user reather than to me (I'm only speaking
about this project ;)
Lots of things:
TECHNICAL INFOS (IMPORTANT READING !)
LIMITATIONS
GETTING wsinetd
BUILDING wsinetd
_WIN32_WINNT
and WINVER
from 0x0500
to 0x0400
.
CONFIGURATION FILE
<port> <max_connections> <path_to_executable> <command_line>
<port>
<max_connections>
<path_to_executable>
<command_line>
# sample config file
# pop2-3 server (the popd daemon uses the pop2 protocol when started as pop2 ...
# and pop3 when started as pop3)
pop2 -1 "c:\program files\popserver\popd.exe" pop2 --no-sockets
pop3 -1 "c:\program files\popserver\popd.exe" pop3 --no-sockets
# imap4r1 server (no particular cmd line here), the limit is set up to comply with
# the maximum expected load on a small intranet (10 machines)
imap4 60 c:\ImapToolkit-2001a\imapd.exe
# hacky remote shell run with LocalSystem's privileges (no auth !)
# never do this, except if you REALLY KNOW what you're doing !!!
# the limit is simple: reserved use for me
12345 1 C:\winnt\system32\cmd.exe
# simple perl script used as a server...
# note that the executable path is repeated twice.
11111 5 c:\perl\bin\perl.exe c:\perl\bin\perl.exe -w "c:\My Scripts\testbed.pl"
port
11111
max_connections
5
path_to_executable
c:\perl\bin\perl.exe
command_line
c:\perl\bin\perl.exe -w "c:\My Scripts\testbed.pl"
INSTALLING wsinetd AS A SERVICE
wsinetd -i
net start wsinetd
net stop wsinetd
wsinetd -u
BUGS & OTHER IMPORTANT NOTICES
int main(int argc, char **argv) {
int c;
while ((c=getchar ()) != EOF) { putchar (c); fflush (stdout); }
}
NOTES TO DEVELOPPERS
Internal synopsis:
service_main()
// main func, called upon service startup
-> service_init()
setup glocal objects
read config file
start a new paused listener thread for each server (entrypoint is wsinetd_main())
starts listener threads
waits for a stop event (triggered by the service control dispatcher)
waits for all listeners to shutdown
bailout
wsinetd_main()
// listens for incoming connections
starts a new pipe_server() thread for each accepted connection
if stop event triggered, waits for shitdown of its child threads (pipe servers) then exits
pipe_server()
setup pipes
setup input thread (reads data from spawned process and sends it to connected client)
setup output thread (reads data from connected client and sends it to spawned process)
spawns the server process
waits for either stop_event/input thread/output thread/spawned process and tries to
terminate the others gracefully
othread()
:
unsigned __stdcall othread (void * data)
{
STREAM *stream = data;
char buf[1];
long i;
while ((i = recv (stream->sock, buf, 1, 0)) > 0 &&
WriteFile (stream->ohdl, buf, 1, (DWORD*)&i, NULL));
return 0;
}
...
while ((i = recv (stream->sock, buf, 1, 0)) > 0 &&
WriteFile (stream->ohdl, buf, 1, (DWORD*)&i, NULL) &&
FlushFileBuffers (stream->ohdl));
...
FlushFileBuffers()
seemed to do it, and Outlook never failed. I
wanted to optimize a little the I/O speed and enlarged the buffer size (for
byte-stream sockets, receipt of a single byte is sufficient to unblock the
caller).
Now it doesn't work anymore with Outlook: This modification only changed
slightly the code size (10 bytes ?), execution time (a few CPU cycles) and data
alignment... I've tried lots of things, even a highly complex asynchronous I/O
mechanism in the I/O threads, allowing for example non-concurent use of the
client socket, but nothing helped. And worse: it works well with imapd in its
Cygwin version... Who's at fault ? Outlook, wsinetd or imapd ? In most
stories, the man in the middle is always the bad one, so wsinetd is my main
suspect, but who knows... If you've got a clue, I'd be happy to hear from you!
Maximum concurent connections
wsinetd.h
,
we can create 2G / (128K + 64K + 64K) = 8192 maximum simultaneous client connections (1 pipe + 2 io per connection).
Note that the listener threads aren't taken in account here.
I haven't been able to test it yet, but I'm pretty sure that any big server will be on
its knees before reaching this limit (even if only the first page of the stack memory is commited).
Another little thing to take in account is that there's a new process created for each client connection,
and Windows isn't written to run thousands of processes simultaneously...
main()
, it handles reception of the listening and first client sockets from the
listener process, then acts as servers ran by the Unix inetd in wait mode (takes over socket listening and
creates a new thread for each new connection, calling the server's original main()
)...
This implies naturally that the whole server is written in a thread safe manner (no global data for example)Advices for a Windows 9x port
<TROLLMODE>
Before thinking about porting to Windows 9x, you should think about
installing a real OS...</TROLLMODE>
But, if you really want to, porting to Win9x should be simple. First create a separate project file
(call it wsinetd9x for example), include wsinetd.c (listener/pipe-server) and util.c in this project
and create a main.c or service.c that will be specific to Win9x (copy the original service.c and
remove all nt's specific stuff). Then, all you have to to is to add W9x specific service management
and rewrite the error log routines.
CREDITS
TODO
The main priority being for the moment to correct that damned bug which showed up with MS
Outlook 2000 used together with UW's imapd Win2K.
COPYRIGHT
wsinetd - Windows Simple inetd daemon
Copyright (C) 2001-2002 Denis Bernard <wsinetd@wildservices.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
REVISON HISTORY
Note about version numbering: in version number x.y.z, x is the major version number, y is the minor
one and z is the build number in the same major version.
2002/12/19 v0.3.8
- Changed compilation options for msgdll: uses now msvcrt.dll
- Made wsinetd project dependant on msgdll (also added a dummy .lib for
msgdll)
- added a script to help in automatic building of releases.
2002/12/18 v0.3.6
- Corrected wrong handling of command lines in the config file. Thanks Hua ;)
2001/11/20 v0.2.5
- Enhanced service cleanup: on stop/shutdown, the service waits for all
spawned threads/processes to terminate, (eventualy forcing their
termination)
- Maximum concurent connections handling: CHANGES IN THE CONFIG FILE FORMAT !
- Removed debug output from the cleanup code (caused deadlocks upon cleanup)
- Changes in the socket-to-pipe code (removed a dummy pseudo-optimization)
- Enhanced the config file parser: paths with spaces are now allowed
- Developpement status is still pre-alpha (deadlocks with MS Outlook 2K/imapd
still unsolved).
2001/11/13 v0.1.4
initial release