Win32 I/O completion ports code release

Toby Douglass toby.douglass at
Sun Dec 3 12:14:21 UTC 2006


I've written a tiny library which provides a simple front end for IO
completion ports.

The ultimate purpose of this is to provide excellent socket handling
under Win32 in libevent so that the socket problem Tor faces is solved.

My code base is written around a resource and error handling framework
and so the original code that I've written and tested was permeated with
that framework.

Having completed testing, I've removed my framework code from the
library and what remains is what I'm releasing here.

I originally intended to create a decent Win32 build of libevent library
and to integrate this code.  However, last night when I finally had a
proper stab at this, I found the libevent code badly disorganised (poor
header file/code structure) and after an hour or so, I gave up.  As 
such, I'm releasing my code here and hoping either a libevent expert 
will integrate it or Tor will use it directly.

I will be supporting this code.  If people have problems with it or need
changed, I will make those changes.

One technical note; I believe that I/O completion ports cannot handle
accept() type behaviour, only recv() and send().  I have however written
a WaitForMultipleObjects() based listen/accept handling library, which
might be particularly useful in conjunction with this IOCP code.

Technical Information
The API has three functions and is best explained by stating these

1. void socket_iocp_new( void **socket_iocp_state );
2. void socket_iocp_delete( void *socket_iocp_state );
3. void socket_iocp_add_socket( void *socket_iocp_state, SOCKET socket,
void *user_state, size_t read_buffer_size, void
(*callback_function)(SOCKET socket, int event_type, void *read_buffer,
DWORD byte_count, void *user_state) );

The purpose of the first two functions is obvious.

 From the users view, the API works like this; you give a socket, a
callback function and a pointer to state of your own (if you have any)
to the API and it will call that callback when a read has occurred.

The callback function is;

void callback_function( SOCKET socket, int event_type, void
*read_buffer, DWORD byte_count, void *user_state );

So, you are given the socket which has completed a read (or errored),
the event type (read or error), the read buffer, and number of bytes in
the buffer, and a pointer to your own state.

When the socket closes, the OS automatically removes it from the IOCP
socket list, which is why there is no delete_socket() function.

Build and Link
I use VC6 and I've arranged the code as a statically linked library.

The file and directory structure is;

libiocp/libiocp.h // public header file to be used with the .lib


The debug and release libraries are created to these pathnames;

libiocp/libiocp (debug).lib
libiocp/libiocp (release).lib

So the basic arrangement is that the public files (libraries and the
public header) are in the root, while the code and build files are in
the subdirectory libiocp.

The code compiles without error with level 4 warnings and warnings as
errors.  I've had to pragma warnings 4005, 4201 and 4305 so that the MS
headers will compile with warnings at level 4.

(I've just been discovering some bad behaviour in WinZip, while making
up the archive.  If you have empty directories in the archive, *they
will not be shown in the archive listing in WinZip*, but they WILL be
created - so you have invisible directories!  also, if you delete all
the files in archive, *the archive file is deleted*, so you then need to
remake it to add files to the archive - which is annoying, because I
added the wrong files, so I deleted them all, went to add the files I
did want...and found I couldn't add them.  I had to go remake the
archive first, despite having *just* made the archive in the first place).

Homepage and Direct Download

More information about the tor-dev mailing list