net.vattp.data
Class StartUpProtocol

java.lang.Object
  |
  +--net.vattp.data.StartUpProtocol
All Implemented Interfaces:
MsgHandler

public class StartUpProtocol
extends Object
implements MsgHandler

Untamed:


Field Summary
private static String[] errTokNames
           
private static BigInteger g
           
private  Vector hisMessagesToSign
          Messages I've received whose signature is to be checked as part of end point identification.
private static BigInteger modulus
           
private  DataPath myDataPath
          The DataPath object we are working with.
private  String myEMsgProtocolVersion
          The agreed E message protocol version
private  PublicKey myHisPublicKey
          The public key of the remote end
private  KeyPair myIdentityKeys
           
private  boolean myIsIncoming
          Whether we are build for initiating an outbound connection or responding to a remote connection
private  String myLocalFlattenedSearchPath
          The semicolon separated search path for this vat
private  String myLocalVatID
          The vatID of this vat
private  Vector myMessagesToSign
          Messages I've sent which are to be signed for as part of end point authentication.
private  byte[] myOutgoingSuspendID
          The suspend ID to present to the other end for a reconnect.
private  String myProtocolSuite
          The agreed upon protocol suite
private  String myRemoteVatID
          The remote vatID we are communicating with
private  Signature mySignature
          The Signature object used for signing and checking signatures
private  int myState
          Current state of the startup protocol state machine
private  boolean myStop
          Set true if we should stop attempting to make a connection before outgoingSetup has been called.
private  VatLocationLookup myVLS
          Entity from which to lookup foreign vatIDs
(package private) static String PROTO_3DES_SDH_M
           
(package private) static String PROTO_3DES_SDH_M2
           
(package private) static String PROTO_NONE
           
private static int ST_DEAD
           
(package private) static int ST_EXPECT_MESSAGE
           
private static int ST_INCOMING_EXPECT_GIVEINFO
           
(package private) static int ST_INCOMING_EXPECT_GO
           
private static int ST_INCOMING_EXPECT_IWANT
           
(package private) static int ST_OUTGOING_EXPECT_GOTOO
           
private static int ST_OUTGOING_EXPECT_IAM
           
private static int ST_OUTGOING_EXPECT_REPLYINFO
           
private static int ST_TRY_NEXT
           
private static int ST_UNSTARTED
           
private static String TheAuthProtocols
          The protocol negotiation string we send, least desired last
private static String[] TheAuthProtocolTable
          The authentication protocols we support.
private static byte TOK_BYE
           
private static byte TOK_DUP
           
private static byte TOK_ERR_INTERNAL
           
private static byte TOK_ERR_PROTOCOL
           
private static byte TOK_ERR_WRONG_ID
           
private static byte TOK_GIVEINFO
           
private static byte TOK_GO
           
private static byte TOK_GOTOO
           
private static byte TOK_IAM
           
private static byte TOK_IWANT
           
private static byte TOK_NOT_ME
           
private static byte TOK_REPLYINFO
           
private static byte TOK_RESUME
           
private static byte TOK_TRY
           
private static byte TOK_YOUCHOSE
           
private static String[] tokNames
           
private  BigInteger x
           
 
Constructor Summary
(package private) StartUpProtocol(DataPath path, boolean isIncoming, String remoteVatID, KeyPair identityKeys, String localVatID, byte[] outgoingSuspendID, String localFlattenedSearchPath, VatLocationLookup vls)
          Make a StartUpProtocol object.
 
Method Summary
static String[] authProtocolTable()
          Enabled:
private  void checkProtocolVersion(DataInputStream packetIn, byte[] packet)
          Respond to the initator's Msg.PROTOCOL_VERSION message.
 void connectionDead(VatTPConnection willBeNull, Throwable reason)
          Enabled: Process a connection failure
private  byte[] firstDH()
          Perform the first calculation in Diffie Hellman key exchange.
private  String formatStartupPacket(byte[] packet)
          Format a Msg.STARTUP packet for error messages.
(package private)  int getState()
          Return the connection startup state
private  void handleStateIncomingExpectGIVEINFO(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting an GIVEINFO -or- DUP message.
private  void handleStateIncomingExpectGO(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting a GO -or- RESUME -or- QUIT message.
private  void handleStateIncomingExpectIWANT(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting a IWANT message.
private  void handleStateOutgoingExpectGOTOO(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting a GOTOO -or- BYE message.
private  void handleStateOutgoingExpectIAM(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting an IAM -or- TRY -or- NOTME -or- DUP message.
private  void handleStateOutgoingExpectREPLYINFO(byte token, DataInputStream packetIn, byte[] packet)
          Process expecting a REPLYINFO -or- YOUCHOSE -or- DUP message.
private  boolean isHisPublicKeyOK(String vatID, byte[] hisKey, int token)
          Decode the line form of his public key and check that it is for his vatID.
private  boolean isSecondDHOK(byte[] publicdh, byte[] sig, byte token)
          Perform the second calculation in Diffie Hellman key exchange.
private  boolean isSigGood(byte[] data, byte[] sig, byte token)
          Check the signature on the data received.
private  String matchProtocols(String protocol)
          Match a suggested authorization protocol with the ones we support.
private  byte[] md5Hash(int pad, byte[] data, MessageDigest md5)
          Calculate the MD5 hash of some data with a specific padding.
 void processMessage(byte[] packetArray, VatTPConnection willBeNull)
          Enabled: Process the next packet of the connection startup protocol.
private  void processProtocolAccepted(DataInputStream packetIn, byte[] packet)
          Handle the Msg.PROTOCOL_ACCEPTED message.
private  void sendErrProtocol(String msg)
          Send a TOK_ERR_PROTOCOL packet
private  void sendGiveInfo()
          Send a TOK_GIVEINFO packet
private  void sendGo(String protocol)
          Send a TOK_GO packet
private  void sendGo(String protocol, byte[] dhparm, byte[] sig)
          Send a TOK_GO packet
private  void sendGoToo(String protocol)
          Send a TOK_GOTOO packet.
private  void sendGoToo(String protocol, byte[] dhparm, byte[] sig)
          Send a TOK_GOTOO packet
private  void sendIAm()
          Send a TOK_IAM packet
private  void sendIWant()
          Send a TOK_IWANT packet
private  void sendMessageForSignature(byte[] message)
          Send a message to the other end and save the message for signature calculation.
private  void sendReplyInfo()
          Send a TOK_REPLYINFO packet
private  void sendResume()
          Send a TOK_RESUME packet
private  void sendTry(String location)
          Send a TOK_TRY packet
private  void sendYouChose()
          Send a TOK_YOUCHOSE packet
private  byte[] signSent(byte[] data, byte token)
          Return a our signature on the data sent.
private  void startupError(byte errorToken, String msg)
          Terminate the connection setup protocol with an error that will get passed to the remote end too.
private  void startupError(byte errorToken, String msg, Throwable t)
          Terminate the connection setup protocol with an error that will get passed to the remote end too.
private  void startupLocalError(String msg)
          Terminate the connection setup protocol with an error.
private  void startupSuccessful()
          Startup protocol has succeeded, let the messages flow.
(package private)  void stopStartUpProtocol()
          Stop the start up protocol.
private  byte[] subbytearray(byte[] bytes, int offset, int len)
          Return a subarray of a given array.
private static String tokName(int tok)
          Translate a startup protocol message token to a printable string for error messages and the like.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

ST_UNSTARTED

private static final int ST_UNSTARTED

ST_INCOMING_EXPECT_IWANT

private static final int ST_INCOMING_EXPECT_IWANT

ST_OUTGOING_EXPECT_IAM

private static final int ST_OUTGOING_EXPECT_IAM

ST_INCOMING_EXPECT_GIVEINFO

private static final int ST_INCOMING_EXPECT_GIVEINFO

ST_OUTGOING_EXPECT_REPLYINFO

private static final int ST_OUTGOING_EXPECT_REPLYINFO

ST_INCOMING_EXPECT_GO

static final int ST_INCOMING_EXPECT_GO

ST_OUTGOING_EXPECT_GOTOO

static final int ST_OUTGOING_EXPECT_GOTOO

ST_EXPECT_MESSAGE

static final int ST_EXPECT_MESSAGE

ST_DEAD

private static final int ST_DEAD

ST_TRY_NEXT

private static final int ST_TRY_NEXT

TOK_BYE

private static final byte TOK_BYE

TOK_DUP

private static final byte TOK_DUP

TOK_GIVEINFO

private static final byte TOK_GIVEINFO

TOK_GO

private static final byte TOK_GO

TOK_GOTOO

private static final byte TOK_GOTOO

TOK_IAM

private static final byte TOK_IAM

TOK_IWANT

private static final byte TOK_IWANT

TOK_NOT_ME

private static final byte TOK_NOT_ME

TOK_REPLYINFO

private static final byte TOK_REPLYINFO

TOK_TRY

private static final byte TOK_TRY

TOK_RESUME

private static final byte TOK_RESUME

TOK_YOUCHOSE

private static final byte TOK_YOUCHOSE

TOK_ERR_PROTOCOL

private static final byte TOK_ERR_PROTOCOL

TOK_ERR_WRONG_ID

private static final byte TOK_ERR_WRONG_ID

TOK_ERR_INTERNAL

private static final byte TOK_ERR_INTERNAL

PROTO_NONE

static final String PROTO_NONE

PROTO_3DES_SDH_M

static final String PROTO_3DES_SDH_M

PROTO_3DES_SDH_M2

static final String PROTO_3DES_SDH_M2

TheAuthProtocols

private static String TheAuthProtocols
The protocol negotiation string we send, least desired last


TheAuthProtocolTable

private static String[] TheAuthProtocolTable
The authentication protocols we support. Excludes none which is a special case


tokNames

private static final String[] tokNames

errTokNames

private static final String[] errTokNames

myDataPath

private final DataPath myDataPath
The DataPath object we are working with.


myIsIncoming

private final boolean myIsIncoming
Whether we are build for initiating an outbound connection or responding to a remote connection


myRemoteVatID

private String myRemoteVatID
The remote vatID we are communicating with


myOutgoingSuspendID

private byte[] myOutgoingSuspendID
The suspend ID to present to the other end for a reconnect. If it is null, reconnection will not be attempted. (Outbound connections only)


myHisPublicKey

private PublicKey myHisPublicKey
The public key of the remote end


myIdentityKeys

private final KeyPair myIdentityKeys

myVLS

private final VatLocationLookup myVLS
Entity from which to lookup foreign vatIDs


myLocalVatID

private final String myLocalVatID
The vatID of this vat


myLocalFlattenedSearchPath

private final String myLocalFlattenedSearchPath
The semicolon separated search path for this vat


myState

private int myState
Current state of the startup protocol state machine


myStop

private boolean myStop
Set true if we should stop attempting to make a connection before outgoingSetup has been called.


myEMsgProtocolVersion

private String myEMsgProtocolVersion
The agreed E message protocol version


myProtocolSuite

private String myProtocolSuite
The agreed upon protocol suite


mySignature

private Signature mySignature
The Signature object used for signing and checking signatures


myMessagesToSign

private final Vector myMessagesToSign
Messages I've sent which are to be signed for as part of end point authentication.


hisMessagesToSign

private final Vector hisMessagesToSign
Messages I've received whose signature is to be checked as part of end point identification.


x

private BigInteger x

g

private static final BigInteger g

modulus

private static final BigInteger modulus
Constructor Detail

StartUpProtocol

StartUpProtocol(DataPath path,
                boolean isIncoming,
                String remoteVatID,
                KeyPair identityKeys,
                String localVatID,
                byte[] outgoingSuspendID,
                String localFlattenedSearchPath,
                VatLocationLookup vls)
Make a StartUpProtocol object.

Parameters:
path - the DataPath this StartUpProtocol is to serve.
isIncoming - true if this StartUpProtocol is to work with an incoming connection. False if this end is the initator.
remoteVatID - if isIncoming, then null, othersize the VatID for the remote vat.
identityKeys - the KeyPair which defines the identity of this vat.
localVatID - The vatID of the local vat.
outgoingSuspendID - The ID to resume a suspended connection if this DataPath is outgoing and is to resume a suspended connection. Otherwise null
localFlattenedSearchPath - the search path we publish for others looking for the local vat in semicolon separated form.
Method Detail

authProtocolTable

public static String[] authProtocolTable()
Enabled:


checkProtocolVersion

private void checkProtocolVersion(DataInputStream packetIn,
                                  byte[] packet)
                           throws IOException
Respond to the initator's Msg.PROTOCOL_VERSION message. Selects the last version sent by the remote end in their PROTOCOL_VERSION packet which is also supported by this end, as the protocol version to use on this connection. That version is returned in a PROTOCOL_ACCEPTED message.

Parameters:
packetIn - The PROTOCOL_VERSION packet stream postioned after the type byte.
Throws:
java.io.IOException - When there is no protocol in common with the remote end. An ERR_PROTOCOL message is sent to the remote end.

connectionDead

public void connectionDead(VatTPConnection willBeNull,
                           Throwable reason)
Enabled: Process a connection failure

Specified by:
connectionDead in interface MsgHandler
Parameters:
willBeNull - The VatTPConnection object which has just died.
reason - is a Throwable which describes why the connection died.

firstDH

private byte[] firstDH()
Perform the first calculation in Diffie Hellman key exchange.

This method gets a random x and calculate g**x mod p. Return the value as a String base 10.

Returns:
A byte array representing the result of the first Diffie Hellman calculation.

formatStartupPacket

private String formatStartupPacket(byte[] packet)
Format a Msg.STARTUP packet for error messages.

Parameters:
packet - the byte array which is the complete packet.
Returns:
the packet formated as a string.

getState

int getState()
Return the connection startup state

Returns:
The connection startup state code for debugging purposes.

handleStateIncomingExpectGIVEINFO

private void handleStateIncomingExpectGIVEINFO(byte token,
                                               DataInputStream packetIn,
                                               byte[] packet)
                                        throws IOException
Process expecting an GIVEINFO -or- DUP message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
ConnectionStartupLocalException - is thrown if this MsgConnection should terminate without notifing the other end.
IOException

handleStateIncomingExpectGO

private void handleStateIncomingExpectGO(byte token,
                                         DataInputStream packetIn,
                                         byte[] packet)
                                  throws IOException
Process expecting a GO -or- RESUME -or- QUIT message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
ConnectionStartupLocalException - is thrown if this MsgConnection should terminate without notifing the other end.
IOException

handleStateIncomingExpectIWANT

private void handleStateIncomingExpectIWANT(byte token,
                                            DataInputStream packetIn,
                                            byte[] packet)
                                     throws IOException
Process expecting a IWANT message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
IOException

handleStateOutgoingExpectGOTOO

private void handleStateOutgoingExpectGOTOO(byte token,
                                            DataInputStream packetIn,
                                            byte[] packet)
                                     throws IOException
Process expecting a GOTOO -or- BYE message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
ConnectionStartupLocalException - is thrown if this MsgConnection should terminate without notifing the other end.
IOException

handleStateOutgoingExpectIAM

private void handleStateOutgoingExpectIAM(byte token,
                                          DataInputStream packetIn,
                                          byte[] packet)
                                   throws IOException
Process expecting an IAM -or- TRY -or- NOTME -or- DUP message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
ConnectionStartupLocalException - is thrown if this MsgConnection should terminate without notifing the other end.
IOException

handleStateOutgoingExpectREPLYINFO

private void handleStateOutgoingExpectREPLYINFO(byte token,
                                                DataInputStream packetIn,
                                                byte[] packet)
                                         throws IOException
Process expecting a REPLYINFO -or- YOUCHOSE -or- DUP message.

Parameters:
token - the actual message token received.
packetIn - is the DataInputStream on the input message positioned after the startup protocol token.
packet - The entire message received as a string for error messages.
Throws:
ConnectionStartupException - is thrown if this MsgConnection should terminate.
ConnectionStartupLocalException - is thrown if this MsgConnection should terminate without notifing the other end.
IOException

isHisPublicKeyOK

private boolean isHisPublicKeyOK(String vatID,
                                 byte[] hisKey,
                                 int token)
                          throws IOException
Decode the line form of his public key and check that it is for his vatID.

Parameters:
vatID - His vatID.
hisKey - His DSA public key expressed as a byte array.
Returns:
is true if his public key matches is vatID, false otherwise.
Throws:
ConnectionStartupException - If hisKey has a bad format, or is invalid.
IOException

isSecondDHOK

private boolean isSecondDHOK(byte[] publicdh,
                             byte[] sig,
                             byte token)
                      throws IOException
Perform the second calculation in Diffie Hellman key exchange.

This method takes the remote end's g**y mod p, and the sitnature on it. It checks ths signature and performs the second Diffie Hellman calculation as (g**y mod p) ** x mod p.

It then takes the resulting dh secret and calculates values for the initial sequence numbers (both send path and receive path).

Parameters:
publicdh - is a byte array containing the far end's first Diffie Hellman calculation.
sig - is a byte array containing the far end's DSS signature on the startup protocol.
token - The startup protocol token being processed. (For determining whether we are the initator or receipent and error reporting.)
Returns:
is true if the connection attempt should continue, false otherwise.
IOException

isSigGood

private boolean isSigGood(byte[] data,
                          byte[] sig,
                          byte token)
                   throws IOException
Check the signature on the data received.

Parameters:
data - is the data to check.
sig - is the signature.
token - is the startup protocol token being processed for error reporting.
Returns:
is true if the signature is good. False for a bunch of "can't occur" situations, and things like invalid or no public key from the other end, or invalid signature.
IOException

matchProtocols

private String matchProtocols(String protocol)
Match a suggested authorization protocol with the ones we support. The comparison ignores the case of the letters.

Parameters:
protocol - the one to match.
Returns:
the standard cased version of the matched name or null if no match.

md5Hash

private byte[] md5Hash(int pad,
                       byte[] data,
                       MessageDigest md5)
Calculate the MD5 hash of some data with a specific padding.

The padding allows different values to be obtained from the same data by varing the padding value. We use it to get the different authentication values from the same Diffie Hellman shared secret.

Parameters:
pad - The int (treated as a byte) to be used to pad the MD5 calculation.
data - The data to be hashed.
md5 - The message digest object to be used.
Returns:
A byte array representing the hash.

processMessage

public void processMessage(byte[] packetArray,
                           VatTPConnection willBeNull)
Enabled: Process the next packet of the connection startup protocol.

Specified by:
processMessage in interface MsgHandler
Parameters:
packetArray - The startup protocol message to process.
willBeNull - is the VatTPConnection object on which the the message arrived.
See Also:
Msg, VatTPConnection

processProtocolAccepted

private void processProtocolAccepted(DataInputStream packetIn,
                                     byte[] packet)
                              throws IOException
Handle the Msg.PROTOCOL_ACCEPTED message. Determine which version of the protocol was accepted and configure this end to use that version.

Parameters:
packet - the packet received.
IOException

sendErrProtocol

private void sendErrProtocol(String msg)
                      throws IOException
Send a TOK_ERR_PROTOCOL packet

Parameters:
msg - is a message describing the error.
Throws:
IOException - is thrown if there is a problem on the send.

sendGiveInfo

private void sendGiveInfo()
                   throws IOException
Send a TOK_GIVEINFO packet

Throws:
IOException - is thrown if there is a problem on the send.

sendGo

private void sendGo(String protocol)
             throws IOException
Send a TOK_GO packet

Parameters:
protocol - is the chosen authorization protocol as a String.
Throws:
IOException - is thrown if there is a problem on the send.

sendGo

private void sendGo(String protocol,
                    byte[] dhparm,
                    byte[] sig)
             throws IOException
Send a TOK_GO packet

Parameters:
protocol - is the chosen authorization protocol as a String.
dhparm - is the public Diffie Hellman parameter
sig - is the signature for authentication.
Throws:
IOException - is thrown if there is a problem on the send.

sendGoToo

private void sendGoToo(String protocol)
                throws IOException
Send a TOK_GOTOO packet.

Parameters:
protocol - is the chosen authorization protocol as a String or null. If null is specified, nothing will be sent in that place.
Throws:
IOException - is thrown if there is a problem on the send.

sendGoToo

private void sendGoToo(String protocol,
                       byte[] dhparm,
                       byte[] sig)
                throws IOException
Send a TOK_GOTOO packet

Parameters:
protocol - is the chosen authorization protocol as a String.
dhparm - is the public Diffie Hellman parameter
sig - is the signature for authentication.
Throws:
IOException - is thrown if there is a problem on the send.

sendIAm

private void sendIAm()
              throws IOException
Send a TOK_IAM packet

Throws:
IOException - is thrown if there is a problem on the send.

sendIWant

private void sendIWant()
                throws IOException
Send a TOK_IWANT packet

Throws:
IOException - is thrown if there is a problem on the send.

sendMessageForSignature

private void sendMessageForSignature(byte[] message)
Send a message to the other end and save the message for signature calculation.

Parameters:
message - is the message to send.

sendReplyInfo

private void sendReplyInfo()
                    throws IOException
Send a TOK_REPLYINFO packet

Throws:
IOException - is thrown if there is a problem on the send.

sendResume

private void sendResume()
                 throws IOException
Send a TOK_RESUME packet

Throws:
IOException - is thrown if there is a problem on the send.

sendTry

private void sendTry(String location)
              throws IOException
Send a TOK_TRY packet

Throws:
IOException - is thrown if there is a problem on the send.

sendYouChose

private void sendYouChose()
                   throws IOException
Send a TOK_YOUCHOSE packet

Throws:
IOException - is thrown if there is a problem on the send.

signSent

private byte[] signSent(byte[] data,
                        byte token)
                 throws IOException
Return a our signature on the data sent.

Parameters:
data - The additional data to sign.
token - The startup protocol token being processed for error reporting.
Returns:
The DSS signature on the data as a byte array.
Throws:
ConnectionStartupException - For a bunch of "can't occur" situations.
IOException

startupError

private void startupError(byte errorToken,
                          String msg)
                   throws IOException
Terminate the connection setup protocol with an error that will get passed to the remote end too.

Parameters:
errorToken - The error token to be passed to the remote end
msg - A message string describing the error.
IOException

startupError

private void startupError(byte errorToken,
                          String msg,
                          Throwable t)
                   throws IOException
Terminate the connection setup protocol with an error that will get passed to the remote end too.

Parameters:
errorToken - The error token to be passed to the remote end
msg - A message string describing the error.
t - A throwable associated with the error.
IOException

startupLocalError

private void startupLocalError(String msg)
Terminate the connection setup protocol with an error.


startupSuccessful

private void startupSuccessful()
                        throws IOException
Startup protocol has succeeded, let the messages flow.

IOException

stopStartUpProtocol

void stopStartUpProtocol()
Stop the start up protocol. This method is called by the DataPath relaying a call from the VatTPMgr when it determines that there are two connections being built between this vat and another vat, andthat this connection is the one that should be abandonded.


subbytearray

private byte[] subbytearray(byte[] bytes,
                            int offset,
                            int len)
Return a subarray of a given array.

The subarray must be within the given array or an exception will be thrown.

Parameters:
bytes - The array.
offset - The offset in bytes to the start of the subarray.
len - The length of the subarray.
Returns:
A new byte array which is the subarray.

tokName

private static String tokName(int tok)
Translate a startup protocol message token to a printable string for error messages and the like.

Parameters:
tok - The integer startup token to represent as a string.
Returns:
A string value for the token or TOK_ERR_??? if tok is negative, or TOK_??? if tok is positive.


comments?