Introduction
In Chapter 10 of my book (pg. 388-393), Exploring BeagleBone, I describe how you can build web-based CGI applications that can interface with electronics hardware that is attached to the BeagleBone using Bash scripts that call C/C++ programs. The solution works well for very straightforward applications, but this discussion investigates more advanced solutions for applications where there are more complex interactions — for example, the use of web forms to pass data between your web browser and the application that is executing on the BeagleBone. In this discussion I begin by explaining how you can use a C/C++ program, rather than a CGI script, to display a web page. I then investigate the use of the GNU Cgicc library for more structured and complex interactions.
The approach describe here will work on any Linux machine, including other embedded platforms such as the Raspberry PI; however, the steps are structured for the BeagleBone platform and the examples that interact with the hardware are specific to the BeagleBone platform — they can however be easily modified. In this example, the Apache server is used to serve the CGI applications, so having Apache installed is the only prerequisite software required. Apache runs on port 8080 of the BeagleBone by default when using the recommended Debian images — you can test that by opening a web browser and entering the IP address of your Beaglebone in the address bar using the following format: http://192.168.7.2:8080/ (replace the IP address with your BeagleBone’s IP address — the one listed is the default IP address for Internet-over-USB).
It could be argued that this is a “dated approach” to solving the problem of having an embedded system web server interact with a web browser client — it has been around since the 1990’s. To some extent that is true. There are powerful alternatives available such as Java servlets, node.js, Dart, PHP etc. However, this approach:
- has a low overhead on the BeagleBone, as the code is compiled rather than interpreted,
- permits access to system calls,
- can interface readily with hardware using the code libraries that I provide in the book.
The downside is that it is not really suitable for novice programmers, the output format syntax can be verbose and session management is complex. Even with that, it is worth pointing out that some large-scale web applications, including those by Google and Amazon, do use C++ on their servers for performance-critical systems. The BeagleBone is not a high-end server, so any performance optimizations are always welcome, perhaps even at the cost of complexity.
All of the code for this discussion is available in the GitHub repository for the book Exploring BeagleBone. The code can be viewed publicly at: the ExploringBB GitHub Chapter 10 directory, and/or you can clone the repository on your BeagleBone (or other Linux device) by typing:
1 2 |
molloyd@beaglebone:~$ sudo apt-get install git molloyd@beaglebone:~$ git clone https://github.com/derekmolloy/exploringBB.git |
[/tagline_box][separator style_type=”shadow” top_margin=”5″ bottom_margin=”5″ sep_color=”” icon=”” width=”” class=”” id=””]
A Simple C++ Dynamic Web Page
The first step is to write a simple C or C++ program that is capable of displaying a dynamically generated web page. This task is performed by a bash script in the book chapter, which is perfectly suitable but limiting, both in capability and performance.
Common Gateway Interface (CGI) is a straightforward approach for building dynamic web applications — effectively it allows a web server to share more than just HTML files and/or static images. It does this by allowing executable scripts/programs in a certain file system locations (e.g., /usr/lib/cgi-bin/) to be executed by the web server, and for the output from the scripts/programs to be passed, via the web server, to the web browser of the user that made the request. CGI allows the user’s web browser to pass information (environment and application information) to the script/program using HTTP POST or GET requests. Almost all programming languages can be used to build CGI applications, as their only role in the transaction is to parse the input that is sent to them by the server, and to construct a suitable HTML output response.
On the BeagleBone, the cgi-bin directory requires root access permissions. There are a number of different ways of solving this problem and that is for another discussion. Since the BeagleBone is not typically a multi-user server, I am going to be liberal in my approach to security so that we do not get bogged down in detail. If you are planning to make your BeagleBone publicly visible on the Internet, and place it in control of your home automation system, then you must investigate the topic of server security.
Hello World (with uptime!)
To create a simple C++ CGI application the application can be deployed to the /usr/lib/cgi-bin/ directory on the BeagleBone by default. This directory requires superuser permissions in order to add a script/program — that issue is dealt with shortly.
You can use the nano editor to create the C++ program. Remember that the command “nano -c” displays row/column numbering at the bottoms of the editor display — this is always useful for locating compilation errors. The following code example in Listing 1 can then be entered — it is also available in the exploringBB GitHub repository in the directory /chp10/cgicc/ with the file name hello.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* C++ CGI BeagleBone uptime example -- Written by Derek Molloy (www.derekmolloy.ie) */ #include <iostream> // for the input/output #include <stdlib.h> // for the getenv call #include <sys/sysinfo.h> // for the system uptime call using namespace std; int main(){ struct sysinfo info; // A structure that contains system stats sysinfo(&info); // retrieve the data char *value = getenv("REMOTE_ADDR"); // The remote address CGI environment variable cout << "Content-type:text/html\r\n\r\n"; // Generate the HTML output cout << "<html><head>\n"; cout << "<title>EBB C++ Uptime</title>\n"; cout << "</head><body>\n"; cout << "<h1>BeagleBone System Uptime</h1>\n"; int mins = info.uptime / 60; // the uptime comes from the sysinfo struct int ram = info.freeram / 1024 / 1024; // the available memory in Mb cout << "<div> The BBB system uptime is " << mins << " minutes.\n"; cout << "There is " << ram << " Mb of memory available.</div>\n"; cout << "<div> The CGI REMOTE_ADDR environment variable is " << value << "</div>"; cout << "</body></html>\n"; return 0; } |
This example uses the sysinfo structure to obtain the system uptime and available memory for the BeagleBone single-board computer. It also uses the environment variables to determine the IP address of the client browser that made the request to execute the CGI program. The following environment variables are available (sourced from CgiEnvironment.cpp): [table caption=”CGI Environment Variables ” width=”750″ colalign=”center|center|center|center”] variable, variable, variable, variable; SERVER_SOFTWARE, SERVER_NAME, GATEWAY_INTERFACE, SERVER_PROTOCOL; SERVER_PORT, REQUEST_METHOD, PATH_INFO, PATH_TRANSLATED; SCRIPT_NAME, QUERY_STRING, REMOTE_HOST, REMOTE_ADDR; AUTH_TYPE, REMOTE_USER, REMOTE_IDENT, CONTENT_TYPE; CONTENT_LENGTH, HTTP_ACCEPT, HTTP_USER_AGENT, REDIRECT_REQUEST; REDIRECT_URL, REDIRECT_STATUS, HTTP_REFERER, HTTP_COOKIE; [/table] You can compile the code using the following steps:
molloyd@beaglebone:~/exploringBB/chp10/cgicc$ ./build
Building the hello.cgi C++ CGI Program
…
molloyd@beaglebone:~/exploringBB/chp10/cgicc$ ls -al
total 24
drwxr-xr-x 2 molloyd molloyd 4096 Mar 25 00:00 .
drwxr-xr-x 15 molloyd molloyd 4096 Mar 24 23:44 ..
-rwxr-xr-x 1 molloyd molloyd 85 Mar 24 23:46 build
-rwxr-xr-x 1 molloyd molloyd 7204 Mar 25 00:00 hello.cgi
-rw-r--r-- 1 molloyd molloyd 1193 Mar 25 00:00 hello.cpp
molloyd@beaglebone:~/exploringBB/chp10/cgicc$ sudo cp hello.cgi /usr/lib/cgi-bin/
The build script executes the command “g++ hello.cpp -o hello.cgi“. Please note that the copy command is executed with superuser permissions. This is required as otherwise it would not have the access level required to create the binary executable (hello.cgi) in the /usr/lib/cgi-bin/ directory.
This CGI program can then be called remotely from the web browser on the desktop computer, using the URL http://192.168.7.2:8080/cgi-bin/hello.cgi, as illustrated in Figure 1 below.
Figure 1: A simple C++ CGI application display
The .cgi extension is not a requirement for the executable CGI program, but it is useful here for clarity. For example, the executable could have been named /usr/lib/cgi-bin/hello and the address that is used in the web browser client would be: http://192.168.7.2:8080/cgi-bin/hello
GNU Cgicc (CGI for C++)
Unfortunately, the approach that is described above is only really suitable for programs that make information available to the Internet. By default, C/C++ do not have the built-in libraries required to easily and effectively build interactive CGI applications — for this we need the Cgicc C++ class library.
The GNU Cgicc is a C++ library for building CGI applications. It is powerful and it greatly simplifies the process of building common gateway interface (CGI) applications — those applications that allow you to interact with the BeagleBone over the Internet using a simplified interface within a web browser. As stated, there are other, more recent, approaches to building web applications, but GNU Cgicc offers an efficient high-performance solution.
Installing GNU Cgicc
To avoid complexity, this discussion assumes that you are building the C++ CGI program directly on the BeagleBone itself. Therefore, the first task is to download, compile and install the GNU Cgicc library on the BeagleBone:
Step 1: Download the Ggicc library
The first step is to download the source code for the Cgicc library. You can find the latest version at: ftp://ftp.gnu.org/gnu/cgicc/. At the time that this discussion was written the most recent version is 3.2.16. It is advisable to choose the most recent version and download it to a user account on the BeagleBone, as follows (performing these steps as root is fine too):
molloyd@beaglebone:~$ mkdir cgicc
molloyd@beaglebone:~$ cd cgicc
molloyd@beaglebone:~/cgicc$ wget ftp://ftp.gnu.org/gnu/cgicc/cgicc-3.2.16.tar.gz
…
2015-03-24 00:53:55 (509 KB/s) - 'cgicc-3.2.16.tar.gz' saved [1409037]
molloyd@beaglebone:~/cgicc$ tar xvf cgicc-3.2.16.tar.gz
…
cgicc-3.2.16/doc/lib-overview.tmpl
cgicc-3.2.16/doc/COPYING.LIB
cgicc-3.2.16/doc/COPYING
cgicc-3.2.16/doc/Makefile.am
Step 2. Configure the source code makefiles
The final installation directory (for make install) should be configured to be /usr. This will ensure that the compiled library is made available to all users.
molloyd@beaglebone:~/cgicc$ cd cgicc-3.2.16
molloyd@beaglebone:~/cgicc/cgicc-3.2.16$ ./configure --prefix=/usr
…
config.status: creating doc/Makefile
config.status: creating doc/Doxyfile
config.status: creating cgicc.pc
config.status: creating cgicc/config.h
config.status: executing depfiles commands
config.status: executing libtool commands
Step 3. Make the project
This step takes approximately five minutes in order to build the library on the BeagleBone. It is initiated by typing make in the download directory:
molloyd@beaglebone:~/cgicc/cgicc-3.2.16$ make
Making all in cgicc
make[1]: Entering directory '/home/molloyd/cgicc/cgicc-3.2.16/cgicc'
make all-am
make[2]: Entering directory '/home/molloyd/cgicc/cgicc-3.2.16/cgicc'
/bin/bash ../libtool --tag=CXX --mode=compile g++ -DHAVE_CONFIG_H -I. -x c++ -Wall -W -pedantic -g -O2 -MT
libcgicc_la-CgiEnvironment.lo -MD -MP -MF .deps/libcgicc_la-CgiEnvironment.Tpo -c -o
libcgicc_la-CgiEnvironment.lo 'test -f 'CgiEnvironment.cpp' || echo './''CgiEnvironment.cpp
…
make[1]: Leaving directory '/home/molloyd/cgicc/cgicc-3.2.16/contrib'
make[1]: Entering directory '/home/molloyd/cgicc/cgicc-3.2.16'
make[1]: Nothing to be done for 'all-am'.
make[1]: Leaving directory '/home/molloyd/cgicc/cgicc-3.2.16'
Step 4. Install the library on the BeagleBone
The final step is to install the compiled library for all users on the BeagleBone. Ensure that you execute make install with superuser permissions, otherwise it will fail to place the library files correctly.
molloyd@beaglebone:~/cgicc/cgicc-3.2.16$ sudo make install
[sudo] password for molloyd:
Making install in cgicc
…
Libraries have been installed in: /usr/lib
…
molloyd@beaglebone:~/cgicc/cgicc-3.2.16$cd /usr/lib
molloyd@beaglebone:/usr/lib$ ls libcgi*
libcgicc.a libcgicc.so libcgicc.so.3.2.10 libcgicc.so.5.0.2
libcgicc.la libcgicc.so.3 libcgicc.so.5
C++ Cgicc HTTP GET
The first example that uses the Cgicc library is a simple HTTP GET request-response example. A GET is used to request data from the server resource, whereas a POST is used to submit data to be processed by the server resource. The general structure of a GET request is to use name/value pairs to identify the functionality that you would like to action. For example, a generalized GET request could be described as:
http://my.beaglebone.com/cgi-bin/mygetapp?name1=value1&name2=value2
This would invoke the application “mygetapp” on the BeagleBone and pass the two variables, name1 and name2, that have the values value1 and value2 respectively. This is approach is quite straightforward and it is easy to construct request strings to be actioned from scripts or other applications. However, this approach should never be used to send sensitive information (e.g., passwords), as the URLs will be visible in server logs, browser histories etc.
The HTTP GET LED Controller
The test application is an LED controller that is very similar to the one that is described in Chapter 5 of the book. The on-board system LEDs can be controlled using the C++ LED class that is available to support that chapter.
Figure 2 illustrates the application that results from the code in Listing 2. You can see in the address bar that the URL has the form “…/getLED.cgi?command=on” — the request URL consists of one name “command” that has the value “on“. By changing this value we can control the behaviour of the USR3 LED that is on the top left-hand corner of the BeagleBone PCB. After this request is sent, the USR3 LED lights constantly.
Figure 2: A C++ CGI GET application (on command)
The code for this example is presented in Listing 2 below. The code example uses the LED.h code that is used in Chapter 5. For convenience it is replicated in this project directory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* C++ CGI BeagleBone GET example -- Written by Derek Molloy (www.derekmolloy.ie) You must set the setuid bit for this script in order that it can access the on-board LED sysfs file system. See the web page for instructions. */ #include <iostream> // for the input/output #include <stdlib.h> // for the getenv call #include <sys/sysinfo.h> // for the system uptime call #include <cgicc/Cgicc.h> // the cgicc headers #include <cgicc/CgiDefs.h> #include <cgicc/HTTPHTMLHeader.h> #include <cgicc/HTMLClasses.h> #include "LED.h" // the LED class from Chapter 5 of the book using namespace std; using namespace cgicc; int main(){ Cgicc form; // The Cgicc object LED *led3 = new LED(3); // The LED object -- USR3 // Generate the response HTML page char *value = getenv("REMOTE_ADDR"); // the remote address CGI env. variable cout << "Content-type:text/html\r\n\r\n"; // generate the HTML output cout << "<html><head>\n"; cout << "<title>EBB C++ GET Example</title>\n"; cout << "</head><body>\n"; cout << "<h1>BeagleBone GET Example</h1>\n"; form_iterator it = form.getElement("command"); // read the URL get command string if (it == form.getElements().end() || it->getValue()==""){ cout << "<div> The LED command is missing or invalid.</div>"; cout << "<div> Valid commands are on, off, flash, and status </div>"; } else{ string cmd(**it); cout << "<div> The LED command is " << cmd << ".</div>"; /** This code sets the USR3 LED state using the LED class **/ if(cmd=="on") led3->turnOn(); else if(cmd=="off") led3->turnOff(); else if(cmd=="flash") led3->flash("100"); else if(cmd=="status"){ cout << "<div>"; led3->outputState(); cout << "</div>"; } else cout << "<div> Invalid command! </div>"; } cout << "<div> The CGI REMOTE_ADDR environment variable is " << value << "</div>"; cout << "</body></html>\n"; return 0; } |
The code has some interesting features, The form_iterator it is used to determine the value associated with the command name of the name/value pair. A check is performed to test that the element is not missing or null. If it is then a usage message is presented to the user. Otherwise, a string object cmd is created in place of **it in order to tidy up the syntax — this is not strictly necessary but it makes the code more legible. The cmd is then compared to the four possible options and the correct LED state is triggered. The program can be compiled using the call:
g++ getLED.cpp LED.cpp -o getLED.cgi -lcgicc
where the getLED.cpp and LED.cpp files are passed to the compiler, along with the -l flag to link with the cgicc library. To deploy the resulting binary (getLED.cgi) the deploy script uses the following calls:
sudo cp getLED.cgi /usr/lib/cgi-bin/
sudo chmod +s /usr/lib/cgi-bin/getLED.cgi
The chmod +s call sets the setuid bit — effectively the getLED.cgi binary is now executed with root permissions by Apache. If you perform a “ls -l” in the /usr/lib/cgi-bin directory you will see the “s” bit set on the binary to indicate that the setuid mode is enable.
molloyd@beaglebone:/usr/lib/cgi-bin$ ls -l
total 64
-rwsr-sr-x 1 root root 19924 Mar 26 2015 getLED.cgi
This is necessary because the LED code requires root access in order to modify the state of the on-board LEDs. Importantly, if this were a CGI script, I would be quite concerned at this point about script code injection. However, this is a CGI program that does not parse input fields. That said, it is not ideal and udev rules (see page 247 in the book) are a better solution for non-root resource access.
The code in Listing 2 does not take full advantage of the Cgicc library — for example, it still manually generates the header output. That will be further improved in the next example — so please keep reading, even if you only require HTTP GET functionality.
Figures 3 below illustrates the other functionality that is available in this application. You can trigger the LED to flash at a fixed frequency, or you can request information from the application about the current status of the LED that is made available via sysfs. All of these changes have an immediate effect on the USR3 LED and it behaves as you would expect.
Figure 3: A C++ CGI GET application (animation of all commands)
C++ Cgicc POST LED Example
The second example that uses the Cgicc library is a HTTP POST example. The POST example allows you to interact with a form that contains checkboxes, radio components, buttons, text fields etc. For example you could use the HTML code in Listing 3 to display a form that passes data to the Cgicc C++ application. That is not required in this example, as the postLED.cgi application generates this code dynamically and adapts the rest of the page to represent the current state of the LED. The operation of this example is best understood by watching the animation in Figure 4.
1 2 3 4 5 6 7 8 9 10 11 |
<html><head><title>EBB C++ Post LED Example</title></head> <body><h1>BeagleBone POST LED Example</h1> <form action="/cgi-bin/postLED.cgi" method="POST"> <div>LED state: <input type="radio" name="command" value="on"/> On <input type="radio" name="command" value="off"checked/> Off <input type="radio" name="command" value="flash"/> Flash <input type="checkbox" name="status" /> Display Status </div> <div>Flash period: <input type="text" name="period" size="6" value="100"> ms <input type="submit" value="Execute Command" /></div></form> </body></html> |
Figure 4: A C++ CGI POST application (animation of all functionality)
You can see that this application changes its output to display the state of the LED, and therefore it appears to be stateful. That is only possible in this example because the HTML form “stores” the “application” state — on each occasion you click the Execute Command button the postLED.cgi application executes afresh and runs to completion, thus losing its state. The expected state is only retained by the HTML form. The full source code for the Cgicc HTTP POST example is presented in Listing 4 below. It is important to note that this is the only source code required! The application generates the HTML form, which calls itself, over and over again. Just like the getLED.cgi application, the LED3 output changes instantly and appears as you would expect.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* C++ CGI BeagleBone POST example -- Written by Derek Molloy (www.derekmolloy.ie) You must set the setuid bit for this script in order that it can access the on-board LED sysfs file system. This example integrates the form for ease of use -- i.e., it is a form that calls itself. It could just as easily receive the input from a regular HTML page. */ #include <iostream> // for the input/output #include <stdlib.h> // for the getenv call #include <sys/sysinfo.h> // for the system uptime call #include <cgicc/Cgicc.h> // the cgicc headers #include <cgicc/CgiDefs.h> #include <cgicc/HTTPHTMLHeader.h> #include <cgicc/HTMLClasses.h> #include "LED.h" // the LED class from Chapter 5 of the book using namespace std; using namespace cgicc; int main(){ Cgicc form; // the CGI form object LED *led3 = new LED(3); // the LED object -- USR3 string flashPeriod, command; // default values bool isStatus = form.queryCheckbox("status"); // get the state of the status checkbox form_iterator it = form.getElement("period"); // get the period text value if (it == form.getElements().end() || it->getValue()==""){ flashPeriod = "100"; // if it is invalid use 100 } else { flashPeriod = it->getValue(); } // otherwise use submitted value it = form.getElement("command"); // get the radio command chosen if (it == form.getElements().end() || it->getValue()==""){ command = "off"; // if it is invalid use "off" } else { command = it->getValue(); } // otherwise use submitted value char *value = getenv("REMOTE_ADDR"); // The remote address CGI env. variable // Generate the form but use states that are set in the form that was submitted cout << HTTPHTMLHeader() << endl; // Generate the HTML form using cgicc cout << html() << head() << title("EBB C++ Post LED Example") << head() << endl; cout << body() << h1("BeagleBone POST LED Example") << endl;; cout << "<form action=\"/cgi-bin/postLED.cgi\" method=\"POST\">\n"; cout << "<div>LED state: <input type=\"radio\" name=\"command\" value=\"on\"" << ( command=="on" ? "checked":"") << "/> On "; // is the command="on"? cout << "<input type=\"radio\" name=\"command\" value=\"off\"" << ( command=="off" ? "checked":"") << "/> Off "; cout << "<input type=\"radio\" name=\"command\" value=\"flash\"" << ( command=="flash" ? "checked":"") << "/> Flash "; cout << "<input type=\"checkbox\" name=\"status\" " << (isStatus ? "checked":"") << " /> Display Status </div>"; cout << "<div>Flash period: <input type=\"text\" name=\"period\" size=\"6\" value=\"" << flashPeriod << "\"> ms "; // populate the text field cout << "<input type=\"submit\" value=\"Execute Command\" />"; cout << "</div></form>"; // Process the form data to trigger the LED state if (command=="on") led3->turnOn(); // turn the LED on? else if (command=="off") led3->turnOff(); // off? else if (command=="flash") led3->flash(flashPeriod); // flash with the period above else cout << "<div> Invalid command! </div>"; // not possible at the moment // If the Display Status checkbox is checked then display the status now // this should happen after the command is set, otherwise it is old data if (isStatus){ cout << "<div>"; led3->outputState(); cout << "</div>"; } cout << "<div> The CGI REMOTE_ADDR environment variable is " << value << "</div>"; cout << body() << html(); return 0; } |
This program has some interesting features. In particular, it uses functions such as HTTPHTMLHeader(), html(), body() etc. to generate the HTML content for the output. This is much less verbose that in Listings 1 and 2 and is less prone to error. There are many more such functions that can be used to further clean up the code. The code example also demonstrates how to interact with radio buttons (command), checkboxes (status), and text inputs (period) within HTML forms.
It is important that the form data is parsed at the top of the program. This is because the form data that was previously submitted needs to be propagated into the new output. Clearly, the first time this form is requested there will be no data present and the code at the beginning of the program assigns default value (e.g., flashPeriod=”100″, command=”off”). If this is not performed then the program will suffer from segmentation faults. From that point onwards, the form output needs to maintain the state and that is why these values appear in the HTML generation code. For example,
1 |
(command=="on" ? "checked":"") |
is a clever piece of code that compares the command string to the string “on”. If they are equal then the word “checked” appears in the HTML form at that point in the code (thanks to the output stream operator <<); however, if they are not equal then the string “” (nothing) appears at that point in the HTML code. This allows a radio item or checkbox item to remain checked or unchecked. Finally towards the end of the program the command is processed and the code to display the status is placed.
cout << (s.length() < t.length() ? s : t) << endl;
This line of code will display the shorter of the strings s and t.[/tagline_box]
Conclusions
This discussion has just scratched the surface on what can be performed using CGI and C++ on the BeagleBone. For very complex applications you may be better placed to examine other frameworks, but for simple high-performance web interfaces, the GNU Cgicc library provides a very appropriate solution. There are several limitations with the current solution. It is a single session solution -- If two users, on two different machines, access the postLED.cgi script at the same time then very strange things will happen! For example, each browser will store an independent state that is likely to be contradictory. However, given that there is only one USR3 LED on the BeagleBone PCB that is not a very significant issue. For more complex applications, session management is important.
For more information on the Cgicc library please see the GNU cgicc library documentation. You will see that the library is capable of handling cookies, file transfers and much more by browsing the Class List.
hi Derek,
you tought me much things thru your videos. Your book shows very good the capabilitys of this technology. Extending the book by a website with further information is great concept. I don’t want to know, how much time this project took and will take.
I never thought that i am able to understand how to turn on a led thru a mobile on my BBB or to write code on my desktop and deploy it automatically to another. I have to thank you very, very much!
greetings
foikei
Thanks for your support Foikei, It took a long time to put everything in place! Great to hear that it has made a difference! Derek.
Hi Derek, I just wanted to say, Thank you! 🙂 These stuffs are brilliant. Not that I learned to implement my C++ programming skills in server side, I was able to develop a Java program that runs on Android, which I will use it in my thesis for my B.Sc..
You Helped me a lot with your book and your website and videos. Frankly speaking, you helped me to become the Geek (Person) I wanted to be!
Again, adore your book and your website and your youtube videos.
Best Wishes
Amir Nourinia
Hi,
I followed the steps for configuring cgicc libraries. But while doing the make step i end up with the following error:
Making install in cgicc
make[1]: Entering directory ‘/path/to/cgicc-3.0.2/cgicc’
/bin/sh ../libtool –mode=compile c++ -DHAVE_CONFIG_H -I. -I. -I. -I.. -g -O2 -c CgiUtils.cc
rm -f .libs/CgiUtils.lo
c++ -DHAVE_CONFIG_H -I. -I. -I. -I.. -g -O2 -c -fPIC -DPIC CgiUtils.cc -o .libs/CgiUtils.lo
CgiUtils.cc:111:30: error: ‘string’ does not name a type
CGICCNS unescapeString(const string& src)
^
CgiUtils.cc:111:41: error: ‘std::__cxx11::string cgicc::unescapeString(const int&)’ should have been declared inside ‘cgicc’
CGICCNS unescapeString(const string& src)
^
CgiUtils.cc: In function ‘std::__cxx11::string cgicc::unescapeString(const int&)’:
CgiUtils.cc:117:18: error: request for member ‘begin’ in ‘src’, which is of non-class type ‘const int’
for(iter = src.begin(); iter != src.end(); ++iter) {
^
CgiUtils.cc:117:39: error: request for member ‘end’ in ‘src’, which is of non-class type ‘const int’
for(iter = src.begin(); iter != src.end(); ++iter) {
^
Makefile:229: recipe for target ‘CgiUtils.lo’ failed
make[1]: *** [CgiUtils.lo] Error 1
make[1]: Leaving directory ‘/path/to/cgicc-3.0.2/cgicc’
Makefile:161: recipe for target ‘install-recursive’ failed
make: *** [install-recursive] Error 1
Hi,
I tried the first example (the “hello.cgi” one) and seemed to be stuck.
When trying to connect to “IPADDRESS/cgi-bin/hello.cgi” it would not be able to connect and I would get a 404 error.
I feel like I am missing out a step with the configuration of the Apache2 server. Was there some pre configuring that was required?
Thanks!
Try other versions…for me,except showed the same error..may others work for you
But try to remove make and allow permission
if even didnt work after…try older version or a completely new one
Hi,
For those who have problems with executing .cgi files on web browser,
I prepared quick solution.
1) Check if apache2 service is listening on port 8080:
$sudo netstat -tlpn
If not, set VirtualHost port in /etc/apache2/ports.conf
and /etc/apache2/sites-available/000-default.conf
then reload apache service:
$sudo systemctl reload apache2
2) Make sure you have proper modules enabled:
$cd /etc/apache2/modules-enabled
$sudo ln -s ../mods-available/cgi.load
3) Teach apache how to interpret .cgi files in directory /usr/lib/cgi-bin/ (or elesewhere):
$sudo nano /etc/apache2/apache2.conf
After other directories configs add:
Options ExecCGI
AllowOverride None
Require all granted
AddHandler cgi-script .cgi
4) Make test of apache configuration:
$sudo apachectl configtest
Should end with ‘Syntax OK’
5) Reload apache service:
$sudo systemctl reload apache2
Now connecting through web browser to:
your.ip.v4.address:8080
should give file /var/www/html/index.html
and:
your.ip.v4.address:8080/cgi-bin/file.cgi
should properly compile /usr/lib/cgi-bin/file.cgi
Hi,
For those who have problems with executing .cgi files on web browser,
I prepared quick solution.
1) Check if apache2 service is listening on port 8080:
sudo netstat -tlpn
If not, set VirtualHost port in /etc/apache2/ports.conf
and /etc/apache2/sites-available/000-default.conf
then reload apache service:
sudo systemctl reload apache2
2) Make sure you have proper modules enabled:
cd /etc/apache2/modules-enabled
sudo ln -s ../mods-available/cgi.load
3) Teach apache how to interpret .cgi files in directory /usr/lib/cgi-bin/ (or elesewhere):
sudo nano /etc/apache2/apache2.conf
After other directories configs add:
4) Make test of apache configuration:
sudo apachectl configtest
Should end with ‘Syntax OK’
5) Reload apache service:
sudo systemctl reload apache2
Now connecting through web browser to:
your.ip.v4.address:8080
should give file /var/www/html/index.html
and:
your.ip.v4.address:8080/cgi-bin/file.cgi
should properly compile /usr/lib/cgi-bin/file.cgi