View/Edit/Compile/Run Web Environment


  1. Overview
  2. Implementation
  3. Interactive I/O (disabled pending redesign)
  4. Security Issues
    IO Authentication - separate document
  5. Plotting
  6. iPlot
  7. HTML
  8. SS
    SS homepage and local documentation
  9. Download

1. Overview

The View/Edit/Compile/Run environment enables students to edit, compile, and run C, Java, and Korn shell programs via a web interface to a Unix server. It provides separate home directories for each course enabled on the system. Each user course directory contains subdirectories for ten projects, a1, ..., a10, and each project contains four C (or C++), Java, dash, octave, and Python files, as well as editable Makefile, text, C/C++ headers, and flex/bison scan.l and parse.y files.

In addition to the ten standard project directories, there is an extra project aX; a special project GSL where C code is linked with the GNU Scientific Library; and a project PPM where C code is linked with a small Portable Pixel Map image library.

The special iPlot project provides a pre-built application for interactive plotting.

The HTML project supports programs generating HTML output.

The SS project provides an interface to a spreadsheet application.

The environment is accessible online at http://vecr.ece.villanova.edu/ and requires Villanova LDAP authentication. Static sample pages are shown here for course fc (Freshman C course).

Sample project home page:

frodo - fc - projects

a1,   a2,   a3,   a4,   a5,   a6,   a7,   a8,   a9,   a10,   aX,   GSL,   PPM,   iPlot,   HTML,   SS,  

zip - download all projects

documentation and source code

Logout - (UserID logout with empty password)

For system administrators and course instructors, the project home page also contains an option to set their UserID to any user. This is useful for grading and for helping students debug their programs.

Sample administrator project home page:

rperry - fc - projects

a1,   a2,   a3,   a4,   a5,   a6,   a7,   a8,   a9,   a10,   aX,   GSL,   PPM,   iPlot,   HTML,   SS,  

zip - download all projects

documentation and source code

Logout - (UserID logout with empty password)

Each project subdirectory page contains links to edit the programs, plus links to view (read-only) all files in the subdirectory. Each subdirectory is initialized with a Makefile and other files related to an assignment, such as input data files.

Sample a1 subdirectory page:

frodo - fc - a1

Home

Edit:

   p1.c,   p2.c,   p3.c,   p4.c,   p1.h,   p2.h,   p3.h,   p4.h,  

   p1.sh,   p2.sh,   p3.sh,   p4.sh,   p1.txt,   p2.txt,   p3.txt,   p4.txt,  

   Makefile,   p1.java,   p2.java,   p3.java,   p4.java,   scan.l,   parse.y,  

   p1.m,   p2.m,   p3.m,   p4.m,   p1.py,   p2.py,   p3.py,   p4.py,  

View:

     360 Jan 23 14:10 Makefile
      84 Feb 12 11:39 p1.c

For a C++ course the Edit list would show .cc and .hh files instead of .c and .h.

In edit mode, a scrollable textarea contains the source code. Sample a1/p1.c edit page:

frodo - fc - a1/p1.c

a1 - Home - preproc - asm - asmopt - disasm - cerr - clean - reload - rmcmts - indent - +frames - -frames
Compile args:
<-save changes args:
1
2
3
4
5
6
7
8
9
10
11

<-save changes


After modifying project source code, Update copies the code to the server. After compiling using the Compile link, the program can be run using Run, or run via gdb for debugging using Debug.

If the program generates output values suitable for plotting, the Plot icon options can be used to pipe the output through a 2D or 3D plotting script to generate a GIF image.

If the program generates PPM image output, the image can be viewed (converted to PNG) using the image view icon

If the program generates output values representing audio samples at 8000 Hz., the Audio icon next to the Debug button can be used to convert to 16-bit WAV and play the audio directly in your browser.

C/Run performs compile and run in one step, IO runs the program with Interactive I/O, and IO/D runs gdb interactively. Program command-line arguments may be specified in the args input fields.

Additional options are:

Sample Compile output:

make p1
---

gcc -std=c11 -pedantic -Wall -g -lm -o p1 p1.c


---
Done.

Sample Run output:

./p1 
---

1 2
2 4
3 1


---
Exit status = 12

Sample 2D Plot output:

Sample 3D Plot output:


2. Implementation

The environment is self-contained in a /vecr/ subdirectory of /home/httpd/. The web server runs chroot() in /home/httpd/ under uid/gid httpd. In order to run programs in this environment, /usr/, /opt/, and /proc/ are loopback mounted read-only there:

Filesystem            kbytes    used   avail capacity  Mounted on
/usr                 3008783 1380722 1567886    47%    /home/httpd/usr
/opt                10326052 1395670 8827122    14%    /home/httpd/opt
/proc                      0       0       0     0%    /home/httpd/proc
The web server maps URLs starting with /prog/ to CGI scripts in the /vecr/cgi/ directory:
<Directory /vecr/cgi>
Options None
</Directory>
ScriptAlias /prog/ "/vecr/cgi/"
/vecr/cgi/ contains links to a setuid-root compiled C program:
# pwd
/home/httpd/vecr/cgi
# ls -li ccs fc
     66721 ---s--x---   2 root     httpd       5980 Feb  2 09:13 ccs
     66721 ---s--x---   2 root     httpd       5980 Feb  2 09:13 fc
#
which is a wrapper that sets the real and effective uid and gid to 0 and invokes the view.pl perl script. The wrapper also sets an environment variable COURSE from the link name, currently either ccs for the Computer Communications Security course, or fc for the Freshman C course. The COURSE environment variable is used to determine the course-specific user home directory location.

The action taken by view.pl depends on whether the HTTP request was GET or POST. For GET, it prepends "GET" to the arguments and exec's the view.sh shell script. For POST, it parses the form input name/value pairs, opens a pipe to stdin of view.sh, prints the mode (update, run, debug, plot, etc.) and arguments, then prints the data from the textarea field (i.e. the C, Java, or dash source code being edited).

view.sh dynamically creates the web pages from which it is reinvoked using GET or POST via the wrapper and perl script. It logs the connection, sanitizes the REMOTE_USER string and extracts the UserID (e.g. extracts rperry from the LDAP DN "uid=rperry,ou=Faculty,ou=Employees,o=villanova.edu"), creates a new unique uid/gid for the UserID, if necessary, and creates project subdirs. Then it handles the GET or POST request, creating additional user files, such as symlinks to files in the prototype project directories, as needed. lib/ contains the database mapping UserID's to uid's, and a counter file used when creating a new uid.

For GET edit and POST update requests, view.sh handles some of the request itself, running as root, then runs a separate update.sh script under the uid/gid of the user. For all other requests, it runs a separate run.sh script under the uid/gid of the user. Also, for the POST run, debug, plot, and command requests, it uses the dash version of ulimit to limit resources.

run.sh runs under the user uid/gid. It determines whether C, Java, or dash is being used based on the file name extension. For compile, run, debug, and plot, it runs the command, including any user-supplied command-line arguments, using a run program which limits the run time to 30 seconds. The limits placed on run-time and other resources help prevent accidental runaway processes.


3. Interactive I/O

(disabled pending redesign)

Interactive programs can be run using the IO option.

Example: frodo - fc - a4/p1.c

#include <stdio.h>
int main( void)
{
  double d;
  while( 1)
  {
    printf( "Enter a number: ");
    if( scanf("%lf",&d) != 1) break;
    printf( "d = %g, 1/d = %g\n", d, 1/d);
  }
  return 0;
}
Using the IO option:


IO Applet Window

The IO applet connects through the web server as a proxy to a Java server to run the program. The top area of the window displays diagnostic information about the connection. The middle area displays the program input and output. Input is typed at the bottom and is copied to the middle area whenever the user presses Enter to send the input to the program.

Options at the very bottom are available to signal end-of-file, stop/disconnect, restart the applet, change font size, and save the output window to file "output.txt" on the server.

The applet starts by requesting a proxy connection through the web server to localhost port 7 where a Java server is listening:


Initial Applet Connection

The Java server then creates a client thread to communicate with the applet:


Applet, Client, and User Process

In the figure above, the transparent web server proxy between the Applet and Copy/Client threads is not shown. After creating the client thread, the Java server is no longer involved in the communications but is shown to complete the diagram of parent/child process relationships drawn with dashed lines. That is, the Server, running as root, creates the Client thread, also running as root. After verifying authentication data from the applet, the Client thread creates a Copy thread, running as root, to handle copying program output back to the applet. The Client thread also creates a Run process, running as the user, which runs and monitors the user program. When needed for the Save option, the Client thread creates a temporary Save process which is not shown in the figure.

Applet authentication data consists of the user name and uid, time, and a ticket. This data, as well as the user directory, program to run, and command-line arguments, are obtained by the applet from parameters passed in the IO web page, for example:

<applet codebase="/vecr/IO" code="IOapplet.class" width=700 height=600>
<param name="user" value="frodo">
<param name="uid" value="3001">
<param name="time" value="1108241035769">
<param name="ticket" value="6afb9f2c5068c68818b202b8995ab03ea7dcc0f13ca70d77ba0215c935b781a5">
<param name="dir" value="/vecr/fc/home/frodo/a4">
<param name="prog" value="./p1">
<param name="args" value="">
The ticket is an HmacSHA256 message authentication code based on a secret, the current time, the user name and uid, created when the IO option is selected. Authentication consists of verifying the ticket and checking that it is not too old. Since the user was already known to be authenticated at the time the IO option was initiated, the ticket allows that authentication to propagate from the applet to the server without having the user resend their userid and password.

After authentication, the applet communicates with the Client using DataOutputStream writeByte() for bytes and writeUTF() for strings to implement a simple protocol using byte constants DATA, EOF, STOP, and SAVE. When the user presses Enter in the input area, the applet sends the DATA byte followed by the input string. Similarly, for the Save option, the applet sends the SAVE byte followed by the output text area in a string. For EOF and STOP options, the applet sends the corresponding EOF or STOP byte. On the server side, the main Client loop uses a switch statement to select the action corresponding to the protocol byte.


4. Security Issues

A separate document is available on security issues related to IO Authentication.

The parts which run as root should not contain flaws which may allow creation or overwriting of arbitrary files or execution of arbitrary user input. Some additional safeguard for the system is provided by running in a chroot environment with read-only, nosuid loopback mounts.

The parts which run as the user allow access to most features of a standard Unix login account, but in a chroot environment with some resource limitations. Since the user can run an arbitrary C, Java, or sh program, there would be little security gained by restricting what can be placed in the command-line arguments to be executed by the shell. In fact, run.sh uses dash eval to run the user programs on purpose to enable use of pipelining and I/O redirection, and the Command option runs an arbitrary Unix command entered into the args input field.

User file security is provided by having the home directories owned by root and readable only by the specific user group, e.g. for user rperry with uid=gid=3002:

# pwd
/home/httpd/vecr/fc/home/rperry
# ls -ld . a1
drwxr-x---  12 root     3002         512 Feb  2 10:01 .
drwx------   2 3002     3002         512 Jan 23 19:23 a1
#
So users can not change the permissions on their home directory and can not see other users files.
5. Plotting

Output suitable for 2D plotting is one x,y pair per line. A program can also just print one y value per line and the plot will have an automatic x axis.

Plots are generated using gnuplot, and gnuplot help plot datafile says:

...
 Only one column (the y value) need be provided.  If x is omitted, `gnuplot`
 provides integer values starting at 0.

 In datafiles, blank records (records with no characters other than blanks and
 a newline and/or carriage return) are significant---pairs of blank records
 separate `index`es (see `plot datafile index`).  Data separated by double
 blank records are treated as if they were in separate data files.

 Single blank records designate discontinuities in a `plot`; no line will join
 points separated by a blank records (if they are plotted with a line style).
...
You can look at the 2D plot script, which basically does this:
(echo "set term gif\nset output\nplot '-' notitle with linespoints"; cat) |
 /usr/bin/gnuplot
to plot standard input, which comes from standard output of the program. Standard error is redirected to a file plot.stderr in the current project directory.

The 3D splot script is similar, and uses the gnuplot splot command, for which help splot datafile says:

...
 Data file organization is essentially the same as for `plot`, except that
 each point is an (x,y,z) triple.  If only a single value is provided, it
 will be used for z, the datablock number will be used for y, and the index
 of the data point in the datablock will be used for x.  If two or four values
 are provided, `gnuplot` uses the last value for calculating the color in
 pm3d plots.  Three values are interpreted as an (x,y,z) triple.  Additional
 values are generally used as errors, which can be used by `fit`.

 Single blank records separate datablocks in a `splot` datafile; `splot`
 treats datablocks as the equivalent of function y-isolines.  No line will
 join points separated by a blank record.  If all datablocks contain the same
 number of points, `gnuplot` will draw cross-isolines between datablocks,
 connecting corresponding points.  This is termed "grid data", and is required
 for drawing a surface, for contouring (`set contour`) and hidden-line removal
 (`set hidden3d`). See also `splot grid_data`.
...
Standard error is redirected to a file splot.stderr in the current project directory.
6. iPlot

The iPlot project provides a pre-built application for interactive plotting of three types of functions.

Sample iPlot subdirectory page:

frodo - fc - iPlot

Home

Edit:

   p1.c,   p2.c,   p3.c,  

View:

The function types are:

  1. p1.c - functions of the form
      double func( double x)
    
    Multiple functions can be defined to display on one plot. The function names are specified in an array at the end of p1.c, for example:
      double (*f[])(double) = { f1, f2, 0};
    
  2. p2.c - parameterized functions of the form:
      typedef struct { double x, y; } Point;
    
      Point func( double t)
    
    Multiple functions can be defined to display on one plot. The function names are specified in an array at the end of p1.c, for example:
      Point (*f[])(double) = { f1, f2, 0};
    
  3. p3.c - two functions named f and fp in the forms:
      double f( double x)
      double fp( double x)
    
    where fp is the derivative of f. In this case the plot provides an option to use Newton's method to find a zero of the function f.

For all three types, function return values equal to HUGE_VAL are not plotted. This can be used to skip unwanted or undefined values.

Sample iPlot/p3.c run, including Newton:

Xmin: Xmax: Zoom: Shift: X-label: Y-label:
X-axis Y-axis Lines Points Title:
.html Xstart:
                        x                         f                        f'
                        1                        -1                         1
                        2                         3                         8
                    1.625               0.650390625                  4.671875
      1.48578595317725748     0.0724015895658800535       3.65110778962203897
      1.46595591973598927    0.00135173984490388754       3.51516843635499132
      1.46557137490709177   5.02401897417570353e-07       3.51255561502700653
      1.46557123187678773   6.92779167366097681e-14       3.51255464336095979
      1.46557123187676797  -1.11022302462515654e-16       3.51255464336082524

p3.c:
#include <math.h>
 
double f( double x)
{
  return -1 + x*x*( -1 + x);
}
 
double fp( double x)
{
  return x*(-2 + x*3);
}

iPlot has options to interactively regenerate the plot shifting left or right, or zooming in or out. X, Y, and Title labels for the plot can be specified, the axes can be enabled or disabled, and the plot style can be adjusted to use lines, points, or both. When using Newton's method, the button normally named "Save" (which saves the display in an html file) is renamed "NSave" to select rerunning Newton and saving.

The iPlot project directory configuration is different from the other projects. The user only has to create functions in C, not a complete program. The Makefile generates executables by linking with one of the object files compiled from iPlot.c, which includes a main program to generate the data for plotting. p1, p2, and p3, which would be compiled C executables in the other project directories, are all just symbolic links to an iPlot.sh shell script which runs the real executable to generate the plot and provides the interactive features.

The idea for iPlot started with a course assignment to create a rudimentary interactive plotting script, in VECR. To enable HTML output instead of the default plain text, VECR was modified to send a "Content-type: text/html" header when a particular project script (e.g. a9/p1.sh) was run. VECR itself originated to support a course assignment in Fall 2002 allowing one to "view", "edit", and "run", a single shell script generating HTML for an interactive directory/file browser.


7. HTML

As noted above regarding the background of iPlot, VECR has sometimes been modified to send a "Content-type: text/html" header when a particular project script was run. The HTML project directory is a generalization of that concept - the html header is sent whenever any program is run in the HTML project.

A program in the HTML project should generate valid HTML output. Forms can be used, posting back to the program itself or to another program. There are two form input names which can be used: args which is passed as command-line arguments; and data which is passed on standard input. Multiple instances of these inputs are concatenated together, and can be separated using hidden inputs.

The environment variable COURSE can be used to refer to the parent directory of the HTML project, as can be seen in this example HTML/p1.sh script:

read data1
rest=`cat`
echo "<html><head><title>test</title></head>
<body bgcolor=white text=black>
<form method=POST action=\"/prog/${COURSE}?HTML+p1.sh\">
arg1: <input name=args size=10 value=\"$1\">
<input type=hidden name=args value=\" \">
<br>arg2: <input name=args size=10 value=\"$2\">
<br><input type=submit name=data value=\"Button1\">
<input type=submit name=data value=\"Button2\">
<input type=hidden name=data value=\"&#10;\">
<br><textarea name=data rows=2 cols=20>
$rest
</textarea>
<br>data1 = $data1
</form></body></html>"
After running this script and filling in some data for the input fields, selecting Button1 produced the following example output:

arg1:
arg2:


data1 = Button1

iPlot.sh is another example using forms and HTML output.


8. SS

The SS project provides an interface to a spreadsheet application, including 2D and 3D plotting of spreadsheet output.

Sample SS subdirectory page:

frodo - fc - SS

Home

Edit:

   p1.ss,   p2.ss,   p3.ss,   p4.ss,  

View:

The provided spreadsheet application is documented separately and may be overridden by the users own spreadsheet program simply by replacing the SS and ss symbolic links.

The requirements for the spreadsheet application to work properly in the VECR/SS project are:

  1. The spreadsheet must read input from standard input.

  2. All output, including error messages, must go to standard output to avoid buffering issues with mixing standard output and standard error.

  3. Output such as debugging or diagnostic messages must be printed before the spreadsheet row/column array, and must contain no lines starting with a tab.

  4. The spreadsheet row/column output must start with a line starting with a tab followed by the column headings separated by tabs. Then, for each row, the output must start a new line starting with the row number followed by a tab followed by the cell values (or formulas or pointers) separated by tabs.

  5. For plotting, the output must consist of one or two (plot2d) or three (plot3d) columns of numbers, preceded by a line starting with a tab.

  6. The spreadsheet must accept the following commands:
      eval [args]           evaluate with optional arguments
      print values          display the cell values
      print formulas        display the cell formulas
      print pointers        display the cell formula pointers
      print formats         display the cell formats
      print symbols         display any symbols which have been defined
      plot2d range          display the specified range values directly
      plot3d range          display the specified range, one line per cell,
    			 in the form: row col value
    
Sample SS run:

: Display: Values Formulas Pointers Formats Symbols
: Lines Points
: .html
 
eval ; print symbols; print values;

  mean = avg(B1:B5) = 75.8
   A  B  C  D
0 grade score avg stdev
1 60.29 57.00 75.80 14.31
2 70.77 67.00
3 96.98 92.00
4 91.74 87.00
5 80.21 76.00

p1.ss:
a0:d0 = { "grade", "score", "avg", "stdev"};
mean = avg(b1:b5); c1 = mean; d1 = stdev(b1:b5);
a1 = 80+15*(b1-mean)/$d$1;
copy a2:a5 a1:a4;
b1:b5 = { 57, 67, 92, 87, 76 };

Sample SS run with 3D plot:

: Display: Values Formulas Pointers Formats Symbols
: Lines Points
: .html

Saved to p1.html

eval ; plot3d r1c1:r50c50;


p1.ss:
#define N 50
#define a 0.4
#define xRC(r,c) R ## r ## C ## c
#define RC(r,c) xRC(r,c)
M = ((N/2.0)-0.5);
RC(1,1):RC(N,N) = { (sin(a*(row()-M))/(row()-M)) *
                    (sin(a*(col()-M))/(col()-M)) };


9. Download

vecr.tar.gz contains the complete documentation and source code.