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