This article evolved from my frustration in developing and debugging CGI programs written for the AuctionBot, a multi-purpose auction server. I found that the available C libraries, C++ class libraries and web server extensions did not fit my needs so I decided to implement a different approach based on debugging over TCP sockets. Using this approach, I have successfully implemented and debugged most of the CGI's for this project.
My development machine at work is a Sun Ultra 1 running Solaris 2.5. At home I have a Linux box running RedHat 5.0. I developed all my debugging code under Linux. Linux provides a very stable development environment that allowed me to develop, test and experiment locally, without requiring remote login to the Sun. Once the code was running, I simply moved it over to the Sun, built it and started using it.
A common CGI debugging technique involves capturing the environment that a CGI is run under (usually to a disk file), restoring the environment on a local machine and running the CGI locally within the restored environment. Using this technique, CGI's can be run from the command-line, or from within a debugger (gdb
for example) and debugged using familiar debugging techniques. This technique is straight forward, but requires the developer to perform the extra work of capturing and restoring the CGI runtime environment.
Another problem in debugging CGI's is viewing the output of a CGI that fails to run correctly. If you are using Apache 1.2 or later, this can be addressed by configuring the web server to log error messages to a error log file. This approach works for some classes of problems, but does not provide the granularity I wanted.
One could write debugging/status information to log files and use tail -f logfile
to view the file. This works, but can produce deadlock conditions if multiple copies of your CGI are running and they attempt to use the same shared resource (the log file) and do not use file locking. Developers must provide file locking code and handle possible deadlock conditions, including cases where a CGI crashes before it releases its file lock [1]. In addition, all writes must be atomic to ensure correct output.
Ideally, one would like to debug the CGI in its natural surroundings, i.e. from within environment created by the web server, without any extra setup work.
SocketDB
provides the required behavior to debug CGI's over TCP sockets. The class supplies methods to connect to the server and write strings over a TCP socket.
class SocketDB { private: int mSD; ErrorTypes mErrorType; int mConnected; public: SocketDB(); SocketDB(char *name, int port); ~SocketDB(); int Connected() { return mConnected; } int ErorType() { return mErrorType; } int Connect(char *name, int port); int Print(char *format,...); int Println(char *format,...); };To connect to the server use the
SocketDB
constructor passing the server name and port, or use the Connect
method. Both will attempt to connect to the server on the specified port. Use the Connected
method to determine if the connection was successful or you can use the return value of Connect
. The Connect
method returns 1 if connected, otherwise, 0. If a connect error occurs, use the ErorType
method to get error information. The file Socket.C
enumerates the error types.
DebugClient
(see DebugClient.C) shows how to use the class. For simplicity, I designed this program to run from the command-line, rather than a CGI program run by the web server. I choose this approach so users could quickly run the program and see how the socket debug class works. Integrating the class into a CGI is very straight forward.
The program attempts to connect to the debug server program specified by the command-line arguments host and port (see source code). If it fails to connect, it prints a message, and the error code and exits. If it connects, it prints the test string, writes the same string over a TCP socket to debug server and reports the result of the debug server write.
DebugServer
(see DebugServer.C) implements an example debug server [2]. This program is a simple echo server that creates a socket, binds to it and accepts connections from clients. Once it gets a connection it forks off and handles the connection. In this case it just reads a string and echoes it.
cd
to the directory containing the example programs and type DebugServer [port]
where port is the port you want the server to listen on. For example, to run the program on port 4000, type DebugServer 4000
.
In another shell cd
to the directory containing the example programs and type DebugClient [host] [port]
where host is the host name of the machine the server is running on (get this by typing hostname
at the command prompt) and the port is the port were the server to listening (4000 for example).
You should see a text string written to the server and to the shell.
Code: http://groucho.eecs.umich.edu/~omalley/software/socket_debug-1.0.tar.gz