Project : ittpServer
I. Server
A. Execution of the Server
1) The Parameters
2) ServerThread and ThreadPool
B. Connections
1) Parser
2) Request
3) Response
4) Protocol
5) IttpException
II. RemoteControl
A. RMI
B. Interface
III. Test
IV. Contribution
GNU
Apache
We designed and
implemented a simplified Web server that communicates with clients via TCP
connections. This second project allows us to go deeper into the principle of
concurrent programming introduced in the first assignment. It illustrates the
theory of the network programming.
The first step to realise this server was to
establish the communication between a client and a server via a socket. Then we
added many clients. Therefore, we have developed the rest of the program
(parser for the request, creation of the response) taking care of the different
critical sections. This project has underlined trivial problems of
synchronisation (Shared variable, critical resources).
In a second time, we developed an interface
that allows the modification of the server‘s parameter. This application uses
the RMI protocol to communicate.
Server
This server contains the main feature to
deliver files through a network. The package ittp contains the server, a client
and a control application. The server process listens for incoming TCP
connections. Once accepted the server dedicates them their own thread until the
request is proceed and the response returned. The control program is a remote
application that manages the server. It function is to monitor and to parameter
the state of the server in real time. The connection to this control client uses
the Remote Method Invocation protocol.
A. Execution of the Server
The server program can be launched with the
fallowing options:
- The port listens by the SocketServer.
- The base directory where are store the
file that a client may request.
- The path to the error and output log file
where are save detailed information.
- Help that prints a synopsis of different
options
1)The Parameters
The Parameters class registers the
different options send to the program such as:
- the allowed method and headers
- the option : port number and base
directory
- the statistic counters: number of request,
connection, error and octet transferred
- the threshold for the timeout and number
of connection allowed
- the state of the server
2)ServerThread and ThreadPool
Once the parameters set up and
the ServerSocket opened, the server runs it own thread ServerThread. This later
listens for incoming connection in an endless loop. When a client solicits a
file, the server registers the request. If accepted by the ServerSocket, the
program starts a new thread and adds it to the thread group ThreadPool.
The ThreadPool and the ServerThread share
some variables (the Parameters fields and the standard output and error stream,
files). To ensure the mutual exclusion among the threads, public synchronised
accessors and mutators provide an access to these shared variables.
We do not know how the standard outputs
behave when multiple threads call them at the same time. In consequence, we
consider them as potentially critics. The method logInfo registered the
different errors and information from the client’s request. The message is
written into the stderr or the stdout stream and it is then copied into the log
file streams. We also verify that a file requested by a client is locked once
open. So that the file cannot be accessed from multiple threads or process
unless it has been unlocked.
We try to as much as possible
to limit the number share data. To reduce the possibility to share variable, we
limited their scope (if possible in private or in local) and to use static only
for the constant value.
B.Connections
When the ServerSocket accepts a connection,
a new object connect is created. This object is an instance of a private inner
class of Server that inherits from the Thread Java Foundation Class. The
constructor of this class receives the socket as argument. Once run, the connect
Thread checks every 250 ms if the socket input stream is ready. Therefore, a wait()
method and a counter define the period corresponding to the timeout. When the
connection is proceed, the counter is reset and the connected remain open until
a second timeout. If the user asks for a second request, this one will be
proceed within the same connection.
int timeout = 10; // [second] int frequency = 4; // [hz] do { int counter = 0; while (!in.ready () && (!broken)) { sleep (1000/frequence); if (++ counter > (timeout * frequency)) broken = true; } if (!broken) { Response response = new Response (); RequestParser p = new RequestParser (...); Request request = p.parse (); request.process (response); send (response); } } while (!broken);
1) Parser
The input received from the socket is a text-based
stream. We use the class Parser to decode this stream and identify the
component. The Parsing with java (Ref. 1) document inspired the design used to
build this class. The parser checks only the grammar but not the correctness of
the input. This task was delegate to the Request class. The parser stops to
read the input when the argument passed does not match the syntax or when it meets
two consecutive new lines. If extra data are present after the two new lines,
they will be proceeding in a further request. The parser is tolerant to extra
space or tabulation character in the request.
2)Request
When the parser identifies a method, it instantiates
the request class. This abstract class delegates the implementation of the method
process() to its sub-class (Get, Head, Option or Trace). This method is the turning
point of the program. In this place, the request is interpreted and the
response elaborated.
We choose this architecture to make the
program easily extendable. This design was inspired from the textbook Object-Oriented
Software Development Using Java (Ref. 1).
If present, the values of the scheme, the
port number or the host are compared to the real ones. If they do not match or
if the request is older than 10 minutes (Date headers), a 404 File not found
error is returned.
The Request class also implements the inner
abstract class headers.
The headerlist registers the information about the request headers. The key of this HashMap is a constant string and the value associated is the object’s Headers.
|
|
This design uniforms the way to access to
the headers and masks the machinery of the code. The parser sets up the headers
when these ones are encounter. Before to pick up the value, the method (get,
trace…) tests if the header isUsed().
The Parser ends its task when the
different values are store (and checked) in the request object. If and only if
no errors are present, the request can be proceed. Therefore, a new object response
is created.
3) Response
The response class wraps the message that
is returned to the client. It design is close to the one of the Request. A HashMap
registered the list of Headers. This inner class contains two abstract method setUsed()
and setAllowed() that are setup when the request is proceed. The inner class Body
stores the file that the client may request. The Body also calculates the
lengths and the md5 key.
The inner class Code provides a set of
methods and constant related to the error (or success) code enclosed within the
headers. The two methods toString() and toStream() returned the formatted
response ready to be send through the socket. The ByteArrayInputStream and SequenceInputStream
JFC have been used to convert the mixed text and byte array to data steam.
4) Protocol
Both Request and Response extends the class
Protocol. This class registers the common information such as the version of
the protocol and the format of the date.
5)IttpException
When an error occurs in the program, this
class is invoked to carry out the message to the Connect class (the class
extending the thread JFC that proceeds the socket information). When this
exception is catch, the request containing the appropriate response error code is
immediately send back to the client and the connection closed.
The constructor of this Class requires two
arguments: the detailed message of the error saved on the error log file and
the response code. This class extends the RuntimeException class.
I. RemoteControl
The class Parameters that holds the
different information related to the server implements the interface RemoteControl.
This one extends the Remote interface. The parameters could now be control from
a remote client thanks to the RMI protocol.
A. RMI
This protocol allows invoking method from a
remote host. In our case, the methods we wish to access are the ones that
control the server. To implement this protocol, we use the program rmic.exe
that generates the stubs from the server and the control. Once the correct
security policy setup, the control client can access to the method on
parameters class. This remote object behaves as if it is a local object. The
documentation of the java shows a useful tutorial to implement this kind of connection
(ref. 2). All the accesses to the interface remoteControl are synchronized: we
had to prevent their access from multiple threads at the same time.
B. Interface
The control client uses the Swing JFC to
construct the window. This offers a high graphical quality for the component
and an easiness to use. The GUI’s structure (Figure XXX) is based on two dialogs.
The main dialog let the user choose what
action he wants to do on the server (start/stop, change the timeout, the number
of connections, the method or headers allowed).
The statistic dialog offers information
about the state of the server (number of request, connection errors, size of
the data transferred)
These values are updated in real time
(every 100 ms). Therefore, the main panels implement the Runnable interface.
II.Test
Before executing a request, the system does
a series of test. Therefore, we have determined several constraints to validate
the pre-execution of a command (Table 2.3). If the request is not valid, an ittpException is thrown. If correct, the
corresponding method in the Request class is proceeding.
The last important part of this project has
been to test and search errors in the program. Therefore, we realised a test
classes to verify the correctness of the error and the response from the server
to critical error. We have used the Junit application to generate the prototype
different classes of test. We have evaluated the different possibility of
malfunction that may happen. The results obtained (appendix XXX) has spotted
some minor failures (generally nullPointerException). In addition, we have test
different parameter when the user executes the program. The unexpected
exceptions and errors obtained have been correct and no more known bug
remained.
The test program has been enclosed to the
program and can be execute by the statement:
java -classpath "man1.jar;Path_to_junit.jar"
ittp.test.ParserSuite.
III. Contribution
GNU
The class LongOpt and GetOpt imported in
our program belong to the library GNU (available on some Linux distribution
e.g. Mandrake 9.2). It is original from c++ library getopt.h. This package
process the different options sent by the user. The method getopt () returns
them in a friendly way. A switch statement proceeds the different parameters.
The command line options to be passed in the traditional Unix manner. That is,
proceeded by a '-' character for short option and '--' for the long option.
gnu\getopt\Getopt.java
gnu\getopt\LongOpt.java
Apache
We have imported in this
program too, some contribution from the apache projects. Especially, we used
two tools they provides in their library to encode and decode a base 64
representation object into a string. This method was used to return the md5
encrypted digest headers. The second package used from this project is a
function that copies an inputStreanm into an outputStream.
org\apache\commons\io\CopyUtils.java
org\apache\soap\encoding\soapenc\Base64.java
We copied the licence the sources to use
these library in their respective directory enclosed in the ittpServer archive.
Conclusion
We tried to solve a problem of shared file
on the network in a simple but efficient way. The designs we choose make the
system easy to extend or to reuse. To implement a new header or a new method on
the server, a developer need just to insert a class on the corresponding
package.
However, this server is a good point to
apply theory but it could not be use in practice. The level of security is low.
We should authenticate the client (or at less add a signature to the request) and
insert a protection to the data (may be encode them).
Another improvement could be to not read
the entire file (needed to calculate the digest message) even if we do not need
to send it. A possibility of improvement will be to open the file, calculate
the MD5’s key from a buffer, and close the file before to answer the request.
Appendix
User manual
The ITTP Server contains several separate
programs that have to be executed in different terminals. All the commands that
follow are executed in the directory ITTPserver:
In a first time, you have to execute
rmiregistry (in bin directory of j2sdk). this allows using the RMI application present
in the program.
the server can be executed with this
command:
%java -classpath . -Djava.security.policy=home\
ITTPserver \ittp.policy -Djava.rmi.server.codebase=file:///home/ITTPserver/ ittp.Server {options}*
The options that can be used
are:
-p or
--port
The contains
the value used by the server. This option allows modifying the number of the
port used by the server to communicate with the client. The default value for
the port is 36000.
-b or --base_dir
The
contains the directory where the client can request a resource. This option
allows modifying the directory where the client can request one resource. The
default value for the base directory is user.dir.
-l or --ErrLog
The
contains the name of the file where the errors are stored. This option allows
modifying the name of the file where errors are stored. The default name for
this file is logErr.log.
-i or --InfoLog
The
contains the name of the file where different information of the server is
stored. This option allows modifying the name of the file where the different
information about the server is stored. The default name for this file is logInfo.log.
-h or
--help
This option prints a
synopsis of standard option previous described.
You can execute more than one option in the
same time. In addition, the order of the option in the command has no
importance in the execution of the server.
Also if you want, you can use the Control
Application to manage the server. In this case You must executed in a third
terminal the following command:
%java -classpath . -Djava.security.policy=home\ITTPserver\ittp.policy ittp.Control
A new window appears and you can modify
several parameters of the server in real time or obtains some statistical
information about the operating server.
Ant Support
If you have the software “ant” (jakarta.apache.org/ant),
you can use the file build.xml. You can run ant it with
- one of these target (all is default target):
- ant prepare: create the needed
directories
- ant realese: compile the java classes
- ant rmic: buil the stub for the server
and the client
- ant jar: create the jar archive
- ant javadoc: create the javadoc
- ant all: create jar and javadoc
- ant clean: clean everything
Download javadoc software (jar)
|