daveb.net : bsdproxy

Background

Not long ago I came across Jonathan Lemon's new FreeBSD system calls: kqueue(2) and kevent(2). These functions allow one to monitor a set of file descriptors without the overhead of select(2) and poll(2) when the number of file descriptors is large. They therefore provide a superior way to implement event-driven programs where the events in question take place on file descriptors. An example of such a program would be a web server which must handle a large number of simultaneous clients.

I wanted to write a program with a kevent-based event loop, just for fun. That is the reason I wrote bsdproxy. The program itself is nothing more than a transparent TCP proxy which sits between the two ends of a connection and forwards data back and forth without modifying it. However, it could conceivably be of use in some situations (see the README for details).

The program is designed to be as efficient as possible so as to maximize the number of simultaneous connections it can support. It works especially well when there is an asymmetry between the connections to the "client" on one side and the "server" on the other. For example, if bsdproxy is used in front of a web server on the same machine, and serves data to clients on slow modem connections, it will buffer the responses from the server (which should arrive very quickly) in a queue of chunks of data which are sequentially written to the (slow) client whenever the client is ready to receive more data. This way, the server can close the connection to the proxy and continue satisfying other requests, while bsdproxy quietly continues emptying the queued response from the server.

All I/O is done in nonblocking mode, and connections to other hosts are also done without blocking. This way, bsdproxy never needs to block. Every event in the event loop is handled as rapidly as possible.

For the data queue implementation, I decided to use GLib. I did this because GLib uses a custom memory allocator which is several times faster than malloc(3) (for the parameters used in bsdproxy) and avoids memory fragmentation. This is especially useful for things like linked lists, which frequently allocate and deallocate small blocks of memory. It is also useful for the queue buffers I use to queue data sent back and forth, since these chunks of memory can be reused and passed around to where they are needed.

I have used bsdproxy to proxy HTTP, HTTPS, SMTP, telnet, and MySQL - just to test it out. In principle, it should be capable of proxying any TCP-based communication between server and its clients.

One important limitation of bsdproxy is that it can only queue data up to the available memory on the machine. It does not write queued data to disk. There are no preset limits on the amount of data which can be queued. I might change this some day, but for now, I merely provide bsdproxy in its current form. Also, the kevent API used is that provided with FreeBSD 4.1/4.2. I believe this API has changed in FreeBSD 5.0 but I have not checked it out.

Download

Tarball:

Header files:

Source files:


© 1999-2013 by Dave Bailey