diff options
-rw-r--r-- | cpp/config/TestUtil.py | 4 | ||||
-rw-r--r-- | cpp/slice/Ice/LocalException.ice | 11 | ||||
-rw-r--r-- | cpp/src/Ice/Connection.cpp | 84 | ||||
-rw-r--r-- | cpp/src/Ice/Connection.h | 1 | ||||
-rw-r--r-- | cpp/src/Ice/ConnectionFactory.cpp | 21 | ||||
-rw-r--r-- | cpp/src/Ice/ConnectionFactory.h | 2 | ||||
-rw-r--r-- | cpp/src/Ice/Exception.cpp | 7 | ||||
-rw-r--r-- | cpp/src/Ice/Protocol.h | 9 | ||||
-rw-r--r-- | cpp/src/Ice/TraceUtil.cpp | 5 | ||||
-rw-r--r-- | java/src/IceInternal/Connection.java | 84 | ||||
-rw-r--r-- | java/src/IceInternal/IncomingConnectionFactory.java | 6 | ||||
-rw-r--r-- | java/src/IceInternal/Protocol.java | 9 | ||||
-rw-r--r-- | java/src/IceInternal/TraceUtil.java | 5 |
13 files changed, 216 insertions, 32 deletions
diff --git a/cpp/config/TestUtil.py b/cpp/config/TestUtil.py index fb9a3a78ad7..2ee25fc35e6 100644 --- a/cpp/config/TestUtil.py +++ b/cpp/config/TestUtil.py @@ -16,8 +16,8 @@ import sys, os # protocol. Otherwise TCP is used. # -protocol = "ssl" -#protocol = "" +#protocol = "ssl" +protocol = "" # # Set compressed to 1 in case you want to run the tests with diff --git a/cpp/slice/Ice/LocalException.ice b/cpp/slice/Ice/LocalException.ice index 733a1113aa9..49902fcedac 100644 --- a/cpp/slice/Ice/LocalException.ice +++ b/cpp/slice/Ice/LocalException.ice @@ -305,6 +305,17 @@ local exception UnknownMessageException extends ProtocolException /** * + * This exception is a specialization of [ProtocolException], that is + * raised if a message is received over a connection that is not yet + * validated. + * + **/ +local exception ConnectionNotValidatedException extends ProtocolException +{ +}; + +/** + * * This exception is a specialization of [ProtocolException], * indicating that a response for an unknown request id has been * received. diff --git a/cpp/src/Ice/Connection.cpp b/cpp/src/Ice/Connection.cpp index e25f1c98fb3..f30bd36759c 100644 --- a/cpp/src/Ice/Connection.cpp +++ b/cpp/src/Ice/Connection.cpp @@ -414,6 +414,25 @@ IceInternal::Connection::message(BasicStream& stream, const ThreadPoolPtr& threa assert(stream.i == stream.b.end()); stream.i = stream.b.begin() + 2; stream.read(messageType); + + // + // Check whether the connection is validated. + // + if(!_connectionValidated && messageType != validateConnectionMsg) + { + // + // Yes, we must set _connectionValidated to true + // here. The connection gets implicitly validated by + // any kind of message. However, it's still a protocol + // error like any other if no explicit connection + // validation message was sent first. Also, if I + // wouldn't set _connecitonValidated to true here, + // then the ConnectionValidatedException would be + // translated int a CloseConnectionException. + // + _connectionValidated = true; + throw ConnectionNotValidatedException(__FILE__, __LINE__); + } // // Uncompress if necessary. @@ -548,6 +567,25 @@ IceInternal::Connection::message(BasicStream& stream, const ThreadPoolPtr& threa break; } + case validateConnectionMsg: + { + traceHeader("received validate connection", stream, _logger, _traceLevels); + if(_endpoint->datagram()) + { + if(_warn) + { + Warning out(_logger); + out << "ignoring validate connection message for datagram connection:\n" + << _transceiver->toString(); + } + } + else + { + _connectionValidated = true; + } + break; + } + case closeConnectionMsg: { traceHeader("received close connection", stream, _logger, _traceLevels); @@ -782,22 +820,33 @@ IceInternal::Connection::Connection(const InstancePtr& instance, { _warn = _instance->properties()->getPropertyAsInt("Ice.ConnectionWarnings") > 0; - if(_adapter) + if(_endpoint->datagram()) { // - // Incoming connections are always implicitly validated. + // Datagram connections are always implicitly validated. // _connectionValidated = true; } else { - // - // Outoging datagram connections are always validated - // implicitly. Outgoing non-datagram connections must receive a - // message from the server for connection validation. - // - //_connectionValidated = _endpoint->datagram(); - _connectionValidated = true; // TODO: Not finished yet. + if(_adapter) + { + // + // Incoming connections play the active role with respect + // to connection validation. + // + _connectionValidated = true; + validateConnection(); + } + else + { + // + // Outgoing connections are passive with respect to + // validation, i.e., they wait until they get a validate + // connection message from the server. + // + _connectionValidated = false; + } } } @@ -959,6 +1008,19 @@ IceInternal::Connection::setState(State state) } void +IceInternal::Connection::validateConnection() +{ + BasicStream os(_instance); + os.write(protocolVersion); + os.write(encodingVersion); + os.write(validateConnectionMsg); + os.write(headerSize); // Message size. + os.i = os.b.begin(); + traceHeader("sending validate connection", os, _logger, _traceLevels); + _transceiver->write(os, _endpoint->timeout()); +} + +void IceInternal::Connection::closeConnection() { BasicStream os(_instance); @@ -969,6 +1031,10 @@ IceInternal::Connection::closeConnection() os.i = os.b.begin(); traceHeader("sending close connection", os, _logger, _traceLevels); _transceiver->write(os, _endpoint->timeout()); + + // + // A close connection is always followed by a connection shutdown. + // _transceiver->shutdown(); } diff --git a/cpp/src/Ice/Connection.h b/cpp/src/Ice/Connection.h index 102012f6378..50fc13f30f5 100644 --- a/cpp/src/Ice/Connection.h +++ b/cpp/src/Ice/Connection.h @@ -90,6 +90,7 @@ private: void setState(State, const ::Ice::LocalException&); void setState(State); + void validateConnection(); void closeConnection(); void registerWithPool(); void unregisterWithPool(); diff --git a/cpp/src/Ice/ConnectionFactory.cpp b/cpp/src/Ice/ConnectionFactory.cpp index 4cfe1b2f95f..0645e0dee39 100644 --- a/cpp/src/Ice/ConnectionFactory.cpp +++ b/cpp/src/Ice/ConnectionFactory.cpp @@ -334,9 +334,18 @@ IceInternal::IncomingConnectionFactory::message(BasicStream&, const ThreadPoolPt try { TransceiverPtr transceiver = _acceptor->accept(0); - ConnectionPtr connection = new Connection(_instance, transceiver, _endpoint, _adapter); - connection->activate(); - _connections.push_back(connection); + // Test code: We drop every 2nd connection we accept. +/* + if(++_testCount % 2) + { + transceiver->close(); + } + else +*/ { + ConnectionPtr connection = new Connection(_instance, transceiver, _endpoint, _adapter); + connection->activate(); + _connections.push_back(connection); + } } catch(const SocketException&) { @@ -371,6 +380,11 @@ IceInternal::IncomingConnectionFactory::finished(const ThreadPoolPtr& threadPool } else if(_state == StateClosed) { +// +// With the new connection validation, this code is not needed +// anymore. +// +/* try { // @@ -399,6 +413,7 @@ IceInternal::IncomingConnectionFactory::finished(const ThreadPoolPtr& threadPool out << "connection exception:\n" << ex << '\n' << _acceptor->toString(); } } +*/ _acceptor->close(); diff --git a/cpp/src/Ice/ConnectionFactory.h b/cpp/src/Ice/ConnectionFactory.h index 15fadcf3ca8..72fe7c4508d 100644 --- a/cpp/src/Ice/ConnectionFactory.h +++ b/cpp/src/Ice/ConnectionFactory.h @@ -101,6 +101,8 @@ private: State _state; bool _warn; bool _registeredWithPool; + + int _testCount; // TODO: For test only. }; } diff --git a/cpp/src/Ice/Exception.cpp b/cpp/src/Ice/Exception.cpp index daa6ee8b3fe..3d6d3bd8733 100644 --- a/cpp/src/Ice/Exception.cpp +++ b/cpp/src/Ice/Exception.cpp @@ -212,6 +212,13 @@ Ice::UnknownMessageException::ice_print(ostream& out) const } void +Ice::ConnectionNotValidatedException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ":\nprotocol error: received message over unvalidated connection"; +} + +void Ice::UnknownRequestIdException::ice_print(ostream& out) const { Exception::ice_print(out); diff --git a/cpp/src/Ice/Protocol.h b/cpp/src/Ice/Protocol.h index 4d9c879b3b6..d79f08bfa2c 100644 --- a/cpp/src/Ice/Protocol.h +++ b/cpp/src/Ice/Protocol.h @@ -38,10 +38,11 @@ const ::Ice::Byte encodingVersion = 0; const ::Ice::Byte requestMsg = 0; const ::Ice::Byte requestBatchMsg = 1; const ::Ice::Byte replyMsg = 2; -const ::Ice::Byte closeConnectionMsg = 3; -const ::Ice::Byte compressedRequestMsg = 4; -const ::Ice::Byte compressedRequestBatchMsg = 5; -const ::Ice::Byte compressedReplyMsg = 6; +const ::Ice::Byte validateConnectionMsg = 3; +const ::Ice::Byte closeConnectionMsg = 4; +const ::Ice::Byte compressedRequestMsg = 5; +const ::Ice::Byte compressedRequestBatchMsg = 6; +const ::Ice::Byte compressedReplyMsg = 7; } diff --git a/cpp/src/Ice/TraceUtil.cpp b/cpp/src/Ice/TraceUtil.cpp index ac4069fc36f..1a9d2889dbe 100644 --- a/cpp/src/Ice/TraceUtil.cpp +++ b/cpp/src/Ice/TraceUtil.cpp @@ -71,6 +71,11 @@ printHeader(ostream& s, BasicStream& stream) s << "(close connection)"; break; } + case validateConnectionMsg: + { + s << "(validate connection)"; + break; + } default: { s << "(unknown)"; diff --git a/java/src/IceInternal/Connection.java b/java/src/IceInternal/Connection.java index f3bb30097e1..33ec2527665 100644 --- a/java/src/IceInternal/Connection.java +++ b/java/src/IceInternal/Connection.java @@ -387,6 +387,26 @@ public final class Connection extends EventHandler byte messageType = stream.readByte(); stream.pos(Protocol.headerSize); + // + // Check whether the connection is validated. + // + if(!_connectionValidated && messageType != Protocol.validateConnectionMsg) + { + // + // Yes, we must set _connectionValidated to true + // here. The connection gets implicitly validated + // by any kind of message. However, it's still a + // protocol error like any other if no explicit + // connection validation message was sent + // first. Also, if I wouldn't set + // _connecitonValidated to true here, then the + // ConnectionValidatedException would be + // translated int a CloseConnectionException. + // + _connectionValidated = true; + throw new Ice.ConnectionNotValidatedException(); + } + switch(messageType) { case Protocol.compressedRequestMsg: @@ -442,6 +462,24 @@ public final class Connection extends EventHandler break; } + case Protocol.validateConnectionMsg: + { + TraceUtil.traceHeader("received validate connection", stream, _logger, _traceLevels); + if(_endpoint.datagram()) + { + if(_warn) + { + _logger.warning("ignoring validate connection message for datagram connection:\n" + + _transceiver.toString()); + } + } + else + { + _connectionValidated = true; + } + break; + } + case Protocol.closeConnectionMsg: { TraceUtil.traceHeader("received close connection", stream, _logger, _traceLevels); @@ -702,24 +740,34 @@ public final class Connection extends EventHandler _warn = _instance.properties().getPropertyAsInt("Ice.ConnectionWarnings") > 0 ? true : false; _registeredWithPool = false; - if(_adapter != null) + if(_endpoint.datagram()) { // - // Incoming connections are always implicitly validated. + // Datagram connections are always implicitly validated. // _connectionValidated = true; } else { - // - // Outoging datagram connections are always validated - // implicitly. Outgoing non-datagram connections must receive a - // message from the server for connection validation. - // - //_connectionValidated = _endpoint.datagram(); - _connectionValidated = true; // TODO: Not finished yet. + if(_adapter != null) + { + // + // Incoming connections play the active role with + // respect to connection validation. + // + _connectionValidated = true; + validateConnection(); + } + else + { + // + // Outgoing connections are passive with respect to + // validation, i.e., they wait until they get a + // validate connection message from the server. + // + _connectionValidated = false; + } } - } protected void @@ -908,6 +956,17 @@ public final class Connection extends EventHandler } private void + validateConnection() + { + BasicStream os = new BasicStream(_instance); + os.writeByte(Protocol.protocolVersion); + os.writeByte(Protocol.encodingVersion); + os.writeByte(Protocol.validateConnectionMsg); + os.writeInt(Protocol.headerSize); // Message size. + _transceiver.write(os, _endpoint.timeout()); + } + + private void closeConnection() { BasicStream os = new BasicStream(_instance); @@ -916,6 +975,11 @@ public final class Connection extends EventHandler os.writeByte(Protocol.closeConnectionMsg); os.writeInt(Protocol.headerSize); // Message size. _transceiver.write(os, _endpoint.timeout()); + + // + // A close connection is always followed by a connection + // shutdown. + // _transceiver.shutdown(); } diff --git a/java/src/IceInternal/IncomingConnectionFactory.java b/java/src/IceInternal/IncomingConnectionFactory.java index f1f27db86c1..83538c6f09a 100644 --- a/java/src/IceInternal/IncomingConnectionFactory.java +++ b/java/src/IceInternal/IncomingConnectionFactory.java @@ -145,6 +145,11 @@ public class IncomingConnectionFactory extends EventHandler } else if(_state == StateClosed) { +// +// With the new connection validation, this code is not needed +// anymore. +// +/* try { // @@ -172,6 +177,7 @@ public class IncomingConnectionFactory extends EventHandler warning(ex); } } +*/ _acceptor.close(); diff --git a/java/src/IceInternal/Protocol.java b/java/src/IceInternal/Protocol.java index 1b34b22840c..fa6cc04575d 100644 --- a/java/src/IceInternal/Protocol.java +++ b/java/src/IceInternal/Protocol.java @@ -34,8 +34,9 @@ final class Protocol final static byte requestMsg = 0; final static byte requestBatchMsg = 1; final static byte replyMsg = 2; - final static byte closeConnectionMsg = 3; - final static byte compressedRequestMsg = 4; - final static byte compressedRequestBatchMsg = 5; - final static byte compressedReplyMsg = 6; + final static byte validateConnectionMsg = 3; + final static byte closeConnectionMsg = 4; + final static byte compressedRequestMsg = 5; + final static byte compressedRequestBatchMsg = 6; + final static byte compressedReplyMsg = 7; } diff --git a/java/src/IceInternal/TraceUtil.java b/java/src/IceInternal/TraceUtil.java index 71e94e582bd..d40b2fa2bfa 100644 --- a/java/src/IceInternal/TraceUtil.java +++ b/java/src/IceInternal/TraceUtil.java @@ -236,6 +236,11 @@ final class TraceUtil out.write("(close connection)"); break; } + case Protocol.validateConnectionMsg: + { + out.write("(validate connection)"); + break; + } default: { out.write("(unknown)"); |