OEM Getting Started

Welcome to the Getting Started guide for the Barracuda App/Web Server library! This guide is designed to help new users, specifically Lua and C/C++ programmers, get acquainted with these two powerful libraries.

If you plan on using Lua, you can skip reading the following document if you base your integration on one of the two ready-to-use reference platforms:

If you do not want to use Lua, check out the C++ WebSocket example in the examples folder. The documentation for this example is available on GitHub. Otherwise, use any of the other examples.

Using the Barracuda App Server library and the Barracuda Web Server Library:

This section covers assembling a server with C components, comparing C/C++ Server Pages (CSP) with Lua Server Pages (LSP), and creating interfaces between Lua and C code. The final part introduces the Virtual File System (VFS).

The Barracuda App/Web Server offers both a C/C++ API and a Lua API for application developers. While the startup code must be written in C (or C++), many of the Barracuda Web Server API's can be accessed using the Lua scripting language.

The Barracuda Web and App Server Setup Video is a helpful resource that guides firmware engineers through the process of integrating the library into an embedded application. In the video, you will find step-by-step instructions on setting up the Barracuda server.

During the setup process, you have the flexibility to choose your preferred development approach. You can opt to develop everything using C/C++, and if desired, you can include CSP in your build. Additionally, you have the option to incorporate Lua into your project.

If you decide to use Lua, it is crucial to design the south bridge API. This API enables Lua to access your low-level APIs and hardware, ensuring seamless communication between Lua scripts and the underlying system.

By following the Barracuda Web and App Server Setup Video, you will gain a clear understanding of the integration process and the available options for your development. It is a valuable resource to get you up and running with the Barracuda server effectively.

Constructing a Server

Creating a Barracuda Web Server involves creating a number of objects. These objects are assembled into a web server specifically designed for your application.

C code

The Barracuda App/Web Server Library is designed in ANSI C. This C library is designed in an object-oriented way compatible with C++. The header files contain special wrappers for C++ code. The following example uses C++. Most ready-to-run examples, such as Xedge, includes C code (not C++) similar to the following:

int main(int argc, char* argv[])
{
   ThreadMutex m; //Create the mutex protecting the dispatcher and server.
   SoDisp dispatcher(&m); //Create the socket dispatcher object.
   //Create the Web-Server object and bind it to the dispatcher
   HttpServer server(&dispatcher);
   // Create a listen object that listen on port 80
   HttpServCon servCon(&server, &dispatcher);
   // Create a secure listen object that listen on port 443
   HttpSharkSslServCon sslServCon(&server, &dispatcher, cert);
   dispatcher.run(); //Never returns.
}

The objects created above are explained in the C/C++ reference manual. The above code creates a platform independent mutex which protects the server in a multi thread enabled Barracuda configuration. The SoDisp is a platform independent socket dispatcher. This object dispatches socket events to the registered objects. For example, the servCon object and the sslServCon object are triggered when a client connects to port 80 and port 443. The HttpServCon object is the standard server listen object. This object typically listens for new client connections on port 80. The sslServCon object listens for connections on port 443 -- that is, it listens for secure HTTP connections. Argument cert is a pointer to a SSL certificate generated by using the command line tool SharkParseCert, which is explained in the C/C++ section.

We are using default arguments for the constructors above. You have many optional arguments that can be passed to the constructors above. For example, you can configure the HttpServCon object to listen to a non standard HTTP port, or you can configure the server to create N threads -- i.e., you can thread enable the server.

In the above example, two listen objects are created. The server permits you to create any number of listen objects. You can, for example, create another HttpServCon object listening for connections on port 80 using IPv6.

The above code shows how to assemble a standalone web server. An application embedding Barracuda should replace the main function with a thread dedicated to the server.

The above assembled web server will return the message "404 page not found" since no resources are so far installed in the Virtual File System. The Virtual File System must at a minimum contain one resource before a client can access the server.

Resources can be installed into the Virtual File System as Lua objects and/or as C/C++ objects. Objects created by C code can be manipulated by Lua code.

Enabling Lua

The following C code fragment is the minimum of what it takes to enable Lua for a Barracuda server. It assumes that we have already created the HttpServer and IoIntfs (IO interface).

lua_State* L;                           /* pointer to a Lua virtual machine */
struct BaLua_param blp = {0};           /* configuration parameters */

blp.vmio   = pvmio;                     /* The required VM io. Pointer to an IoIntf */
blp.server = pserver;                   /* pointer to a HttpServer */
L = balua_create(&blp);                 /* create the Lua state */

The above configuration parameters are the only parameters required to enable Lua. There are additional parameters that you can optionally configure. For example, a timer object is installed as follows:

BaTimer timer(&m,8000);
blp.timer = &timer;

The timer is very useful as it enables the server to trigger timer events. Many web application frameworks such as PHP must rely on external cron scripts to run maintenance services. Barracuda includes a timer object that permits Lua code to run at regular intervals.

For detailed explanation refer to the Barracuda Lua C interface.

Note: Without enabling Lua, you will only have access to the C HTTPS client library and the C WebSocket Server, while the other protocols listed in the Protocols section will be unavailable.

Lua Server Pages and C/C++ Server Pages

Lua Server Pages, or LSP for short, and C/C++ Server Pages , or CSP for short, are technologies that enable you to make dynamic and interactive web pages.

What are LSP and CSP?

A LSP file normally contains HTML tags, just like a HTML file. However, an LSP file can also contain Lua scripts, normally surrounded by the delimiters <?lsp and ?>. Lua server scripts are executed on the server, and can contain any valid Lua expressions, statements, functions, etc.

A CSP file is similar to an LSP page; however, a CSP file contains C or C++ code normally surrounded by the delimiters <% and %>, which are also known as CSP tags. The CSP compiler supports a number of tags specifically designed for C and C++ code.

LSP pages and CSP pages are provided with some predefined objects. The request object is used to get information from the client, and the response object is used to send output to the client from the server.

The following two examples show an LSP and a CSP web page hit counter. The examples execute code in the server and dynamically produce a HTML page:

LSP example:
<?lsp
   page.count = (page.count or 0) + 1
?>
<html>
  <body>
    <p>
      You are visitor <?lsp=page.count?>.
    </p>
  </body>
</html>
CSP example:
<%! int count; %>
<%!! count = 0; %>
<html>
  <body>
    <p>
      You are visitor <%="%d" ++count%>.
    </p>
  </body>
</html>

The above examples use expression tags, <?lsp= ?> for LSP and <%="format flag" %> for CSP. The result of an expression is emitted as HTML/XML.

Device Management with CSP and LSP

Let's say we have the two following C functions that directly interact with the hardware. The first function enables us to set an LED on or off. The second function returns the LED state, which is 1 for on and 0 for off.

void setLed(int on);
int getLed(void);

To control the LED from a CSP and LSP page, we start by making a simple web page template with one HTML form.

<html>
  <body>
    <form method="post">
      Set LED: <input type="checkbox" name="LED" >
      <br>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

Controlling the LED using CSP

When using CSP, we inject C or C++ code into an HTML page. Since we use C code, we can directly call the two LED functions setLed and getLed. The following example shows the above template converted to a fully functional CSP page (using C code, not C++).

<%g #include "LED.h" %>
<%
if(HttpMethod_Post == HttpRequest_getMethodType(request))
{
   /* Fetch 'POST' data: param 'LED' (from HTML form) */
   const char* led = HttpRequest_getParameter(request, "LED");
   setLed(led ? 1 : 0);
}
%>
<html>
  <body>
    <form method="post">
      Set LED:
       <input type="checkbox" name="LED" <%= getLed() ? "checked" : "" %>>
      <br>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

In the above CSP page, we check if the HTTP method type is POST and if it is, we set the LED to either on or off. The on/off state is fetched from the HTTP parameter "LED", i.e., from the browser's POST data sent from the "LED" checkbox in the HTML code.

On line 14, in the LED checkbox, we must dynamically set the attribute "checked" if the LED is set to "on". The "checked" attribute makes the browser automatically check the checkbox element.

Controlling the LED using LSP

When using LSP, we cannot directly call C functions from within an LSP page since a Lua script cannot directly call a C function. What we need is Lua bindings for the two LED functions. The bindings, when registered in the Lua VM, enable Lua scripts to call C functions via the bindings.

Creating Lua bindings can be done automatically or manually. We will first look into how to do it automatically and then how to do it manually.

Automatic Lua binding generation for the two LED functions

Create a new text file, name it "functions.txt", and copy the two LED function prototypes to this file such that the file contains:

void setLed(int on);
int getLed(void);

Navigate to https://realtimelogic.info/swig/, enter the name LED, and click "continue". Drag and drop the text file "functions.txt" onto the online binding generator's web page. The online web application generates the Lua bindings, and the file should automatically download. Include the generated C file in your build, and follow the instructions provided by the online Lua bindings generator. In particular, you must initialize the bindings by calling luaopen_LED(L) from your C startup code.

After compiling the new Lua bindings (C code) and after modifying the C startup code, compile and run the server. Create the following LSP file in the LSP directory (where you have configured the server to read LSP pages):

<?lsp
if "POST" == request:method() then
   local led = request:data("LED") -- Fetch 'POST' data: param 'LED'
   LED.setLed(led and true or false) -- Call auto generated C binding
end
?>
<html>
  <body>
    <form method="post">
      Set LED:
       <input type="checkbox" name="LED"
          <?lsp= LED.getLed() and "checked" or "" ?>>
      <br>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

In the above example, LED.setLed expects an integer that is either one or zero and function LED.getLed returns either one or zero. Although this works, it is better to change the C prototypes such that one can use a Lua boolean value. We will not go into how this can be done in this tutorial, but you should consult the online swig documentation and make the bindings use boolean values.

Creating Lua bindings manually

Start by creating two function prototypes as follows:

static int LED_setLed(lua_State* L);
static int LED_getLed(lua_State* L);

As you can see from the above, the two functions take a Lua state as argument and return an integer. Lua uses a virtual stack to pass values to and from C. We will not go into this in detail here, but you should consult the Lua book, which describes this in detail. An older version of this book is available online.

static int LED_setLed(lua_State* L)
{
   /* Fetch value at stack position 1 */
   int on = lua_toboolean(L, 1);
   /* Call the LED function that is interfacing the hardware */
   setLed(on);
   return 0; /* No Lua return value */
}

static int LED_getLed(lua_State* L)
{
   /* Call the LED function that get's the LED state from the hardware */
   int on = getLed();
   /* Push the on/off state onto the Lua stack */
   lua_pushboolean(L, on);
   return 1; /* Inform Lua that we have one return value */
}

The above two functions must be registered in the Lua state that was created by the C startup code. The following code creates a Lua table by the name "LED" and attaches the two C functions to this table.

static int LED_register(lua_State* L)
{
   static const luaL_Reg reg[] = {
      {"setLed", LED_setLed},
      {"getLed", LED_getLed},
      {NULL, NULL}
   };
   luaL_newlib(L, reg);
   return 1;
} /* End */


int luaopen_LED(lua_State* L)
{
   luaL_requiref(L, "LED", LED_register, TRUE);
   return 1;
}

A detailed explanation on how the two above functions work is explained in the advanced Lua bindings tutorial. Notice that we use the same name for registering the Lua bindings as we used in the bindings that were automatically generated. The C startup code must call luaopen_LED(L) in order to register the Lua bindings.

The LSP page we used for the automatically generated bindings must now be changed slightly since the setLed function now expects a boolean value and the getLed function returns a boolean value. The following shows what must be changed:

Original: LED.setLed(led and 1 or 0)
New code: LED.setLed(led and true or false)

Original: <?lsp= LED.getLed() == 1 and "checked" or "" ?>
New code: <?lsp= LED.getLed() and "checked" or "" ?>

Introduction to the Virtual File System

In this guide, we will introduce you to the Barracuda Virtual File System from a C code perspective. Understanding the Virtual File System is crucial because it forms the foundation of your web application(s). For more information on assembling a VFS, refer to the Lua Virtual File System section, which includes Lua examples. Even if you're working with C code, this section provides a valuable high-level overview of VFS concepts and implementation strategies.

The web server delegates the request to the Virtual File System after it has parsed and analyzed a client HTTP request command. The job of the Virtual File System is to locate the resource requested by the client and to delegate the HTTP request command to the requested resource. If no resource is found or if the Virtual File System is empty, a "404 not found" error message is sent to the client.

The Barracuda App/Web Server is designed to run in embedded devices with non standard file systems. The server encapsulates file system operations into an I/O interface which shields the server from the underlying architecture. An I/O interface implementation can be a file system, a ZIP file, or even a database. The construction ba.openio("vm") above initializes the resource reader with the Lua VM's I/O interface which was configured by the C/C++ startup code.

In many web servers, a resource is synonymous with a file in the file system. The web-server simply locates the file in the file system and sends the file to the client. In Barracuda, a resource can basically be anything and, most importantly, a resource does not have to be a physical file.

An example of a resource in the Virtual File System is an LSP resource. A LSP resource contains Lua code that is executed when the client requests the resource. Another example of a resource is CSP. A CSP resource contains either C or C++ code that is executed when the client requests the resource.

Resources such as LSP and CSP are contained in a resource collection, aka a directory. The Barracuda Web Server includes many directory types such as the Resource Reader, the Resource Manager, and WebDAV. You can also create your own specialized directory type.

The following figure shows the C++ inheritance diagram for directories. The C++ names are not identical to the Lua names.

HttpDir

Next: C and C++ Introduction