Welcome to SIMPL Programming for Python
Lesson #7

Course content Enter chat room Send email 
to mailing list
Check calendar

Lesson Overview

This lesson is about using SIMPL within a CGI program.

We are going do things a little differently than we have in the previous lessons. We will still be sending various possible messages to a C receiver, just as in lessons #3, #4, and #6 however, the user front end will be provided for by a web browser running a small piece of HTML code. This HTML file contains a form which is processed to retrieve the type of message to be sent. This form processing is performed by a CGI script written in Python. When the value of the appropriate form key is determined, the corresponding message is then sent to the C receiver program for processing.

In short, we will be using the same C receiver program that we used in lessons #3, #4, and #6. Accordingly, the messages will also be the same. The HTML code will provide the user input capability and the CGI script will process that input and send the corresponding message to the C receiver. It is interesting to note that where the SIMPL messages originate is of no concern to the receiver program. So far it has received messages from a local Python program (lesson #4), via the tclSurrogate (lesson #6) and now via a CGI script (lesson #7).

Again, we recommend that you read the document readme.python which is located in the docs directory below the SIMPL root directory. Pay particular attention to the final section called "SIMPL in CGI Programs".


Note:

Like lesson #6, we are going to run all of the programs on one host for convenience. This would not normally be the case. A more usual scenario would be that the browser would be running in some other location than the server. Moreover, the server would likely be sending its message via the CGI script to some other remote host running the receiver program.

With this algorithm, we hope to demonstrate the following:

  1. how information may be sent via a browser to a receiver using SIMPL.

Note:

Do NOT cut and paste the following code pieces. The scripts are available in the .../www directory for you to run directly.


Let's quickly examine the HTML code.

The following code can be found in the ../www/lesson7_cgi.html file.
1.<html>
2.<head>
3.<title>Python SIMPL CGI</title>
4.</head>
5.<body>
6.<H1><center>Python SIMPL CGI</center></H1>
7.<form name="tokens" method="post" action="http://localhost/cgi-bin/lesson7_cgi.py">
8.<center>
9.    <select name="tokens" size="3">
10.        <option selected>send message token type 10</option>
11.        <option>send message token type 20</option>
12.        <option>send message token type 30</option>
13.    </select>
14.    <br/>
15.    <p>
16.     <input type="submit" value="send message"/>
17.    </p>
18.</center>
19.</form>
20.</body>
21.</html>

Lines 1-6 are the usual HTML start code.
Line 7 defines the form required and the CGI program that will process it. Notice the URL for the action to be taken upon submission of the form. It is http://localhost/cgi-bin/lesson7_cgi.py. The http is such that the server port will located. The localhost is such that the host that the browser is running on is selected. The cgi-bin is the directory where the server will find the CGI script to be run. Finally, the CGI script to be called is named lesson7_cgi.py.
Lines 8-18 produce the required user front end.

Now, let's examine the Python CGI script.

The following code can be found in the ../www/lesson7_cgi.py file.
1. #! /usr/bin/python
2.
3. # required modules
4. import cgi
5. #cgi.test()
6. import wcsimpl
7.
8. def sendToReceiver(value):
9.     sName = "SENDER"
10.     rName = "RECEIVER"
11.
12.     # attach a simpl name
13.     retVal = wcsimpl.nameAttach(sName, 1024)
14.     if retVal == -1:
15.         toBrowser("name attach error " + wcsimpl.whatsMyError())
16.         return
17.
18.     # name locate the receiver
19.     receiverId = wcsimpl.nameLocate(rName)
20.     if receiverId == -1:
21.         toBrowser("name locate error " + wcsimpl.whatsMyError())
22.         return
23.
24.     if value == "send message token type 10":
25.         wcsimpl.packInt(10, wcsimpl.BIN)
26.         wcsimpl.packInt(99, wcsimpl.BIN)
27.         wcsimpl.packInt(999, wcsimpl.BIN)
28.         wcsimpl.packInt(9999, wcsimpl.BIN)
29.     elif value == "send message token type 20":
30.         wcsimpl.packInt(20, wcsimpl.BIN)
31.         wcsimpl.packFloat(3.1415, wcsimpl.BIN)
32.     elif value == "send message token type 30":
33.         wcsimpl.packInt(30, wcsimpl.BIN)
34.         s = "We are the knights who say Neee."
35.         l = len(s)
36.         wcsimpl.packInt(l, wcsimpl.BIN)
37.         wcsimpl.packString(s, wcsimpl.BIN)
38.     else:
39.         toBrowser("unknown choice")
40.         return
41.
42.     # send the message to the receiver
43.     retVal = wcsimpl.send(receiverId)
44.     if retVal == -1:
45.         toBrowser("send error " + wcsimpl.whatsMyError())
46.
47. #***************************************************************************
48.
49. def toBrowser(str):
50.     print "Content-type: text/html\n"
51.     print "<HTML>\n"
52.     print "<HEAD>\n"
53.     print "<TITLE>%s</TITLE>\n" %("Python SIMPL CGI")
54.     print "</HEAD>\n"
55.     print "<BODY>\n"
56.     print "<H1><center>%s</center></H1>\n" %str
57.     print "</BODY>\n"
58.     print "</HTML>\n"
59.
60. #***************************************************************************
61. # operational part of the program
62.
63. # get the form parameters
64. form = cgi.FieldStorage()
65.
66. # check for a form
67. if not form:
68.     # no form available
69.     toBrowser("no form available")
70. else:
71.     # process form parameter
72.     key = "tokens"
73.     if form.has_key(key):
74.         value = form.getvalue(key)
75.         # SIMPL send the chosen message to the receiver
76.         sendToReceiver(value)
77.     else:
78.         toBrowser("no message type")
79.
80. # detach SIMPL name
81. wcsimpl.nameDetach()

Lines 4-6 import the required modules. Note line 5; it is commented out but when it is uncommented it will dump information to the browser regarding the server being used. It can be very useful for debugging.
Lines 8-45 define a function used to build the message and perform the SIMPL send to the C receiver.
Lines 9-10 define the SIMPL names of the sender and the receiver.
Lines 13-16 attach unique SIMPL name.
Lines 19-22 SIMPL name locate the receiver program.
Lines 24-40 build the message to be sent to the receiver.
Lines 43-45 perform the SIMPL send to the receiver.
Lines 49-58 define a function to send messages back to the browser.
Lines 64-81 define an HTML form, retrieve the form key that determines the type of message to be sent to the receiver, and finally perform a SIMPL name detach.

Let's examine the receiving program. Note: this is exactly the same receiving program used in Lessons #3, #4, and #6.

The following code can be found in the ../src/receiver.c file.
1. /*
2. FILE: receiver.c
3. DESCRIPTION: This is a C simpl receiver.
4. Refer to lessons 3, 4, 6, 7.
5. USAGE: receiver
6. */
7.
8. // include required headers
9. #include <stdio.h>
10. #include <stdlib.h>
11. #include <simpl.h>
12.
13. // define possible message structures
14. typedef struct
15.     {
16.     int token;
17.     int var1;
18.     int var2;
19.     int var3;
20.     } MSG1;
21.
22. typedef struct
23.     {
24.     int token;
25.     float var1;
26.     } MSG2;
27.
28. typedef struct
29.     {
30.     int token;
31.     int var1;
32.     char var2[34];
33.     } MSG3;
34.
35. int main()
36. {
37. char *me = "RECEIVER";
38. char *sender;
39. char mem[1024];
40.  int n;
41. MSG1 *in1;
42. MSG2 *in2;
43. MSG3 *in3;
44. int *token;
45.
46. // perform simpl name attach
47. if (name_attach(me, NULL) == -1)
48.     {
49.     printf("%s: cannot attach name-%s\n", me whatsMyError());
50.     exit(-1);
51.     }
52.
53. while (1)
54.     {
55.     // receive incoming messages
56.     n = Receive(&sender, mem, 1024);
57.     if (n == -1)
58.         {
59.         printf("%s: Receive error-%s\n", me, whatsMyError());
60.         continue;
61.         }
62.
63.     // set a pointer to the value of the message token
64.     token = (int *)mem;
65.
66.     // decide course of action based on the value of the token
67.     switch (*token)
68.         {
69.         case 10:
70.             in1 = (MSG1 *)mem;
71.             Printf("token=%d var1=%d var2=%d var3=%d\n",
72.            & nbsp;    in1->token,
73.            & nbsp;    in1->var1,
74.            & nbsp;    in1->var2,
75.            & nbsp;    in1->var3);
76.             break;
77.
78.         case 20:
79.             in2 = (MSG2 *)mem;
80.             printf("token=%d var1=%d\n",
81.            & nbsp;    in2->token,
82.            & nbsp;    in2->var1);
83.             break;
84.
85.         case 30:
86.             in3 = (MSG3 *)mem;
87.             printf("token=%d var1=%d var2=%.*s\n",
88.                  in3->token,
89.            & nbsp;    in3->var1,
90.            & nbsp;    in3->var1,
91.            & nbsp;    in3->var2);
92.             break;
93.
94.         default:
95.             printf("%s: unknown message token=%d\n", me. token);
96.         }
97.
98.     // reply to sender
99.     Reply(sender, NULL, 0);
100.   }
101.
102. return(0);
103. }

Lines 9-11include the required C header files. Note the inclusion of the simpl.h header file.

Lines 14-20
define the binary message that corresponds to token value 10.

Lines 22-26
define the binary message that corresponds to token value 20.

Lines 28-33
define the binary message that corresponds to token value 30.

Line 35
is the start of the program.

Lines 37-44
declare necessary local variables.

Lines 47-51
handle the simpl name attach.

Line 53
starts an infinite loop which awaits incoming messages.

Lines 56-61
receive the incoming messages.

Line 64
sets a pointer to the incoming message token.

Lines 67-96
deal with each message type based on the token by printing the various message components to the screen.
Line 99 replies a null message to the blocked sender. This reply message could be anything at all but in the interests of simplicity, the reply message has been made null.

The Makefile for the C receiver program.

The receiver program must be compiled and linked before it can be of any use. Go to ../src and at the command prompt type:

make clean
Then type:
make install
This makes a new executable of receiver.c called receiver and puts it in ../bin .

Note:

In order to run this Makefile, the shell variable SIMPL_HOME must be set so that the make can find the SIMPL header files and library.

The Web Server.

In order to continue with this lesson and be able to run the programs, the web server needs to be checked for certain configuration issues. Again, we recommend that you read the document readme.python which is located in the docs directory below the SIMPL root directory. Pay particular attention to the subsection called "Web Server".

As previously stated we are going to use the Apache web server. In order for Apache to perform as required, it may be necessary for Apache's configuration file to be modified. Let us say that that file is /etc/httpd/conf/httpd.conf. Let us also say that the html, cgi, etc. files accessed and used by Apache are located in subdirectories below /var/www. The following are some of the things that have to be set for the Apache server to be able to function correctly:

  1. The lesson7_cgi.html and lesson7_cgi.py CGI file must be copied into the relevant directories for the Apache server to find them:

        cd ../www
        cp lesson7_cgi.html /var/www/html
        cp lesson7_cgi.py /var/www/cgi-bin

    Make certain that the permissions on these files make them available to all users.

  2. The following line should appear in the configuration file so that the CGI dynamic shared object (DSO) can be used by Apache:

        LoadModule cgi_module modules/mod_cgi.so

  3. A useful shortcut for Apache is to define what is meant by the standard directory listing for cgi-bin, the location of the CGI programs. This also appears as a line in the configuration file.

        ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

  4. You will need to be able to access the CGI programs so you will need the following as well:

        <Directory "/var/www/cgi-bin">
        AllowOverride None
        Options None
        Order allow,deny
        Allow from all
        </Directory>

  5. In order to access SIMPL libraries it may be necessary to export a shell variable to Apache. Specifically, if the CGI program is a Python script then the Python interpreter will need to know where the SIMPL modules are located. This is often accomplished using the shell variable PYTHONPATH. For example, at boot time the following shell command may be run from a profile:

        export PYTHONPATH=/home/simpl/python/modules

    If this is the case, then the following line may also be required in the Apache configuration file:

        PassEnv PYTHONPATH

  6. Again for example, it may also be necessary to add the following line in the case of a Python-based CGI script if your CGI script name ends in .py:

        AddHandler cgi-script .py

  7. All SIMPL libraries require a special directory whose location is given by an environment variable called FIFO_PATH. This variable must also be set, usually at boot time and must also be passed to Apache with the following line in the configuration file:

        PassEnv FIFO_PATH

Let's run the programs.

In order to run this lesson's programs do the following:

  1. make sure that PYTHONPATH has been exported to your shell.
    ie. export PYTHONPATH=$(SIMPL_HOME)/python/modules
  2. open a shell window. This can be opened from a desktop such as KDE or GNOME.
  3. in this shell window, change directory to ../bin.
  4. start the web server. In our case we used Apache because of its widespread use. At the prompt type:
    apachectl start
  5. start the C receiver program. At the command line prompt type:
    receiver
  6. open a web browser.
  7. for the URL enter:
    http://localhost/lesson7_cgi.html
  8. the browser should render a list of three choices. Choose one and then push the "send message" button.
  9. check the shell window where the receiver is running. You should see a message printed to the screen.


Let's rerun with the C receiver and the webserver in the cloud

Recall that in previous lessons we had arranged to run the C receiver on the Linode at icanprogram.ca. The output from the C receiver was piped into a filter process which in turn wrapped that output in HTML for display at:

http:/icanprogram.ca/course/creceiver.html

We also have arranged for the Python-CGI to be available to the webserver on the Linode. To run in this mode the URL is:

http://icanprogram.ca/course/lesson7_cgi.html

Notice what happened here:

The very same cloud based instance of C receiver that we accessed via the TCP/IP SIMPL surrogate and tclSurrogate in previous lessons has now been accessed remotely from a browser using Python as the CGI script. NO CHANGES whatsoever were required in the C receiver code to achieve this. It is identical code to the C receiver you accessed locally in these same lessons.

Summary

Let's summarize what you should have observed in this lesson:

The SIMPL toolkit allows you to build modules that are

This is the SIMPL toolkit's value proposition.

End of Lesson 7.


Copyright of iCanProgram Inc.  2003-2011