Revision: 439 http://skycastle.svn.sourceforge.net/skycastle/?rev=439&view=rev Author: zzorn Date: 2008-04-04 08:44:16 -0700 (Fri, 04 Apr 2008) Log Message: ----------- Moved Message validation to the AbstractProtocol, separating concerns and providing the message validation to all Protocols that extend the AbstractProtocol. Modified Paths: -------------- trunk/skycastle/modules/core/src/main/java/org/skycastle/connection/ClientConnectionHandlerImpl.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/SerializationProtocol.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistry.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistryImpl.java trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java Added Paths: ----------- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/connection/ClientConnectionHandlerImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/connection/ClientConnectionHandlerImpl.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/connection/ClientConnectionHandlerImpl.java 2008-04-04 15:44:16 UTC (rev 439) @@ -5,11 +5,11 @@ import com.sun.sgs.client.simple.SimpleClient; import com.sun.sgs.client.simple.SimpleClientListener; import org.skycastle.messaging.Message; -import org.skycastle.protocol.Protocol; import org.skycastle.protocol.ProtocolException; import org.skycastle.protocol.negotiation.ClientSideProtocolNegotiator; import org.skycastle.protocol.negotiation.NegotiationStatus; import org.skycastle.protocol.negotiation.ProtocolNegotiator; +import org.skycastle.protocol.protocols.Protocol; import org.skycastle.protocol.registry.ProtocolRegistry; import org.skycastle.protocol.registry.ProtocolRegistryImpl; import org.skycastle.util.ParameterChecker; Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java 2008-04-04 15:44:16 UTC (rev 439) @@ -1,6 +1,6 @@ package org.skycastle.protocol.negotiation; -import org.skycastle.protocol.Protocol; +import org.skycastle.protocol.protocols.Protocol; import org.skycastle.protocol.registry.ProtocolRegistry; import org.skycastle.util.ParameterChecker; import org.skycastle.util.StringUtilities; Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java 2008-04-04 15:44:16 UTC (rev 439) @@ -1,6 +1,6 @@ package org.skycastle.protocol.negotiation; -import org.skycastle.protocol.Protocol; +import org.skycastle.protocol.protocols.Protocol; /** * A state machine that can negotiate a protocol to use with another party connected over a network. Copied: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java (from rev 438, trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/AbstractProtocol.java) =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java 2008-04-04 15:44:16 UTC (rev 439) @@ -0,0 +1,131 @@ +package org.skycastle.protocol.protocols; + +import org.skycastle.messaging.Message; +import org.skycastle.protocol.ProtocolException; +import org.skycastle.util.ParameterChecker; +import org.skycastle.util.parameters.ParameterSet; +import org.skycastle.util.parameters.ValidationError; +import org.skycastle.util.parameters.validators.ParameterValidator; +import org.skycastle.util.parameters.validators.type.TypeValidator; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; + +/** + * Provides common functionality. + * + * @author Hans Haggstrom + */ +public abstract class AbstractProtocol + implements Protocol, Serializable +{ + + //====================================================================== + // Private Fields + + private final String myProtocolId; + private final ParameterValidator myMessageValidator; + + //====================================================================== + // Private Constants + + private static final long serialVersionUID = 1L; + + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Protocol Implementation + + public final String getProtocolId() + { + return myProtocolId; + } + + + public final byte[] encode( final Message messageToSend ) throws ProtocolException + { + checkMessageTypes( messageToSend, "Could not send message" ); + + return encodeWithoutCheck( messageToSend ); + } + + + public final Message decode( final byte[] receivedBytes ) throws ProtocolException + { + final Message recievedMessage = decodeWithoutCheck( receivedBytes ); + + checkMessageTypes( recievedMessage, "Could not accept recieved message" ); + + return recievedMessage; + } + + //====================================================================== + // Protected Methods + + //---------------------------------------------------------------------- + // Protected Constructors + + /** + * @param protocolId an identifier for this protocol. Used for protocol negotiation. Should be in + * the Java identifier format (letter + numbers and letters and underscores). + * @param messageValidator a {@link TypeValidator} that is used to check that the types that are allowed + * to be serialized and deserialized are in a set of allowed types. Can also check + * types of nested {@link Collection}s, {@link Map}s, and {@link ParameterSet}s. + * <p/> + * Can be used to improve the security by specifying only simple data classes that + * can be transfered, to minimize hijacking some more complex class with a custom + * state to instabilize or compromize the server (or client). + */ + protected AbstractProtocol( final String protocolId, final ParameterValidator messageValidator ) + { + ParameterChecker.checkIsIdentifier( protocolId, "protocolId" ); + ParameterChecker.checkNotNull( messageValidator, "messageValidator" ); + + myProtocolId = protocolId; + myMessageValidator = messageValidator; + } + + //---------------------------------------------------------------------- + // Abstract Protected Methods + + /** + * Encodes the message without first validating it (the calling {@link AbstractProtocol} takes care of + * that). + * + * @param messageToSend the message to encode to bytes for network transfer. + * + * @return the bytes representing the message to transfer + * + * @throws ProtocolException if there was some error when encoding the message. + */ + protected abstract byte[] encodeWithoutCheck( final Message messageToSend ) throws ProtocolException; + + /** + * Decodes the message without validating it afterwards (the calling {@link AbstractProtocol} takes care + * of that). + * + * @param receivedBytes an array of bytes received over the network. Note that malicious crackers may + * send any kind of messages, so the error handling should be robust. + * + * @return the message represented by the specified bytes. + * + * @throws ProtocolException if there was some error when decoding the received message. + */ + protected abstract Message decodeWithoutCheck( final byte[] receivedBytes ) throws ProtocolException; + + //====================================================================== + // Private Methods + + private void checkMessageTypes( final Message message, final String description ) + throws ProtocolException + { + final ValidationError validationError = myMessageValidator.validateParameter( message, "" ); + if ( validationError != null ) + { + throw new ProtocolException( description + ", it contains a non-allowed type: " + validationError.toString() ); + } + } + +} Property changes on: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Id Name: svn:eol-style + native Copied: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java (from rev 438, trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/Protocol.java) =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java 2008-04-04 15:44:16 UTC (rev 439) @@ -0,0 +1,42 @@ +package org.skycastle.protocol.protocols; + +import org.skycastle.messaging.Message; +import org.skycastle.protocol.ProtocolException; + +/** + * A protocol used to communicate between server and client. + * <p/> + * The transport happens as byte array messages. + * <p/> + * The transfered data is messages with source and target game object, a message type, and a set of named + * parameters of primitive data structures and collections. + * + * @author Hans Haggstrom + */ +public interface Protocol +{ + /** + * @return a string ID used to identify this protocol during protocol negotiations. The ID should be a + * valid Java identifier (sart with letter, contain no spaces, etc). + */ + String getProtocolId(); + + /** + * @param messageToSend the message to encode to bytes for network transfer. + * + * @return the bytes representing the message to transfer + * + * @throws ProtocolException if there was some error when encoding the message. + */ + byte[] encode( Message messageToSend ) throws ProtocolException; + + /** + * @param receivedBytes an array of bytes received over the network. Note that malicious crackers may + * send any kind of messages, so the error handling should be robust. + * + * @return the message represented by the specified bytes. + * + * @throws ProtocolException if there was some error when decoding the received message. + */ + Message decode( byte[] receivedBytes ) throws ProtocolException; +} Property changes on: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Id Name: svn:eol-style + native Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/SerializationProtocol.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/SerializationProtocol.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/SerializationProtocol.java 2008-04-04 15:44:16 UTC (rev 439) @@ -1,12 +1,8 @@ package org.skycastle.protocol.protocols; import org.skycastle.messaging.Message; -import org.skycastle.protocol.AbstractProtocol; -import org.skycastle.protocol.Protocol; import org.skycastle.protocol.ProtocolException; -import org.skycastle.util.ParameterChecker; import org.skycastle.util.parameters.ParameterSet; -import org.skycastle.util.parameters.ValidationError; import org.skycastle.util.parameters.validators.ParameterValidator; import org.skycastle.util.parameters.validators.type.TypeValidator; @@ -22,13 +18,15 @@ */ public final class SerializationProtocol extends AbstractProtocol - implements Serializable { //====================================================================== - // Private Fields + // Public Constants - private final ParameterValidator myMessageValidator; + /** + * The identifier of this {@link Protocol}. + */ + public static final String SERIALIZATION_PROTOCOL_ID = "SerializationProtocol"; //====================================================================== // Private Constants @@ -53,20 +51,16 @@ * can be transfered, to minimize hijacking some more complex class with a custom * state to instabilize or compromize the server (or client). */ - // TODO: Refactor the message validator storage and checking into an abstract base class public SerializationProtocol( final ParameterValidator messageValidator ) { - super( "SerializationProtocol" ); - - ParameterChecker.checkNotNull( messageValidator, "messageValidator" ); - - myMessageValidator = messageValidator; + super( SERIALIZATION_PROTOCOL_ID, messageValidator ); } - //---------------------------------------------------------------------- - // Protocol Implementation + //====================================================================== + // Protected Methods - public byte[] encode( final Message messageToSend ) throws ProtocolException + @Override + protected byte[] encodeWithoutCheck( final Message messageToSend ) throws ProtocolException { final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = null; @@ -75,8 +69,6 @@ //noinspection IOResourceOpenedButNotSafelyClosed objectOutputStream = new ObjectOutputStream( byteArrayOutputStream ); - checkMessageTypes( messageToSend, objectOutputStream ); - objectOutputStream.writeObject( messageToSend ); return byteArrayOutputStream.toByteArray(); @@ -92,7 +84,8 @@ } - public Message decode( final byte[] receivedBytes ) throws ProtocolException + @Override + protected Message decodeWithoutCheck( final byte[] receivedBytes ) throws ProtocolException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( receivedBytes ); ObjectInputStream objectInputStream = null; @@ -101,11 +94,7 @@ //noinspection IOResourceOpenedButNotSafelyClosed objectInputStream = new ObjectInputStream( byteArrayInputStream ); - final Message message = (Message) objectInputStream.readObject(); - - checkMessageTypes( message, objectInputStream ); - - return message; + return (Message) objectInputStream.readObject(); } catch ( IOException e ) { @@ -128,18 +117,6 @@ //====================================================================== // Private Methods - private void checkMessageTypes( final Message message, final Closeable objectOutputStream ) - throws ProtocolException - { - final ValidationError validationError = myMessageValidator.validateParameter( message, "" ); - if ( validationError != null ) - { - closeStream( objectOutputStream ); - throw new ProtocolException( "Could not transfer message, it contains a non-allowed type: " + validationError.toString() ); - } - } - - private void closeStream( final Closeable stream ) throws ProtocolException { Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistry.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistry.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistry.java 2008-04-04 15:44:16 UTC (rev 439) @@ -1,13 +1,13 @@ package org.skycastle.protocol.registry; import com.sun.sgs.app.ManagedObject; -import org.skycastle.protocol.Protocol; +import org.skycastle.protocol.protocols.Protocol; import java.io.Serializable; import java.util.Set; /** - * A registry that can be used to access available {@link org.skycastle.protocol.Protocol}s. + * A registry that can be used to access available {@link org.skycastle.protocol.protocols.Protocol}s. * * @author Hans Haggstrom */ @@ -20,8 +20,8 @@ Set<String> getAvailableProtocolIds(); /** - * @return the {@link org.skycastle.protocol.Protocol} with the specified protocol id, or null if not - * found. + * @return the {@link org.skycastle.protocol.protocols.Protocol} with the specified protocol id, or null + * if not found. */ Protocol getProtocol( String protocolId ); } Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistryImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistryImpl.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/registry/ProtocolRegistryImpl.java 2008-04-04 15:44:16 UTC (rev 439) @@ -1,7 +1,7 @@ package org.skycastle.protocol.registry; import org.skycastle.protocol.MessageValidator; -import org.skycastle.protocol.Protocol; +import org.skycastle.protocol.protocols.Protocol; import org.skycastle.protocol.protocols.SerializationProtocol; import org.skycastle.util.ParameterChecker; @@ -11,7 +11,7 @@ import java.util.Set; /** - * A registry used to access available {@link org.skycastle.protocol.Protocol}s. + * A registry used to access available {@link org.skycastle.protocol.protocols.Protocol}s. * * @author Hans Haggstrom */ Modified: trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java =================================================================== --- trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java 2008-04-03 22:16:52 UTC (rev 438) +++ trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java 2008-04-04 15:44:16 UTC (rev 439) @@ -6,9 +6,10 @@ import junit.framework.TestCase; import org.skycastle.messaging.Message; -import org.skycastle.protocol.AbstractProtocol; -import org.skycastle.protocol.Protocol; +import org.skycastle.protocol.MessageValidator; import org.skycastle.protocol.ProtocolException; +import org.skycastle.protocol.protocols.AbstractProtocol; +import org.skycastle.protocol.protocols.Protocol; import org.skycastle.protocol.registry.ProtocolRegistryImpl; import org.skycastle.util.StringUtilities; @@ -29,16 +30,17 @@ // Private Constants private static final String DUMMY_PROTOCOL_ID = "DummyProtocol"; - private static final Protocol DUMMY_PROTOCOL = new AbstractProtocol( DUMMY_PROTOCOL_ID ) + private static final Protocol DUMMY_PROTOCOL = new AbstractProtocol( DUMMY_PROTOCOL_ID, + new MessageValidator() ) { - public byte[] encode( final Message messageToSend ) throws ProtocolException + protected byte[] encodeWithoutCheck( final Message messageToSend ) throws ProtocolException { return new byte[0]; } - public Message decode( final byte[] receivedBytes ) throws ProtocolException + protected Message decodeWithoutCheck( final byte[] receivedBytes ) throws ProtocolException { return null; } @@ -46,18 +48,20 @@ }; private static final String FOO_PROTOCOL_ID = "FooProtocol"; - private static final Protocol FOO_PROTOCOL = new AbstractProtocol( FOO_PROTOCOL_ID ) + private static final Protocol FOO_PROTOCOL = new AbstractProtocol( FOO_PROTOCOL_ID, + new MessageValidator() ) { - public byte[] encode( final Message messageToSend ) throws ProtocolException + protected byte[] encodeWithoutCheck( final Message messageToSend ) throws ProtocolException { return new byte[0]; } - public Message decode( final byte[] receivedBytes ) throws ProtocolException + protected Message decodeWithoutCheck( final byte[] receivedBytes ) throws ProtocolException { return null; + } }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.