Click here to Skip to main content
15,886,100 members
Articles / Programming Languages / C++

Webio - An embedded web server

Rate me:
Please Sign up or sign in to vote.
4.88/5 (33 votes)
20 Jul 2008BSD3 min read 196.6K   3.8K   108  
A C-language web server with embedded files and CGI.
<head>
<title>Progman</title>

<style type="text/css">

body {
#  font-family: arial, helvetica, sans-serif;
}

.code {
  font-family: arial, helvetica, sans-serif;
  color: green;
}

.name {
  font-family: arial, helvetica, sans-serif;
  text-decoration: bold;
}

h2 {
   padding-left: 2em;
}

h3 {  
   padding-left: 4em;
}

h4 {  
   padding-left: 4em;
   margin-top: 1px;
   margin-bottom: 1px;
}
h5 {  
   padding-left: 8em;
   margin-top: 1px;
   margin-bottom: 1px;
}

</style>
</head>

<body>

<table><tr><td width=11></td><td>
<img src="webby.gif">
</td><td width=20 ></td><td valign=center >
<h1>Webio programmers manual</h1>
</td></tr></table>

Last edit: July 14th, 2008 by John Bartas
<hr>

<h2>Contents</h2>
<h4><a href="#Introduction">Introduction</a></h4>

<h4><a href="#Internal structure">Internal structure</a></h4>
<h5><a href="#Source files">Source files</a></h5>
<h5><a href="#threads entry point">Threads entry point</a></h5>
<h5><a href="#main objects">Main objects</a></h5>
<h5><a href="#heap memory">Heap memory</a></h5>

<h4><a href="#The demo application" >The demo application</a></h4>
<h5><a href="#Building on Linux with GCC">Building on Linux with GCC</a></h5>
<h5><a href="#Building on Windows via Visual Studio">Building on Windows via Visual Studio</a></h5>

<h4><a href="#Merging Webio with your target or application" >Merging Webio with your target or application</a></h4>
<h5><a href="#Initialization">Initialization</a></h5>
<h5><a href="#Runtime">Runtime</a></h5>

<h4><a href="#fsbuilder" >fsbuilder</a></h4>
<h5><a href="#Overview"></a></h5>
<h5><a href="$Per-file Options"></a></h5>
<h5><a href="#Command line Options">Command line Options</a></h5>
<h5><a href="#Static files">Static files</a></h5>
<h5><a href="#dynamic_content" >Dynamic content</a></h5>
<h5><a href="#ssi" >SSI</a></h5>
<h5><a href="#C-code expressions" >C-code expressions</a></h5>
<h5><a href="#cgi" >CGI</a></h5>
<h5><a href="#Redirecting to another file" >Redirecting to another file</a></h5>

<h4><a href="#Compile-time options" >Compile-time options</a></h4>

<h4><a href="#authentication">Authentication</a></h4>

<h4><a href="#Portability" >Portability</a></h4>
<h5><a href="#Header files" >Header files</a></h5>
<h5><a href="#Portbility routines" >Portbility routines</a></h5>

<h4><a href="#Debugging aids">Debugging aids</a></h4>
<h5><a href="#dtrap">dtrap</a></h5>
<h5><a href="#heap checking">heap checking</a></h5>

<h4><a href="#The case for HTML GUIs">The case for HTML GUIs</a></h4>
<h5><a href="#Buster">Buster</a></h6>



<hr>
<a name="Introduction">
<h2>Introduction</h2>

The <span class=name> Webio</span> server is a small portable web server designed as a library for inclusion in embedded systems or as a Browser-based GUI in applications. It compiles and runs on both Windows and Linux.

<p>
Webio includes:
<ul>
<li> SSI, both with disk files and for calling embedded C routines to produce output</li>
<li> CGI, both for executing external scripts and internal C code</li>
<li> A <a href=#fsbuilder>file system builder</a> for embedded html content in C programs</li>
<li> HTTP 1.1 features, including authentication and pipelining</li>
</ul>

<hr>
<a name="Internal structure">
<h2>Internal structure</h2>
<p>
Webio is written entirely in C language, and has been tested on Microsoft and GCC compilers. Most source files are compiled on all target systems with no "ifdefs or modifications - we've tried to limit those to a few selected include files.
<p>
Some source "*.c" files may contain the HTML content, which will change from one application to the next. These files are usually generated by the fsbuilder utility, described <a ref=#fsbuild > here.</a>
<p>
The porting engineer will also usually want to provide additional file to implement <a href=#dynamic_content > dynamic content</a> via Webio's <a href=#ssi >SSI</a> and  <a href=#cgi >CGI</a> interfaces. 

<a name="Source files">
<h3>Source files</h3>

The following source and header files should not be modified in the course of ordinary ports or applications:

<table >
<tr><td width=50 rowspan=6> <td width=140>
webio.c   </td><td>  Core thread and socket processing
</td></tr><tr><td>
webclib.c  </td><td> C functions for aiding SSI and CGI routines 
</td></tr><tr><td>
webfs.c    </td><td> Support for internal (embedded) and external (disk) file systems
</td></tr><tr><td>
webobjs.c   </td><td> Implements web session and file objects
</td></tr><tr><td>
webutils.c  </td><td> Useful C utility functions 
</td></tr><tr><td>
webio.h     </td><td> Primary Webio object definitions 
</td></tr></table>

<p>
These source and header files <i>may</i> need to be modified or replaced when porting <span class=name>Webio./span>

<table >
<tr><td width=50 rowspan=4> <td width=140>
websys.c   </td><td>  Windows vs. Linux "ifdef" code 
</td></tr><tr><td>
websys.h   </td><td>  System definitions, may include windowsdefs.h or 
linuxdefs.h
</td></tr><tr><td>
windowsdefs.h </td><td>  Windows port definitions 
</td></tr><tr><td>
linuxdefs.h   </td><td>  Linux port definitions 
</td></tr></table>

<p>
The next list of source and header files are produced by the <span class=name><a href=#fsbuilder>fsbuilder</a></span> in the demo program. The may be present as named in the your final application, or you may choose to rename them. In either case, hand editing the,m is not recommended, since they will be re-written each time you run the fsbuilder tool.

<table >
<tr><td width=50 rowspan=4> <td width=140>
imgdata.c </td><td>  C char[] arrays with embedded image data 
</td></tr><tr><td>
wsfcode.c </td><td>  C function stubs for embedded form and CGI routines 
</td></tr><tr><td>
wsfdata.c </td><td>  File structure list and arrays with embedded HTML pages
</td></tr><tr><td>
wsfdata.h </td><td>  Declarations and prototypes for all the above
</td></tr></table>

<p>
The following file is provided for building a simple test application with Webio, to verify basic compiler and system functionality before you merge Webio with your target application of system 

<table >
<tr><td width=50 rowspan=4> <td width=140>
webtest.c  </td><td>  <span class=code> main()</span> for Windows & Linux test app
</td></tr></table>


<a name="threads entry point">
<h3>threads entry point "wi_thread();"</h3>

Since <span class=name >Webio</span> is designed to be used as a library, it uses the simplest workable model - it repeatedly polls <span class=code> wi_poll()</span> the main entry point for the server.  <span class=code> wi_poll()</span> first does a non-blocking <span class=code>select()</span> call to see the any of the web servers sockets requires action. It then loops through the list of open web server sessions, checking to see if any of those require action. If performs whatever actions it can with each object (socket or session), stopping when it can go no further without blocking. The object is then left in a state where execution can be resumed in a later instance of  <span class=code> wi_poll()</span> .

<p>
 <span class=code> wi_poll()</span> it designed to be driven by a single  thread. The routine the routine <span class=code> wi_thread(); </span>, is provided to implement this. easily. The demo program demonstrates how it to this. It's sole thread, the  <span class=code> main()</span>  routine sets up the network (ifdeffed for Linux or windows) and then blocks in a call to   <span class=code> wi_thread(); </span>. When this call returns, the application has terminated.
<p>
All the objects keep stateful information, so if the execution is required to block, the code can simply return to the main thread, or whatever is calling <span class=code> wi_poll()</span> 

<p>

<a name="main objects">
<h3>main objects</h3>

<p><span class=code> wi_sess </span>
<br>
One of these objects is created for every connection which is opened to the web server. Is contains the open socket, buffers for reading and writing, and pointers to any related file objects.
<p>
The main poll activity of the program works largely by traversing a linked list of <span class=code> wi_sess; </span> objects and checking each for any pending work which can now be done because of changes since the last poll.
<p>
<p><span class=code> wi_file </span>
<br>
This is a wrapper for a lower layer FILE descriptor. One of these 
is maintained by the server for each open file. The lower layer descriptor may be a conventional disk file, one of the embedded files produced by fsbuilder, or other types of files defined by the programmer.


<p><span class=code> wi_filesys </span>
<br>
One of these objects is created for each type of file supported in the build. Typically there will be one foe disk files and one for fsbuilder embeddded files. 
<p>
The object is primarily a list of routines which perform common ansi-like file operations, such as<span class=code> fopen, </span><span class=code> fread, </span> and <span class=code> fwrite</span>. New file systems may be implemented by defining another one of these objects and provided it's member functions.

<p><span class=code> em_file </span>
<br>
One of these is created for each embedded file - files which are contained in the program itself. These files are saved as arrays of C unsigned chars and these arrays are managed by a linked list of em_file structures. Both these structures and the character arrays they manage are generated by the <span class=name ><a href="#fsbuilder" >fsbuilder</a></span> tool. 
<p>
NOTE This structure should NOT be changed unless the fsbuilder is modified to incorporate the change.  

<a name="heap memory">
<h3>heap memory</h3>
Normal heap management with  <span class=code> malloc()</span > and  <span class=code> free() </span> are not always portable enough for Webio, especially on real-time systems; where they often don't exist at all. 
<p>
We deal with the by allocating and freeing all our memory via the macros <span class=code> WI_MALLOC() </span > and <span class=code>  WI_FREE() </span>. 
<p>
These are further wrapped insire the calls <span class=code> wi_malloc() </span> and <span class=code>  wi_free() </span>, which perform error checking by allocating slightly longer buffers than needed and placing markers around the area returned to the caller. If these markers are corrupted when the block is freed, then the code has serious errors and an <a href=#dtrap > embedded breakpoint </a>can be invoked. 


<hr>
<a name="The demo application" >
<h2>The demo application</h2>

The demo application is a simple standalone web server, provided for building a test application with  <span class=name>Webio</span>, to verify basic compiler and system functionality before you merge Webio with your target application of system. It demonstrates simple web pages with SSIs, Authentication, images, and a form.

<a name="Building on Linux with GCC">
<h3>Building on Linux with GCC</h3>

To build the demo application on linux, follow these steps:

<ul><li>
un-tar or otherwise download the distribution.
</li><li>
In needed, build the fsbuilder utility ("make")
</li><li>
build the server with "make -f Makefile"
</li><li>
Start the server (must be root): "./webio &"
</li></ul>

<a name="Building on Windows via Visual Studio">
<h3>Building on Windows via Visual Studio</h3>

To build the demo application on Windows, follow these steps:
<ul><li>
un-zip or otherwise download the distribution.
</li><li>
With Visual studio v7.0 (or newer) open the Webio.dsw project file 
</li><li>
Click the build button. Check the output window for errors.
</li><li>
Run the server: "Debug/webio"
</li></ul>



<a name="Merging Webio with your target or application" >
<h2>Merging Webio with your target or application</h2>

For most applications and targets, this is simply a matter of replacing the code in  <span class=name>webtest.c</span> which initializes the web server at start-up and supports it during runtime. If your system will be running the web server in a single thread (recommended), you may even be able to take the <span class=code>"main()</span>" routine from the demo, change the name (most tool chains won't like another use of the name <span class=code>"main"</span>) and use it as a basis for your thread's entry point. The <span class=code>main()</span> routine does what most threads do - initializes the resources needed for the thread, and then enters an simple loop that runs until shutdown.

<a name="Initialization">
<h3>Initialization</h3>

To prepare to run the web server, perform the following steps in order:
<p>

<b>1) Start the network (not needed on Linux)</b>
<br><br>
On at least some versions of windows, you will need to start the "winsock" network services by calling <span class=code>WSAStartup()</span>, as in the <span class=name>webtest.c</span> example. Most Unix-like systems don't require this; their networks are already running when your application loads. Other OS's may have needs like Windows - check your OS networking documents to be sure.
<p>
<b>2) call wi_init() to Initialize the web server. </b>
<br><br>
This sets up Webio internals and preforms the sockets <span class=code>listen()</span> call which connects <span class=name>Webio</span> to the network. 
<p>

<b>3) Install any authentication routines your file system requires. </b>
<br><br>
If your web server will require authentication of users to view certain pages, you will need to set a pointer to the authentication routine(s) to be used. How these routines work is described in detail in the <a href="#authentication">authentication</a> section. To install them you need to set pointers in the structures which manage each file system. The code to install a routine for the embedded file system is:

<span class=code><pre>
   /* Install our embedded file authentication routine */
   emfs.wfs_fauth = wfs_auth;
</pre></span>

...where <span class=code>wfs_auth</span> is your authentication routine. This example is straight from the <span class=name>webtest.c</span> sample code. 
<p>

<a name="Runtime">
<h3>Runtime</h3>

Aside from the standard OS services (networking, file system, heap memory), the web server requires two additional services during runtime.
<p>

<b>1) The counting timer, <span class=code>cticks.</span> </b>
<p>
This is defined as an unsigned long which is incremented by one at regular intervals, ideally about 1/10 of a second. The number of "ticks" per second is given by the <span class=code>#define TPS</span>. It is the responsibility of the porting engineer to make sure that <span class=code>cticks</span> in incremented at the <span class=code>TPS</span> rate. Neglecting to do this will disable the web servers ability to time out idle connection.
<p>

<b>2) CPU cycles (i.e. a thread). </b>
<p>
The simplest way to do this is to call <span class=code>wi_thread();</span>. This will block forever (until the web server terminates), so it should only be called from a dedicated thread; and then only after the initialization in the <a href="#Initialization">previous section</a> is complete.
<p>

If you don't have a multi-threaded system, you can also drive the server by polling. Just call the routine <span class=code>wi_poll();</span> as often possible - at least several times a second. The more often you call this, the better your server's response time will be. This routine returns the number of web serer seesions which required CPU cycles during the call - the higher this number, the more often you should be calling  <span class=code>wi_poll();</span>. 
<p>
<p>

<hr>
<a name="fsbuilder" >
<h2>The File system builder, fsbuilder</h2>
<a name="Overview">

When embedding a web server as a GUI in an application or an Embedded system, it's usually desirable to package some or all of the web server's HTML files in the code itself, rather than having them on the disk. Reasons for this include:

<ul><li>
Ram based files allow much faster access than disk files.
</li><li>
Prevents users from modifying sensitive GUI files on the disk.
</li><li>
Allow operation on systems without a conventional file system.
</li><li>
Allow a tight coupling of dynamic page content and C routines.
</li><li>
Reduce the number of files in the installation package
</li></ul>

To support file embedding,  <span class=name >Webio</span> is bundled with the  <span class=name >fsbuilder</span> tool.  <span class=name >fsbuilder</span> is a C++ program which will compile and run on both Windows and Linux. A makefile is included for Linux, and a Microsoft Visual C project file is included for Windows. 

<p>
Once built, <span class=name >fsbuilder</span> is meant to be run as a command line application on the development system. The <span class=name >Webio </span> Linux demo makefiles will invoke it as needed to produce new C file whenever the content changes. <span class=name >fsbuilder</span> is NOT meant to be part of the program containing <span class=name >Webio</span> .

<p>
<span class=name >fsbuilder</span> takes a list of files as it's only required command line argument. The "listfile" is a plain text file, with one file name per line. Generally, static content files such as text and images which are in the list should exist on the working directory (or in an indicated path). The list may also include names of SSI and CGI files, for which placeholders are created by <span class=name >fsbuilder</span>. 

<p>
The listfile may contain comment lines starting with "#";

<p>
<a name="Per-file Options">
<h3>Per-file Options</h3>
Each file name line in the listfile may also contain several options:

<table ><tr><td width=10 rowspan=10></td><td>
   -a </td><td> Requests for the file will require authentication
   </td></tr><tr><td>
   -c </td><td> Enable cache control - Browser will not cache the file
   </td></tr><tr><td>
   -o <outfile></td><td> send C data array output to named file
   </td></tr><tr><td>
   -s <funcname></td><td> data comes from named function (generated)
   </td></tr><tr><td>
   -f </td><td><funcname> file maps to C code form handler
   </td></tr><tr><td>
   -p <funcname> </td><td>file is server push, generate function
   </td></tr><tr><td>
   -g <filename> </td><td>generate C code to handle SSI or form data
   </td></tr><tr><td>
   -e <exp> </td><td>file maps to a "C" expression
   </td></tr><tr><td>
   -w </td><td>supress warnings on this file
   </td></tr></table>
<p>
<a name="Command line Options">
<h3>Command line Options</h3>
<p>
In addition to these per-file options, the following command line options will efect ALL files:

<table ><tr><td width=10 rowspan=10></td><td>
   -a </td><td> Requests for the file will require authentication
   </td></tr><tr><td>
   -c </td><td> Enable cache control - Browser will not cache the file
   </td></tr><tr><td>
   -o <outfile></td><td> send C data array output to named file
   </td></tr><tr><td>
    -h <outfile></td><td>  send C headers to named file
   </td></tr></table>

<p>

<p>
<a name="Static files">
<h3>Static files</h3>

<span class=name >fsbuilder</span>  reads the static files (those which not created with the -s, -f, -g, or -e, options) from the disk. The bytes values in the file are output as C source code, in C char arrays. The names of the char arrays are generated from teh names of the disk files, modified as needed to server as C labels For example, dots, while common in file names,  are not allowed in C language array names.

Each static file also results in <span class=name >fsbuilder</span> creating an entry in an array of <span class=name >em_file</span> structures. These structures serve a function similar to inodes in a UNIX files system. They contain information about the size and name of the file, and have a pointer to the char array with the file's data. The C files containing the embedded file data and structures, when compiled and linked with the Webio library, will server as an embedded read-only file system 


<h3>Dynamic files</h3>

Lines in the listfile with the options -s, -f, -g , and -e will create pseudo files in the <span class=name >em_file</span> array. This files are not associated with any file read from the disk, rather their content is generated by software each time the file is referenced. The most efficient way to do this is with C code linked into the system with <span class=name >Webio</span>, but it can also be done by a reference to an external script or program (as with typical CGI). The types of dynamic files are described in the following section.


<hr>
<a name="dynamic_content" >
<h2>dynamic content</h2>
<p>
This section describes how to use <span class=name >Webio's</span> two mains types of dynamic content, SSI and CGI. Both are implemented as "pseudo" files - entries in the <span class=name >em_file</span> list which do not have any array of static data associated with them. When the core server loop does a read on these files, rather than copying out data the embedded file system code calls a C routine, passing the <span class=name >wi_sess</span> structure ( aka a session) to the C routine. The C routine fills in a per-session buffer with the HTML (or other content) which is to be returned to the browser. 

<p>
The exact semantics of the C routines which service SSI and CGI functions are different, but in both cases a stub routine is generated by the fsbuilder utility and left (by default) in the file <span class=name > wsfdata.c</span>. This file should not be compiled directly, rather the stubs it contains should be copied to a user maintained file, which IS compiled and linked with the <span class=name >webio</span> system. This allows you to add your own code to the stubs without it being overwritten the next time you build. 

<p>
The name of the C routine is set by the line in the listfile which creates the pseudo file. If you get an "unresolved external" error in your link, you have probably created a pseudo file and forgotten to copy the stub out of wsfdata.c. 


<a name="ssi" >
<h3>SSI</h3>

SSI files are created by including a line in the listfile which follows the file name with "-s", the SSI option. If the named file exists on the disk it is ignored. As described above, an entry for the file is created in the <span class=name >em_file</span> list, a C routine stub is generated, and the hooks which cause the stub to be called at runtime are added to the  <span class=name >em_file</span> entry. 

<p>
Lets look at the details of SSI via an example, one which places the current time in an HTML page. The HTML might look like this:

<pre>

&lt;!--#include file="time_of_day.ssi" --&gt;

</pre>

The syntax for the listfile line to create the SSI file and C routine stub would be:
<p>
time_of_day.ssi -s time_of_day_routine

<p>
The C stub would look like:
<span class=code><pre>
/* time_of_day_routine()
 *
 * SSI routine stub
 */

int
time_of_day_routine(wi_sess * sess, EOFILE * eofile)
{
   /* Add your code here */
   return 0;
}
</pre></span>

Note: a prototype for this routine is created in <span class=name >wsfdata.h</span> (default name) which SHOULD be included in your SSI and CGI code files.

<p>
Lastly, you need to provide code which puts the text/html to be displayed in the output buffer passed in  <span class=name >sess</span>. The buffer has it's own data type, <span class=name >txbuf</span>, which has a fairly complex semantics because of the issues with allocating buffers as we need to write to them, and freeing them as they are written to the TCP socket.  Fortunately you don;t need to deal with this - <span class=name >webio</span>'s library includes the function <span class=code >wi_printf()</span>, which outputs formatted text into the session's output buffer. 

<p>
Using <span class=code >wi_printf()</span>, your time of day function might look something like this:

<span class=code><pre>

/* time_of_day_routine()
 *
 * Sample SII routine to print TOD into an output html file. 
 *
 */

int 
time_of_day_routine(wi_sess * sess, EOFILE * eofile)
{
   char * time_String; 

   time_String = get_system_time(); /* call OS for current time */

   wi_printf(sess, "Time is now: %s &lt;br&gt;", time_String );

   return 0;      /* OK return code */
}
</pre></span>

<p>
Since the original include statement was in an HTML file, HTML can be included in the text written to the output buffer. In this case, a line break was inserted at end of line. Controlling HTML generation on-the-fly with C code can be a very powerful tool. Javascript can also be created by SSI routines.

<p>
The return value from SSI routines is 0 if the routine succeeds, non-zero if something goes amiss. Currently (July 2008) the core Webio code does nothing with the returned value, but it might in the future.  

<a name="C-code expressions" >
<h3>C-code expressions</h3>
Sometimes it's useful to be able to include the result of a simple C code expression in an HTML file, but without the additional coding (and overhead of an additional C routine) require by the SSI "-s" option. For these situations <span class=name >Webio</span> supports the "-e" option. This allows C language expressions to be specified directly from the listfile. These expressions are still reference via an SSI in the HTML code, however the C code to resolve the C expression and output the result into the HTML stream is entirely generated by <span class=name >fsbuilder.</span>

<p>
To understand how this works, let examine it's use in the demo server. The demo creates an SSI file which display the number of total memory blocks allocated by the server since it's been running. The listfile contains this line:

<pre>
memhits.var -e u_long  wi_totalblocks
</pre>

This relies on the existence of the "unsigned long" variable named wi_totalblocks (which counts the memory allocations), and  creates an embedded SSI file named <span class=name >memhits.var</span>. <span class=name >memhits.var</span> can the be reference in an HTML page as follows:

<pre>
...and mem cexp: &lt;!--#include file="memhits.var" --&gt;
</pre>

When the page is displayed, the include tag is replace by the number of memory allocations which have occurred up to that point. 
<pre>
...and mem cexp: 51243
</pre>
<p>

A single step is required bny ther programmer to support all the C-code expressions in the system - you must copy the routine <span class=code > wi_cvariables()</span> from the wsfcode.c file generated by <span class=name >fsbuilder </span> into a C file which is linked into the system. As with other SSI and CGI code, the generated code is created in a "non live" file so that you can modify it as needed, and future runs of <span class=name >fsbuilder </span> will not overwrite it.

<p>
The advantages of using the C-code expressions "-e" option over the SSI "-s" option are less work during development, and less overhead during runtime. 

<p>
<font color=red>WARNING</font><br>
When <span class=name >fsbuilder </span> generates the code for <span class=code > wi_cvariables()</span>, is generates a <span class=code >switch:</span> statement with algorithmically generated <span class=code >case:</span> labels. These labels include several digits, based on the order of the files in the listfile, to ensure uniqueness. For example in the demo example the lable might be <span class=code >"MEMHITS_VAR5"</span> if the file is the fifth in the listfile. 
<p>
The "gotcha" this creates is when you add more files to the listfile ahead of the "-e" file. This changes the label (in this case from <span class=code >"MEMHITS_VAR5"</span> to something like <span class=code >"MEMHITS_VAR8"</span>) in both the ".c" and the ".h" output files. Since the the header (".h") file are included in the compiled code and the ".c" files are not, this creates a discrepancy between name of the label in the two files, and at compile time you will get an error something like:

<pre>
gcc -g -DLINUX -c webtest.c -o webtest.o
webtest.c: In function "wi_cvariables":
webtest.c:157: error: "MEMHITS_VAR5" undeclared (first use in this function)
</pre>
 
If this happens, you need to update the labels in the C file, either by copying in the new <span class=code >wi_cvariables()</span> routine, or manual editing.


<a name="cgi" >
<h3>CGI</h3>

CGI routines are also created by including a line in the listfile which does not refer to a existing disk file, but to create a CGI file the listfile line contains the option "-f".  The example from the demo package listfile is:

<pre>
# form handlers
testaction.cgi -f testaction_cgi
</pre>

This creates an <span class=code >em_file</span> structure and includes it in the list of embedded files. When the file is referenced, usually because the use clicked a form submit button, the C routine following "-f" is invoked - in this case, <span class=code >testaction_cgi();.</span> As with SSI function, the  <span class=name >fsbuilder </span>  creates a C stub for the routine in <span class=name >wsfcode.c</span> and a prototype in <span class=name >wfsdata.h</span>. The code stub should be moved to a "live" code file, and the prototype included as appropriate. The code stub generated for <span class=code >testaction_cgi();.</span> is:

<span class=code><pre>
/* testaction_cgi
 * Stub routine for form processing
 * 
 * Returns NULL if OK, else short error text
 */

char *
testaction_cgi(wi_sess * sess, EOFILE * eofile)
{
   char *   your_name;

   your_name = wi_formvalue(sess, "your_name");   /* default: John */


   /* Add your code here */

   return 0;
}
</pre></span>

As you can see, this is a bit more complex than the simple SSI stub. In the case of the CGI routine, the  <span class=name >fsbuilder </span> scanned the HTML code, and included code to extract the name-value pairs in the form form into local C language variables. Once you copy this stub to a working filer you are ready to jump right in manipulating form data with C code - the whole name-value extraction process is automated. 

<p>
In the event that Webio can't parse the HTML (hey, it happens) it may be useful to explain how the form's name-value info is passed to the CGI routine. Whenever a HTTP GET or POST request is received, the attached name-value text is parsed into a <span class=code>wi_form</span> object. The definition of the object is in the <span class=name >webio.h</span>  file. The session objects's (<span class=code >wi_sess</span>) <span class=code >ws_formlist</span> field is set to point to this form structure. 
<p>
As the name implies, the forms can be a linked list, however there is usually only one. Multiple forms may be attached to a session if a page invoked with name/value pairs includes and SSI which also has name/vale pairs.  
<p>
Form structures are automatically freed by the <span class=name >Webio</span> internals when the page processing is complete. <span class=name >Webio</span> also provides the utility function <span class=code >wi_formvalue()</span> to return the text for a value in the form when the corresponding name is passed. 

<p>
After the form name/value pairs have been processed, the browser expects a page to be displayed in response to the GET or POST request. Since the file name in the request was directed to the CGI routine, there is no actual file associated with the request. If would be possible for the C routine to generate the entire file (as conventional CGI systems often do), however that can mean a lot of tedious extra code. To avoid this, use the <span class=code >wi_redirect()</span> function described ion the next section.

<p>
The return value of the CGI routine is NULL if the routine has successfully handler the CGI input and redirected (or otherwise handled) the resulting page to be displayed. If the CGI routine return a non-NULL value, it is assumed to be a pointer to some error text, which is displayed on an otherwise blank web page. Since these error pages are rather plain, it's recommended that the CGI routine establish it's own error handler and pages, and leave the non-NULL return scenario for very unlikely situations or minimalist web servers. 

<a name="Redirecting to another file" >
<h3>Redirecting to another file</h3>

The <span class=code >wi_redirect()</span> function is provided for those times when embedded C code needs to send an entire HTML file to the browser. It's use is illustrated in the file <span class=name >webtest.c:</span>

<span class=code><pre>
...
  wi_redirect(sess, "gotname.html");

   return( NULL );
}
</pre></span>

In this case, the file "gotname.html" is opened and prepared for sending to the browser. The are two important points to note  about this operation:
<br>
<br>
<b>Note 1:</b> Any file currently being sent to the browser is closed and replaced with the redirect file. In other words the redirect file is NOT inserted into the existing file, it fully replaces it. This is not an issue during CGI processing since there is no existing file, but it could be confusing at other time.
<br>
<br>
<b>Note 2:</b> The redirect file does not actually get sent until the C routine (usually a CGI routine) returns to the Webio core and the core gets a chance to run. The redirect file is only queued for sending by <span class=code >wi_redirect()</span>, the sending does not actually start during the <span class=code >wi_redirect()</span> call.
<p>

<hr>
<href name="Webio Options" >
<h2>Webio Options</h2>

<a name="Compile-time options" >
<h3>Compile-time options</h3>

<span class=name >Webio</span> has several options which can by omitted via C <span class=code >#ifdef</span> statements at compile time. The are listed and described in this excerpt from the demo <span class=name websys.h</span> file.

<span class=code><pre>
/*********** Optional webio features - comment out to remove ***************/

#define WI_STDFILES  1     /* Allow host system (Linux, Windows) files */
#define WI_EMBFILES  1     /* Allow embedded FS files */

#define WI_THREAD    1     /* Drive webio with a thread rather than polling */


/*********** Webio sizes and limits ***************/

#define WI_RXBUFSIZE    1536  /* rxbuf[] total size */
#define WI_TXBUFSIZE    1400  /* txbuf[] section size */
#define WI_MAXURLSIZE   512   /* URL buffer size  */
#define WI_FSBUFSIZE    4096  /* file read buffer size */

#define WI_PERSISTTMO   300   /* persistent connection timeout */
</pre></span>


The <span class=name >Webio</span>  server supports an option to make it only available to Browsers on the local system. This is provided as a security measure for those who want to use <span class=name >Webio</span>  as a program GUI, but don't want other machines to be able to access the GUI over the network. 
<p>
Activating this option is simple - you just set the global int variable <span class=code>wi_localhost</span> to non-zero. This could actually be done at compile time runtime by editing the declaration in <span class=name>webio.c</span>, but the current implementation does this at runtime to allow applications to treat this as a user option.  



<hr>
<a name="authentication">
<h2>authentication</h2>

Every file system supported by the web server (usually just the embedded file system and sometimes one disk file system) has the option of supporting file authentication. Support is indicated by setting the file system <span class=code>wi_filesys</span>  structure's authentication routine pointer to a routine which will handle requests for authentication. The format for such routines is:

<span class=code><pre>
int         file_auth_routine(void * fd, char * name, char * pw);  /* Optional, for authentication */
</pre></span>

If this member field in the  <span class=code>wi_filesys</span> structure is NULL then no authentication is performed. If this is non-null, it had better point to a routine of the above format. The routine should take the user name and password passed, and check the file (passed as a descriptor to an already opened file) and determine if the credentials allow access to the file. If so the routine returns a non-zero, if not the routine returns zero. 

<p>
This is most efficient when used with embedded files. Each line in the listfile which contains the option "-a" will cause <span class=name >fsbuilder </span> will set a flag in the embedded file's descriptor. This flag can be used to allow universal access to non-flagged files and restrict access to flagged files. Note that the programmer must still provide a routine (and name/password database) to resolve access. An example of this is in the <span class=code>wfs_auth()</span> routine in the file webtest.c

<p>
Currently only Basic authentication is supported, MD5 will be in a future release.

<p>
A note about implementation: Passing the file descriptor (FD) is very efficient for the embedded FS, but may be less than ideal for the OS disk-based FS. Finding out which file is being passed form the FD requires intimate knowledge of the file system - usually a pain to actually code.
<p>
One way around this would be to hook the <span class=code>wi_fopen()</span> member of the <span class=code>wi_filesys</span> structure, and keep a map of file name (and/or other useful access info) indexed by the FD. Another approach would be to modify the code in webio.c to pass more info to the auth routine. 

<hr>
<a name="Portability" >
<h2>Portability:</h2>

I once said to a UNIX bigot "Unix people think 'portable' means it runs on two flavors of Unix." Of course he replied "So what's your point?".  My point is that making something run on both Windows and Linux, with 99% shared code source code and no in-line #ifdefs (like <span class=name >Webio</span> does) is a lot harder. Linux and Windows had different network APIs (Winsock is NOT sockets), and many embedded systems have no file system at all. Some even lack memory management. 

<span class=name >Webio</span> is made portable across such environments by determining which aspects of the web server will vary from system to system, writing code that only uses functionality found on all the target systems, and abstracting out functionality that has has a different syntax across systems. 

<p>
For example, on Linux a socket can only be closed by passing it to the file system's <span class=code>close()</span> call. On Windows, a socket is closed by calling Winsock's <span class=code>closesocket()</span> - passing it to <span class=code>close()</span>, at least on some versions of Windows, will result in a system crash. <span class=name >Webio</span> maintains portability across both system by using the less common <span class=code>closesocket()</span> call throughout it's code, and mapping this to <span class=code>close()</span> on Linux ports. Since the syntax of <span class=code>close</span> and <span class=code>closesocket()</span> are identical, this is done with a C <span class=code>#define.</span>. In fact, to support the forgetful and dyslexic, we also have a <span class=code>#define.</span> for <span class=code>socketclose().</span>. 

<p>
The remainder of this section lists each area where there are deviations between Linux, Windows, and common Embedded targets,  and describes how <span class=name >Webio</span> addresses the various systems with one clean code base. The only assumptions are 

<ul><li>
A standard C compiler and library.
</li><li>
A TCP stack with a sockets-like network API.
</li><li>
Multiple threads, or the ability to periodically poll a core routine.
</li></ul>


<a name="Portability files and routines" >
<h3>Portability files and routines</h3>

Wherever possible, definitions for support across projects and operating systems are in the header file <span class=name >websys.h</span>. In the demo program a single <span class=name >websys.h</span> works across Linux (Fedora 7) and Windows (XP)  by including one of two sub-headers either <span class=name >linuxdefs.h</span> or <span class=name >windowsdefs.h</span>. Porting to other operating systems should start with going through whichever of these files is most like your target system, and redefining things as described on the following sections. 


<a name="Header files" >
<h3>Header files</h3>

The header files required for standard ANSI C library prototypes, as well as common typedefs, are not the same across all operating systems. For this reason, the <span class=name >webio</span> C source files all include <span class=name >websys.h</span>, and these other files (<span class=name >stdio.h, ctypes.h</span>, etc) should be included within <span class=name >websys.h.</span>


<a name="Portbility routines" >
<h3>Portbility routines</h3>
 The following routine require actions from the system, but the syntax is different between systems. Each of these performs a simple function which needs to be implemented (either by macro or as a routine) on each target system.

<p>
<span class=name >WI_NOBLOCKSOCK()</span><br><br>

This primitive is passed an open socket, which should be set to non-blocking mode. Once in non-blocking mode, calls to redcv() and send() should return EWOULDBLOCK if they cannot complete immediately. The Linux example: 
<br>
#define WI_NOBLOCKSOCK(socket) fcntl(socket, F_SETFL, O_NONBLOCK)
</pre></span>

<p>
<span class=name >wi_getdate()</span><br><br>
This primitive should return a static string containing the current date and time in a user-readable format. The returned value will be used in building HTTP headers, so the format must be compliant with HTTP standards. See the Windows example for a usable format string.

<p>
<span class=name >strnicmp()</span><br><br>
This primitive compares two strings up to a passed length, ignoring case. It is a merging of the ANSI functions <span class=code >stricmp()</span> and <span class=code >strncmp()</span>. Despite it's non-standard status, many C libraries (notably Microsoft) support it anyway. Because of this, Webio ports to systems without it require that it be in the portability code.

<p>
<span class=code>closesocket()</span><br><br> 
This primitive should close the passed open socket. On most Unix-like systems it can be mapped directly to <span class=code >close().</span

<p>

<hr>
<a name="Debugging aids">
<h2>Debugging aids</h2>

<a name=dtrap >

<a name="dtrap">
<h3>dtrap()</h3>

This is used throughout the code as a sort of embedded breakpoint. It is called whenever something suspicious is detected (say, a variable value out of the expected range). Developers  with debuggers should <b>ALWAYS</b> place a breakpoint on dtrap so they are aware of such problems


<a name="heap checking">
<h3>heap checking</h3>
 This is already described in the section on <a href="#heap memory">Heap memory</a>. It's worth noting here that the heap wrapper routines also keep counters of alloc and free calls, so gradual memory leaks can be detected by watching for a slow increase between these counters. 
 

<hr>
<a name="The case for HTML GUIs">
<h2>The case for HTML GUIs</h2>
<p>
This section could be called a rant, but this author has been mystified for 20 years as to why there is no industry standard for implementing GUIs across different Operating Systems. We have an ANSI standard C library, sockets (and quasi-socket Winsock) for Networking. But since the Xerox Star, through Apple's Lisa and MAC, past OS/2, and into Windows and X-Windows, no two popular systems use even similar GUIs - until the advent of HTML. 
<p>
HTML with CSS and Javascript provides a serviceable GUI across every OS with a mouse and graphics screen. While the displays don't usually support HTML natively, most platforms have at least one free web browser available. Even my cell phone came with one. 
<p>
With the universal GUI platform, It only makes sense for application writers to implement simple GUIs with HTML, rather than Windows, MAC or Linux GUI calls. While some graphics intensive apps (such paint programs) are still better done on a native GUI, apps such as spreadsheets, text editors, and databases are as easy, if not easier, to implement on HTML. Look at the sophisticated office suite provided by Google apps.
<p>
The HTML GUI also has the benefit of freeing the user from having the GUI on the same computer that runs the app. By opening a few ports in a home firewall, you could run all your apps on a machine at your house and use them from any browser, anywhere on the Internet. No VPN or PC-Anywhere-like add-ons required. 
<p>
The one missing ingredient for most application writers to write such apps is a web server designed to be embedded right in the application as a library - like Webio. 
<p>

<a name="Buster">
<h3>Buster</h3>
A few years back I wanted to write a portable application, including a portable GUI. I created Webio, since none of the open source web servers out there did quite what I wanted. The result is the open source Network monitoring aplication Buster, downloadable from <A href="http://www.praemio.com" target=top>www.praemio.com</a>. Buster (along with Webio) has also been modified to serve the Network Neutrality Squad's NN-Agent; available from <a href="http://www.nnsquad.org/agent" target=top>www.nnsquad.org</a>. In both cases, a Windows build and full source is available for download. Both these applications demonstrate a GUI rich in forms, pictures and graphics. They serve as advanced examples of what <span class=name >Webio</span> can do. 


<p>
I'm hoping that by releasing this into open source, with any license restrictions, It will accerate the changing over from OS-locked GUIS to the universal GUI - HTML.  

<p>
If you need help or have suggestions, feel free to email me - 
<a href="mailto:jbartas @speakeasy.net" >jbartas @speakeasy.net</a>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Chief Technology Officer praemio.com
United States United States
See my bio here:

http://www.bartas.net/resume.htm

Comments and Discussions