SDSU CS 596 Client-Server Programming
Parsing and State machines

[To Lecture Notes Index]
San Diego State University -- This page last updated February 22, 1996

Contents of TITLE Lecture

  1. Parsing and State machines
    1. SPOP
    2. Sample session
    3. SPOP features
  2. Lexical Analysis
  3. Parsing
      1. Simple Parsing Problems
    1. Finite Automata
    2. Implementing a state machine: switch
      1. Switch method analysis
    3. Implementing a state machine: table
      1. State table (continued)
      2. State table: Alternate version
      3. Naming the states
    4. Implementing a state machine: the OO way
      1. State machine: OO way (continued)
      2. OO way: the base class SPOPState
      3. OO way: the NoAuth state class
      4. OO way: the HaveUser state class
      5. OO way: things not shown in example

Parsing and State machines


CS courses that are very useful:


The problem: Protocols need to be parsed by both the client and the server.


SPOP


Example protocol:
Simple Post Office Protocol (SPOP)

Command have the same functionality as POP but are limited to the following:


Sample session


moria% telnet rohan 110
Trying 130.191.143.100...
Connected to rohan.sdsu.edu.
Escape character is '^]'.
+OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at rohan starting.
USER turtle
+OK Password required for turtle.
PASS *******
+OK turtle has 1 message(s) (354 octets).
LIST
+OK 1 messages (354 octets)
.
QUIT
+OK Pop server at rohan signing off.
Connection closed by foreign host.
moria%


SPOP features


The authentication consists of two commands which have to come in sequence:


The other commands (except for QUIT) cannot be executed before the user has been authenticated.


What does this mean for the client and server?



Lexical Analysis


The first step in parsing a protocol is to extract the commands from the input stream.

Since POP (and therefore SPOP) is a line oriented protocol, the logical steps to get commands is:



In Java we can use readLine() to get a line of text and a StringTokenizer to break the line into tokens.

Why not use ASCIIInputStream.readWord()?


Parsing


Simple approach: (Excuse my pseudo code here...)

start:
get command
if  command is "USER" then
  username = argument
  get command
  if  command is "PASS" then
    password = argument
    if valid(username,password) then
      while true
        get command
        if command is "LIST" then
          performLIST
        elsif command is "RETR" then
          performRETR(argument)
        elsif command is "QUIT" then
          return
        end if
      end while
    end if
  end if
end if


Simple Parsing Problems


Major problems with this algorithm:


Also note that this is implemented in terms of functions. No OOP was used.


Finite Automata


A better way of looking at all of this is using a picture.







[ Silence while Andrew draws a weird picture ]


Implementing a state machine: switch

int state = 0;
while (true)
{
	command = next command;
	switch (state)
	{
		case 0:
			if (command.equals("USER"))
			{
				username = argument;
				state = 1;
			}
			else if (command.equals("QUIT"))
				state = 4;
			else
				error("Unknown: " + command);
			break;
		case 1:
			if (command.equals("PASS"))
			{
				if (valid(username, argument))
					state = 2;
				else
				{
					error("Unauthorized");
					state = 3;
				}
			}
			else
				error("Unknown: " + command);
			break;
...

Switch method analysis


Major problems with this algorithm:



Advantages:


Implementing a state machine: table

01234
USER13344
PASS32344
LIST33244
RETR33244
QUIT44444


Usable? Not really, we need actions associated with state transitions. Problem here is that Java doesn't have function pointers.

Also the PASS command can succeed or fail.

There is also lots of redundency in the table.


State table (continued)


We can fix the problem with the two outcomes of the PASS command by making each outcome its own command:

01234
USER13344
PASSvalid32344
PASSbogus33344
LIST33244
RETR33244
QUIT44444


Also, actions could be objects that implement a certain SPOP state interface.


State table: Alternate version


In C/C++ we can define the following:

struct
{
	int		currentState;
	char		*command;
	int		stateIfSucceed;
	int		stateIfFailed;
	int		(*action)(char **);
} actionTable[] =
{
	{0, "USER", 1, 3, actionUser},
	{0, "QUIT", 4, 4, actionQuit},
	{1, "PASS", 2, 3, actionPass},
	{1, "QUIT", 4, 4, actionQuit},
	{2, "LIST", 2, 2, actionList},
	{2, "RETR", 2, 2, actionList},
	{2, "QUIT", 4, 4, actionList},
	{0, 0, 0, 0, 0}
};


Advantages:


Naming the states


We will use the following names for the states:

0NoAuth
1HaveUser
2Process
3Invalid
4Quit



Implementing a state machine: the OO way


The idea here is to make each state an object.

A state object can then be called upon to process a request and return the new state.

There should be only one object for each state for efficiency reasons.

This is done by declaring a static member of each state class to contain an object of that class.

Example:

public class SingleObjClass
{
	private static SingleObjClass obj =
              new SingleObjClass();
	private SingleObjClass()
	{
	}
	public static SingleObjClass getInstance()
	{
		return obj;
	}
}

State machine: OO way (continued)


Two ways to proceed from here:


We'll use the second method in an example.


OO way: the base class SPOPState


public class SPOPState
{
	public SPOPState USER(String args[])
	{
		return Invalid.getInstance();
	}

	public SPOPState PASS(String args[])
	{
		return Invalid.getInstance();
	}

	public SPOPState LIST(String args[])
	{
		return Invalid.getInstance();
	}

	public SPOPState RETR(String args[])
	{
		return Invalid.getInstance();
	}

	public SPOPState QUIT(String args[])
	{
		return Quit.getInstance();
	}
}

OO way: the NoAuth state class


public class NoAuth extends SPOPState
{
	private static NoAuth obj = new NoAuth();
	private SPOPInitial()
	{
	}

	public static NoAuth getInstance()
	{
		return obj;
	}

	public SPOPState USER(String args[])
	{
		Validator.setUsername(args[0]);
		return HaveUser.getInstance();
	}
}

OO way: the HaveUser state class


public class HaveUser extends SPOPState
{
	private static HaveUser obj =
						new HaveUser();
	private SPOPInitial()
	{
	}

	public static HaveUser getInstance()
	{
		return obj;
	}

	public SPOPState PASS(String args[])
	{
		if (Validator.valid(args[0]))
		{
			return Process.getInstance();
		}
		else
		{
			return Invalid.getInstance();
		}
	}
}

OO way: things not shown in example


The previous example was meant to show the structure, it is by no means complete.

Things missing:


Other Issues: