diff options
author | Mark Spruiell <mes@zeroc.com> | 2014-05-29 11:06:44 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2014-05-29 11:06:44 -0700 |
commit | 3cfd324cdcc65d2acbc7536f1652d44f66a0e896 (patch) | |
tree | 44613394c5b9c6c6eb0ec8b41e110002a58d60ea /java/src | |
parent | Fixed Python throughput demo config (diff) | |
download | ice-3cfd324cdcc65d2acbc7536f1652d44f66a0e896.tar.bz2 ice-3cfd324cdcc65d2acbc7536f1652d44f66a0e896.tar.xz ice-3cfd324cdcc65d2acbc7536f1652d44f66a0e896.zip |
porting C++ transport changes to Java
Diffstat (limited to 'java/src')
39 files changed, 3440 insertions, 3878 deletions
diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java index c001462c960..fb2c0ce8a33 100644 --- a/java/src/Ice/ConnectionI.java +++ b/java/src/Ice/ConnectionI.java @@ -341,7 +341,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne sendRequest(IceInternal.Outgoing out, boolean compress, boolean response) throws IceInternal.LocalExceptionWrapper { - int requestId = 0; final IceInternal.BasicStream os = out.os(); if(_exception != null) @@ -363,6 +362,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // _transceiver.checkSendSize(os.getBuffer(), _instance.messageSizeMax()); + int requestId = 0; if(response) { // @@ -382,7 +382,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne os.writeInt(requestId); } - out.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, + out.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, os.size() - IceInternal.Protocol.headerSize - 4); // @@ -418,7 +418,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne sendAsyncRequest(IceInternal.OutgoingAsync out, boolean compress, boolean response) throws IceInternal.LocalExceptionWrapper { - int requestId = 0; final IceInternal.BasicStream os = out.__getOs(); if(_exception != null) @@ -440,6 +439,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // _transceiver.checkSendSize(os.getBuffer(), _instance.messageSizeMax()); + int requestId = 0; if(response) { // @@ -459,13 +459,13 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne os.writeInt(requestId); } - out.__attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, + out.__attachRemoteObserver(initConnectionInfo(), _endpoint, requestId, os.size() - IceInternal.Protocol.headerSize - 4); int status; try { - status = sendMessage(new OutgoingMessage(out, out.__getOs(), compress, requestId)); + status = sendMessage(new OutgoingMessage(out, os, compress, requestId)); } catch(Ice.LocalException ex) { @@ -505,8 +505,8 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(_exception != null) { // - // If there were no batch requests queued when the connection failed, we can safely - // retry with a new connection. Otherwise, we must throw to notify the caller that + // If there were no batch requests queued when the connection failed, we can safely + // retry with a new connection. Otherwise, we must throw to notify the caller that // some previous batch requests were not sent. // if(_batchStream.isEmpty()) @@ -597,6 +597,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne buffer.b.get(lastRequest); _batchStream.resize(_batchMarker, false); + // + // Send the batch stream without the last request. + // try { // @@ -673,7 +676,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne public synchronized void abortBatchRequest() { - _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, + _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, _batchAutoFlush); _batchRequestNum = 0; _batchRequestCompress = false; @@ -711,7 +714,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { return begin_flushBatchRequestsInternal(cb); } - + public AsyncResult begin_flushBatchRequests(IceInternal.Functional_VoidCallback __responseCb, IceInternal.Functional_GenericCallback1<Ice.LocalException> __localExceptionCb, @@ -793,6 +796,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _batchStream.swap(out.os()); + // + // Send the batch stream. + // boolean sent = false; try { @@ -809,7 +815,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // // Reset the batch stream. // - _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, + _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, _batchAutoFlush); _batchRequestNum = 0; _batchRequestCompress = false; @@ -857,6 +863,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _batchStream.swap(outAsync.__getOs()); + // + // Send the batch stream. + // int status; try { @@ -873,7 +882,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // // Reset the batch stream. // - _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, + _batchStream = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding, _batchAutoFlush); _batchRequestNum = 0; _batchRequestCompress = false; @@ -1103,7 +1112,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { return; } - assert(_state < StateClosing); _adapter = adapter; @@ -1166,36 +1174,49 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne return; } + int readyOp = current.operation; try { unscheduleTimeout(current.operation); - if((current.operation & IceInternal.SocketOperation.Write) != 0 && !_writeStream.isEmpty()) + + int writeOp = IceInternal.SocketOperation.None; + int readOp = IceInternal.SocketOperation.None; + + if((readyOp & IceInternal.SocketOperation.Write) != 0) { + final IceInternal.Buffer buf = _writeStream.getBuffer(); if(_observer != null) { - observerStartWrite(_writeStream.pos()); + observerStartWrite(buf); } - if(!_transceiver.write(_writeStream.getBuffer())) + writeOp = _transceiver.write(buf); + if(_observer != null && (writeOp & IceInternal.SocketOperation.Write) == 0) { - assert(!_writeStream.isEmpty()); - scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout()); - return; - } - if(_observer != null) - { - observerFinishWrite(_writeStream.pos()); + observerFinishWrite(buf); } - assert(!_writeStream.getBuffer().b.hasRemaining()); } - if((current.operation & IceInternal.SocketOperation.Read) != 0 && !_readStream.isEmpty()) + + while((readyOp & IceInternal.SocketOperation.Read) != 0) { + final IceInternal.Buffer buf = _readStream.getBuffer(); + if(_observer != null && !_readHeader) + { + observerStartRead(buf); + } + + readOp = _transceiver.read(buf, _hasMoreData); + if((readOp & IceInternal.SocketOperation.Read) != 0) + { + break; + } + if(_observer != null && !_readHeader) + { + assert(!buf.b.hasRemaining()); + observerFinishRead(buf); + } + if(_readHeader) // Read header if necessary. { - if(!_transceiver.read(_readStream.getBuffer(), _hasMoreData)) - { - return; - } - assert(!_readStream.getBuffer().b.hasRemaining()); _readHeader = false; if(_observer != null) @@ -1256,34 +1277,33 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { throw new Ice.DatagramLimitException(); // The message was truncated. } - else - { - if(_observer != null) - { - observerStartRead(_readStream.pos()); - } - if(!_transceiver.read(_readStream.getBuffer(), _hasMoreData)) - { - assert(!_readStream.isEmpty()); - scheduleTimeout(IceInternal.SocketOperation.Read, _endpoint.timeout()); - return; - } - if(_observer != null) - { - observerFinishRead(_readStream.pos()); - } - assert(!_readStream.getBuffer().b.hasRemaining()); - } + continue; } + break; } - + + int newOp = readOp | writeOp; + readyOp = readyOp & ~newOp; + assert(readyOp != 0 || newOp != 0); + if(_state <= StateNotValidated) { + if(newOp != 0) + { + // + // Wait for all the transceiver conditions to be + // satisfied before continuing. + // + scheduleTimeout(newOp); + _threadPool.update(this, current.operation, newOp); + return; + } + if(_state == StateNotInitialized && !initialize(current.operation)) { return; } - + if(_state <= StateNotValidated && !validate(current.operation)) { return; @@ -1307,24 +1327,41 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } else { - assert(_state <= StateClosing); - + assert(_state <= StateClosingPending); + // // We parse messages first, if we receive a close // connection message we won't send more messages. - // - if((current.operation & IceInternal.SocketOperation.Read) != 0) + // + if((readyOp & IceInternal.SocketOperation.Read) != 0) { - info = parseMessage(current.stream); // Optimization: use the thread's stream. + info = new MessageInfo(current.stream); // Optimization: use the thread's stream. + newOp |= parseMessage(info); } - if((current.operation & IceInternal.SocketOperation.Write) != 0) + if((readyOp & IceInternal.SocketOperation.Write) != 0) { - sentCBs = sendNextMessage(); - if(sentCBs != null) + sentCBs = new java.util.LinkedList<OutgoingMessage>(); + newOp |= sendNextMessage(sentCBs); + if(!sentCBs.isEmpty()) { ++_dispatchCount; } + else + { + sentCBs = null; + } + } + + if(_state < StateClosed) + { + scheduleTimeout(newOp); + _threadPool.update(this, current.operation, newOp); + } + + if(readyOp == 0) + { + return; } } } @@ -1368,9 +1405,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); } + current.ioCompleted(); } - + if(_dispatcher != null) { if(info != null && info.heartbeatCallback == null) // No need for the stream if heartbeat callback @@ -1452,22 +1490,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne ++count; } - if(info.invokeNum > 0) - { - // - // Method invocation (or multiple invocations for batch messages) - // must be done outside the thread synchronization, so that nested - // calls are possible. - // - invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, - info.adapter); - - // - // Don't increase count, the dispatch count is - // decreased when the incoming reply is sent. - // - } - if(info.heartbeatCallback != null) { try @@ -1480,8 +1502,24 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } ++count; } + + // + // Method invocation (or multiple invocations for batch messages) + // must be done outside the thread synchronization, so that nested + // calls are possible. + // + if(info.invokeNum > 0) + { + invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, + info.adapter); + + // + // Don't increase count, the dispatch count is + // decreased when the incoming reply is sent. + // + } } - + // // Decrease dispatch count. // @@ -1493,13 +1531,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(_dispatchCount == 0) { // - // Only initiate shutdown if not already done. It - // might have already been done if the sent - // callback or AMI callback was dispatched when - // the connection was already in the closing - // state. + // Only initiate shutdown if not already done. It might + // have already been done if the sent callback or AMI + // callback was dispatched when the connection was already + // in the closing state. // - if(_state == StateClosing && !_shutdownInitiated) + if(_state == StateClosing) { try { @@ -1523,11 +1560,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne public void finished(IceInternal.ThreadPoolCurrent current) { + synchronized(this) + { + assert(_state == StateClosed); + unscheduleTimeout(IceInternal.SocketOperation.Read | IceInternal.SocketOperation.Write); + } + // - // Check if the connection needs to call user callbacks. If it doesn't, we - // can safely run finish() from this "IO thread". Otherwise, we either run - // finish() with the dispatcher if one is set, or we promote another IO - // thread first before calling finish(). + // If there are no callbacks to call, we don't call ioCompleted() since we're not going + // to call code that will potentially block (this avoids promoting a new leader and + // unecessary thread creation, especially if this is called on shutdown). // if(_startCallback == null && _sendStreams.isEmpty() && _asyncRequests.isEmpty() && _callback == null) { @@ -1551,7 +1593,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { finish(); } - }, + }, this); } catch(java.lang.Exception ex) @@ -1567,43 +1609,30 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne public void finish() { - synchronized(this) - { - assert(_state == StateClosed); - unscheduleTimeout(IceInternal.SocketOperation.Read | - IceInternal.SocketOperation.Write | - IceInternal.SocketOperation.Connect); - } - if(_startCallback != null) { _startCallback.connectionStartFailed(this, _exception); _startCallback = null; } - + if(!_sendStreams.isEmpty()) { if(!_writeStream.isEmpty()) { // - // Return the stream to the outgoing call. This is important for + // Return the stream to the outgoing call. This is important for // retriable AMI calls which are not marshalled again. // OutgoingMessage message = _sendStreams.getFirst(); _writeStream.swap(message.stream); } - - // - // NOTE: for twoway requests which are not sent, finished can be called twice: the - // first time because the outgoing is in the _sendStreams set and the second time - // because it's either in the _requests/_asyncRequests set. This is fine, only the - // first call should be taken into account by the implementation of finished. - // + for(OutgoingMessage p : _sendStreams) { - if(p.requestId > 0) + p.finished(_exception); + if(p.requestId > 0) // Make sure finished isn't called twice. { - if(p.out != null) // Make sure finished isn't called twice. + if(p.out != null) { _requests.remove(p.requestId); } @@ -1612,11 +1641,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _asyncRequests.remove(p.requestId); } } - p.finished(_exception); } _sendStreams.clear(); } - + for(IceInternal.Outgoing p : _requests.values()) { p.finished(_exception, true); @@ -1628,7 +1656,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne p.__finished(_exception, true); } _asyncRequests.clear(); - + if(_callback != null) { try @@ -1662,18 +1690,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne return _toString(); } - public java.nio.channels.SelectableChannel + public java.nio.channels.SelectableChannel fd() { return _transceiver.fd(); } - public boolean - hasMoreData() - { - return _hasMoreData.value; - } - public synchronized void timedOut() { @@ -1685,7 +1707,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { setState(StateClosed, new TimeoutException()); } - else if(_state == StateClosing) + else if(_state < StateClosed) { setState(StateClosed, new CloseTimeoutException()); } @@ -1760,7 +1782,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _monitor = monitor; _transceiver = transceiver; _desc = transceiver.toString(); - _type = transceiver.type(); + _type = transceiver.protocol(); _connector = connector; _endpoint = endpoint; _adapter = adapter; @@ -1786,7 +1808,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } _nextRequestId = 1; _batchAutoFlush = initData.properties.getPropertyAsIntWithDefault("Ice.BatchAutoFlush", 1) > 0 ? true : false; - _batchStream = new IceInternal.BasicStream(instance, IceInternal.Protocol.currentProtocolEncoding, + _batchStream = new IceInternal.BasicStream(instance, IceInternal.Protocol.currentProtocolEncoding, _batchAutoFlush); _batchStreamInUse = false; _batchRequestNum = 0; @@ -1869,8 +1891,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne private static final int StateActive = 2; private static final int StateHolding = 3; private static final int StateClosing = 4; - private static final int StateClosed = 5; - private static final int StateFinished = 6; + private static final int StateClosingPending = 5; + private static final int StateClosed = 6; + private static final int StateFinished = 7; private void setState(int state, LocalException ex) @@ -1888,6 +1911,11 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(_exception == null) { + // + // If we are in closed state, an exception must be set. + // + assert(_state != StateClosed); + _exception = ex; // @@ -1903,7 +1931,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _exception instanceof ConnectionTimeoutException || _exception instanceof CommunicatorDestroyedException || _exception instanceof ObjectAdapterDeactivatedException || - (_exception instanceof ConnectionLostException && _state == StateClosing))) + (_exception instanceof ConnectionLostException && _state >= StateClosing))) { warning("connection exception", _exception); } @@ -1995,19 +2023,15 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } case StateClosing: + case StateClosingPending: { // - // Can't change back from closed. + // Can't change back from closing pending. // - if(_state >= StateClosed) + if(_state >= StateClosingPending) { return; } - if(_state == StateHolding) - { - // We need to continue to read in closing state. - _threadPool.register(this, IceInternal.SocketOperation.Read); - } break; } @@ -2020,7 +2044,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _threadPool.finish(this); break; } - + case StateFinished: { assert(_state == StateClosed); @@ -2069,7 +2093,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(oldState != newState) { _observer = _instance.getObserver().getConnectionObserver(initConnectionInfo(), - _endpoint, + _endpoint, newState, _observer); if(_observer != null) @@ -2089,7 +2113,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _exception instanceof ConnectionTimeoutException || _exception instanceof CommunicatorDestroyedException || _exception instanceof ObjectAdapterDeactivatedException || - (_exception instanceof ConnectionLostException && _state == StateClosing))) + (_exception instanceof ConnectionLostException && _state >= StateClosing))) { _observer.failed(_exception.ice_name()); } @@ -2117,17 +2141,19 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { assert(_state == StateClosing); assert(_dispatchCount == 0); - assert(!_shutdownInitiated); + if(_shutdownInitiated) + { + return; + } _shutdownInitiated = true; if(!_endpoint.datagram()) { // - // Before we shut down, we send a close connection - // message. + // Before we shut down, we send a close connection message. // - IceInternal.BasicStream os = new IceInternal.BasicStream(_instance, + IceInternal.BasicStream os = new IceInternal.BasicStream(_instance, IceInternal.Protocol.currentProtocolEncoding); os.writeBlob(IceInternal.Protocol.magic); IceInternal.Protocol.currentProtocol.__write(os); @@ -2138,23 +2164,18 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if((sendMessage(new OutgoingMessage(os, false, false)) & IceInternal.AsyncStatus.Sent) > 0) { + setState(StateClosingPending); + // - // Schedule the close timeout to wait for the peer to close the connection. If - // the message was queued for sending, sendNextMessage will schedule the timeout - // once all messages were sent. + // Notify the the transceiver of the graceful connection closure. // - scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + int op = _transceiver.closing(true, _exception); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.register(this, op); + } } - - // - // The CloseConnection message should be sufficient. Closing the write - // end of the socket is probably an artifact of how things were done - // in IIOP. In fact, shutting down the write end of the socket causes - // problems on Windows by preventing the peer from using the socket. - // For example, the peer is no longer able to continue writing a large - // message after the socket is shutdown. - // - //_transceiver.shutdownWrite(); } } @@ -2190,10 +2211,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne private boolean initialize(int operation) { - int s = _transceiver.initialize(_readStream.getBuffer(), _writeStream.getBuffer()); + int s = _transceiver.initialize(_readStream.getBuffer(), _writeStream.getBuffer(), _hasMoreData); if(s != IceInternal.SocketOperation.None) { - scheduleTimeout(s, connectTimeout()); + scheduleTimeout(s); _threadPool.update(this, operation, s); return false; } @@ -2203,6 +2224,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // _desc = _transceiver.toString(); setState(StateNotValidated); + return true; } @@ -2213,7 +2235,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { if(_adapter != null) // The server side has the active role for connection validation. { - if(_writeStream.size() == 0) + if(_writeStream.isEmpty()) { _writeStream.writeBlob(IceInternal.Protocol.magic); IceInternal.Protocol.currentProtocol.__write(_writeStream); @@ -2227,22 +2249,28 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(_observer != null) { - observerStartWrite(_writeStream.pos()); + observerStartWrite(_writeStream.getBuffer()); } - if(_writeStream.pos() != _writeStream.size() && !_transceiver.write(_writeStream.getBuffer())) + + if(_writeStream.pos() != _writeStream.size()) { - scheduleTimeout(IceInternal.SocketOperation.Write, connectTimeout()); - _threadPool.update(this, operation, IceInternal.SocketOperation.Write); - return false; + int op = _transceiver.write(_writeStream.getBuffer()); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.update(this, operation, op); + return false; + } } + if(_observer != null) { - observerFinishWrite(_writeStream.pos()); + observerFinishWrite(_writeStream.getBuffer()); } } else // The client side has the passive role for connection validation. { - if(_readStream.size() == 0) + if(_readStream.isEmpty()) { _readStream.resize(IceInternal.Protocol.headerSize, true); _readStream.pos(0); @@ -2250,17 +2278,23 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne if(_observer != null) { - observerStartRead(_readStream.pos()); + observerStartRead(_readStream.getBuffer()); } - if(_readStream.pos() != _readStream.size() && !_transceiver.read(_readStream.getBuffer(), _hasMoreData)) + + if(_readStream.pos() != _readStream.size()) { - scheduleTimeout(IceInternal.SocketOperation.Read, connectTimeout()); - _threadPool.update(this, operation, IceInternal.SocketOperation.Read); - return false; + int op = _transceiver.read(_readStream.getBuffer(), _hasMoreData); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.update(this, operation, op); + return false; + } } + if(_observer != null) { - observerFinishRead(_readStream.pos()); + observerFinishRead(_readStream.getBuffer()); } assert(_readStream.pos() == IceInternal.Protocol.headerSize); @@ -2276,10 +2310,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _readProtocol.__read(_readStream); IceInternal.Protocol.checkSupportedProtocol(_readProtocol); - + _readProtocolEncoding.__read(_readStream); IceInternal.Protocol.checkSupportedProtocolEncoding(_readProtocolEncoding); - + byte messageType = _readStream.readByte(); if(messageType != IceInternal.Protocol.validateConnectionMsg) { @@ -2301,19 +2335,28 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne _writeStream.pos(0); _readStream.resize(IceInternal.Protocol.headerSize, true); - _readHeader = true; _readStream.pos(0); - + _readHeader = true; + return true; } - private java.util.List<OutgoingMessage> - sendNextMessage() + private int + sendNextMessage(java.util.List<OutgoingMessage> callbacks) { - assert(!_sendStreams.isEmpty()); - assert(!_writeStream.isEmpty() && _writeStream.pos() == _writeStream.size()); + if(_sendStreams.isEmpty()) + { + return IceInternal.SocketOperation.None; + } + else if(_state == StateClosingPending && _writeStream.pos() == _writeStream.size()) + { + // Message wasn't sent, empty the _writeStream, we're not going to send more data. + OutgoingMessage message = _sendStreams.getFirst(); + _writeStream.swap(message.stream); + return IceInternal.SocketOperation.None; + } - java.util.List<OutgoingMessage> callbacks = new java.util.LinkedList<OutgoingMessage>(); + assert(!_writeStream.isEmpty() && _writeStream.pos() == _writeStream.size()); try { while(true) @@ -2338,17 +2381,17 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } // - // If we are in the closed state, don't continue sending. + // If we are in the closed state or if the close is + // pending, don't continue sending. + // + // This can occur if parseMessage (called before + // sendNextMessage by message()) closes the connection. // - // The connection can be in the closed state if parseMessage - // (called before sendNextMessage by message()) closes the - // connection. - // - if(_state >= StateClosed) + if(_state >= StateClosingPending) { - return callbacks; + return IceInternal.SocketOperation.None; } - + // // Otherwise, prepare the next message stream for writing. // @@ -2375,45 +2418,50 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // if(_observer != null) { - observerStartWrite(_writeStream.pos()); + observerStartWrite(_writeStream.getBuffer()); } - if(_writeStream.pos() != _writeStream.size() && !_transceiver.write(_writeStream.getBuffer())) + if(_writeStream.pos() != _writeStream.size()) { - assert(!_writeStream.isEmpty()); - scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout()); - return callbacks; + int op = _transceiver.write(_writeStream.getBuffer()); + if(op != 0) + { + return op; + } } if(_observer != null) { - observerFinishWrite(_writeStream.pos()); + observerFinishWrite(_writeStream.getBuffer()); } } } catch(Ice.LocalException ex) { setState(StateClosed, ex); - return callbacks; + return IceInternal.SocketOperation.None; } - assert(_writeStream.isEmpty()); - _threadPool.unregister(this, IceInternal.SocketOperation.Write); - // - // If all the messages were sent and we are in the closing state, we schedule + // If all the messages were sent and we are in the closing state, we schedule // the close timeout to wait for the peer to close the connection. // if(_state == StateClosing) { - scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout()); + setState(StateClosingPending); + int op = _transceiver.closing(true, _exception); + if(op != 0) + { + return op; + } } - return callbacks; + return IceInternal.SocketOperation.None; } private int sendMessage(OutgoingMessage message) { assert(_state < StateClosed); + if(!_sendStreams.isEmpty()) { message.adopt(); @@ -2423,8 +2471,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // // Attempt to send the message without blocking. If the send blocks, we register - // the connection with the selector thread or we request the caller to call - // finishSendMessage() outside the synchronization. + // the connection with the selector thread. // assert(!message.prepared); @@ -2434,6 +2481,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne message.stream = doCompress(stream, message.compress); message.stream.prepareWrite(); message.prepared = true; + int op; if(message.outAsync != null) { @@ -2444,16 +2492,21 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels); } + // + // Send the message without blocking. + // if(_observer != null) { - observerStartWrite(message.stream.pos()); + observerStartWrite(message.stream.getBuffer()); } - if(_transceiver.write(message.stream.getBuffer())) + op = _transceiver.write(message.stream.getBuffer()); + if(op == 0) { if(_observer != null) { - observerFinishWrite(message.stream.pos()); + observerFinishWrite(message.stream.getBuffer()); } + int status = IceInternal.AsyncStatus.Sent; if(message.sent()) { @@ -2466,12 +2519,13 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } return status; } + message.adopt(); _writeStream.swap(message.stream); _sendStreams.addLast(message); - scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout()); - _threadPool.register(this, IceInternal.SocketOperation.Write); + scheduleTimeout(op); + _threadPool.register(this, op); return IceInternal.AsyncStatus.Queued; } @@ -2549,18 +2603,18 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne ConnectionCallback heartbeatCallback; } - private MessageInfo - parseMessage(IceInternal.BasicStream stream) + private int + parseMessage(MessageInfo info) { assert(_state > StateNotValidated && _state < StateClosed); - MessageInfo info = new MessageInfo(stream); - _readStream.swap(info.stream); _readStream.resize(IceInternal.Protocol.headerSize, true); _readStream.pos(0); _readHeader = true; + assert(info.stream.pos() == info.stream.size()); + // // Connection is validated on first message. This is only used by // setState() to check wether or not we can print a connection @@ -2569,15 +2623,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne // _validated = true; - assert(info.stream.pos() == info.stream.size()); - try { // // We don't need to check magic and version here. This has already // been done by the ThreadPool which provides us with the stream. // - assert(info.stream.pos() == info.stream.size()); info.stream.pos(8); byte messageType = info.stream.readByte(); info.compress = info.stream.readByte(); @@ -2611,14 +2662,24 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } else { - setState(StateClosed, new CloseConnectionException()); + setState(StateClosingPending, new CloseConnectionException()); + + // + // Notify the the transceiver of the graceful connection closure. + // + int op = _transceiver.closing(false, _exception); + if(op != 0) + { + return op; + } + setState(StateClosed); } break; } case IceInternal.Protocol.requestMsg: { - if(_state == StateClosing) + if(_state >= StateClosing) { IceInternal.TraceUtil.trace("received request during closing\n" + "(ignored by server, client will retry)", @@ -2638,7 +2699,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne case IceInternal.Protocol.requestBatchMsg: { - if(_state == StateClosing) + if(_state >= StateClosing) { IceInternal.TraceUtil.trace("received batch request during closing\n" + "(ignored by server, client will retry)", @@ -2715,7 +2776,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } - return info; + return _state == StateHolding ? IceInternal.SocketOperation.None : IceInternal.SocketOperation.Read; } private void @@ -2787,23 +2848,72 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } - private void - scheduleTimeout(int status, int timeout) + private void + scheduleTimeout(int status) { + int timeout; + if(_state < StateActive) + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideConnectTimeout) + { + timeout = defaultsAndOverrides.overrideConnectTimeoutValue; + } + else + { + timeout = _endpoint.timeout(); + } + } + else if(_state < StateClosingPending) + { + if(_readHeader) // No timeout for reading the header. + { + status &= ~IceInternal.SocketOperation.Read; + } + timeout = _endpoint.timeout(); + } + else + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideCloseTimeout) + { + timeout = defaultsAndOverrides.overrideCloseTimeoutValue; + } + else + { + timeout = _endpoint.timeout(); + } + } + if(timeout < 0) { return; } - if((status & IceInternal.SocketOperation.Read) != 0) + try { - _timer.schedule(_readTimeout, timeout); - _readTimeoutScheduled = true; + if((status & IceInternal.SocketOperation.Read) != 0) + { + if(_readTimeoutScheduled) + { + _timer.cancel(_readTimeout); + } + _timer.schedule(_readTimeout, timeout); + _readTimeoutScheduled = true; + } + if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0) + { + if(_writeTimeoutScheduled) + { + _timer.cancel(_writeTimeout); + } + _timer.schedule(_writeTimeout, timeout); + _writeTimeoutScheduled = true; + } } - if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0) + catch(Throwable ex) { - _timer.schedule(_writeTimeout, timeout); - _writeTimeoutScheduled = true; + assert(false); } } @@ -2823,34 +2933,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } - private int - connectTimeout() - { - IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); - if(defaultsAndOverrides.overrideConnectTimeout) - { - return defaultsAndOverrides.overrideConnectTimeoutValue; - } - else - { - return _endpoint.timeout(); - } - } - - private int - closeTimeout() - { - IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); - if(defaultsAndOverrides.overrideCloseTimeout) - { - return defaultsAndOverrides.overrideCloseTimeoutValue; - } - else - { - return _endpoint.timeout(); - } - } - private ConnectionInfo initConnectionInfo() { @@ -2875,7 +2957,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne { return connectionStateMap[state]; } - + private void warning(String msg, Exception ex) { @@ -2888,46 +2970,50 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } private void - observerStartRead(int pos) + observerStartRead(IceInternal.Buffer buf) { if(_readStreamPos >= 0) { - _observer.receivedBytes(pos - _readStreamPos); + assert(!buf.empty()); + _observer.receivedBytes(buf.b.position() - _readStreamPos); } - _readStreamPos = pos; + _readStreamPos = buf.empty() ? -1 : buf.b.position(); } private void - observerFinishRead(int pos) + observerFinishRead(IceInternal.Buffer buf) { if(_readStreamPos == -1) { return; } - assert(pos >= _readStreamPos); - _observer.receivedBytes(pos - _readStreamPos); + assert(buf.b.position() >= _readStreamPos); + _observer.receivedBytes(buf.b.position() - _readStreamPos); _readStreamPos = -1; } private void - observerStartWrite(int pos) + observerStartWrite(IceInternal.Buffer buf) { if(_writeStreamPos >= 0) { - _observer.sentBytes(pos - _writeStreamPos); + assert(!buf.empty()); + _observer.sentBytes(buf.b.position() - _writeStreamPos); } - _writeStreamPos = pos; + _writeStreamPos = buf.empty() ? -1 : buf.b.position(); } private void - observerFinishWrite(int pos) + observerFinishWrite(IceInternal.Buffer buf) { if(_writeStreamPos == -1) { return; } - assert(pos >= _writeStreamPos); - _observer.sentBytes(pos - _writeStreamPos); + if(buf.b.position() > _writeStreamPos) + { + _observer.sentBytes(buf.b.position() - _writeStreamPos); + } _writeStreamPos = -1; } @@ -3160,7 +3246,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne private boolean _readTimeoutScheduled; private StartCallback _startCallback = null; - private Ice.BooleanHolder _hasMoreData = new Ice.BooleanHolder(false); private final boolean _warn; private final boolean _warnUdp; @@ -3222,6 +3307,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne Ice.Instrumentation.ConnectionState.ConnectionStateActive, // StateActive Ice.Instrumentation.ConnectionState.ConnectionStateHolding, // StateHolding Ice.Instrumentation.ConnectionState.ConnectionStateClosing, // StateClosing + Ice.Instrumentation.ConnectionState.ConnectionStateClosing, // StateClosingPending Ice.Instrumentation.ConnectionState.ConnectionStateClosed, // StateClosed Ice.Instrumentation.ConnectionState.ConnectionStateClosed, // StateFinished }; diff --git a/java/src/IceInternal/Acceptor.java b/java/src/IceInternal/Acceptor.java index fb1f9f24b3d..0d883d6ef8b 100644 --- a/java/src/IceInternal/Acceptor.java +++ b/java/src/IceInternal/Acceptor.java @@ -15,5 +15,6 @@ public interface Acceptor void close(); void listen(); Transceiver accept(); + String protocol(); String toString(); } diff --git a/java/src/IceInternal/EndpointFactory.java b/java/src/IceInternal/EndpointFactory.java index aabdec78581..61425287f5c 100644 --- a/java/src/IceInternal/EndpointFactory.java +++ b/java/src/IceInternal/EndpointFactory.java @@ -13,7 +13,9 @@ public interface EndpointFactory { short type(); String protocol(); - EndpointI create(String str, boolean oaEndpoint); + EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint); EndpointI read(BasicStream s); void destroy(); + + EndpointFactory clone(ProtocolInstance instance); } diff --git a/java/src/IceInternal/EndpointFactoryManager.java b/java/src/IceInternal/EndpointFactoryManager.java index 94f61fbb873..64fd927c771 100644 --- a/java/src/IceInternal/EndpointFactoryManager.java +++ b/java/src/IceInternal/EndpointFactoryManager.java @@ -16,8 +16,7 @@ public final class EndpointFactoryManager _instance = instance; } - public synchronized void - add(EndpointFactory factory) + public synchronized void add(EndpointFactory factory) { for(int i = 0; i < _factories.size(); i++) { @@ -30,8 +29,7 @@ public final class EndpointFactoryManager _factories.add(factory); } - public synchronized EndpointFactory - get(short type) + public synchronized EndpointFactory get(short type) { for(int i = 0; i < _factories.size(); i++) { @@ -44,77 +42,101 @@ public final class EndpointFactoryManager return null; } - public synchronized EndpointI - create(String str, boolean oaEndpoint) + public synchronized EndpointI create(String str, boolean oaEndpoint) { - String s = str.trim(); - if(s.length() == 0) + String[] arr = IceUtilInternal.StringUtil.splitString(str, " \t\r\n"); + if(arr == null) { Ice.EndpointParseException e = new Ice.EndpointParseException(); - e.str = "value has no non-whitespace characters"; + e.str = "mismatched quote"; throw e; } - java.util.regex.Pattern p = java.util.regex.Pattern.compile("([ \t\n\r]+)|$"); - java.util.regex.Matcher m = p.matcher(s); - boolean b = m.find(); - assert(b); + if(arr.length == 0) + { + Ice.EndpointParseException e = new Ice.EndpointParseException(); + e.str = "value has no non-whitespace characters"; + throw e; + } - String protocol = s.substring(0, m.start()); + java.util.ArrayList<String> v = new java.util.ArrayList<String>(java.util.Arrays.asList(arr)); + String protocol = v.get(0); + v.remove(0); if(protocol.equals("default")) { protocol = _instance.defaultsAndOverrides().defaultProtocol; } + EndpointFactory factory = null; + for(int i = 0; i < _factories.size(); i++) { EndpointFactory f = _factories.get(i); if(f.protocol().equals(protocol)) { - return f.create(s.substring(m.end()), oaEndpoint); - - // Code below left in place for debugging. - - /* - EndpointI e = f.create(s.substring(m.end()), oaEndpoint); - BasicStream bs = new BasicStream(_instance, true, false); - e.streamWrite(bs); - java.nio.ByteBuffer buf = bs.getBuffer(); - buf.position(0); - short type = bs.readShort(); - EndpointI ue = new IceInternal.OpaqueEndpointI(type, bs); - System.err.println("Normal: " + e); - System.err.println("Opaque: " + ue); - return e; - */ + factory = f; } } + if(factory != null) + { + EndpointI e = factory.create(v, oaEndpoint); + if(!v.isEmpty()) + { + Ice.EndpointParseException ex = new Ice.EndpointParseException(); + ex.str = "unrecognized argument `" + v.get(0) + "' in endpoint `" + str + "'"; + throw ex; + } + return e; + + // Code below left in place for debugging. + + /* + EndpointI e = f.create(s.substring(m.end()), oaEndpoint); + BasicStream bs = new BasicStream(_instance, true, false); + e.streamWrite(bs); + java.nio.ByteBuffer buf = bs.getBuffer(); + buf.position(0); + short type = bs.readShort(); + EndpointI ue = new IceInternal.OpaqueEndpointI(type, bs); + System.err.println("Normal: " + e); + System.err.println("Opaque: " + ue); + return e; + */ + } + // // If the stringified endpoint is opaque, create an unknown endpoint, // then see whether the type matches one of the known endpoints. // if(protocol.equals("opaque")) { - EndpointI ue = new OpaqueEndpointI(s.substring(m.end())); - for(int i = 0; i < _factories.size(); i++) + EndpointI ue = new OpaqueEndpointI(v); + if(!v.isEmpty()) + { + Ice.EndpointParseException ex = new Ice.EndpointParseException(); + ex.str = "unrecognized argument `" + v.get(0) + "' in endpoint `" + str + "'"; + throw ex; + } + factory = get(ue.type()); + if(factory != null) { - EndpointFactory f = _factories.get(i); - if(f.type() == ue.type()) - { - // - // Make a temporary stream, write the opaque endpoint data into the stream, - // and ask the factory to read the endpoint data from that stream to create - // the actual endpoint. - // - BasicStream bs = new BasicStream(_instance, Protocol.currentProtocolEncoding, true, false); - ue.streamWrite(bs); - Buffer buf = bs.getBuffer(); - buf.b.position(0); - bs.readShort(); // type - return f.read(bs); - } + // + // Make a temporary stream, write the opaque endpoint data into the stream, + // and ask the factory to read the endpoint data from that stream to create + // the actual endpoint. + // + BasicStream bs = new BasicStream(_instance, Protocol.currentProtocolEncoding, true, false); + bs.writeShort(ue.type()); + ue.streamWrite(bs); + Buffer buf = bs.getBuffer(); + buf.b.position(0); + bs.readShort(); // type + bs.startReadEncaps(); + EndpointI e = factory.read(bs); + bs.endReadEncaps(); + return e; } return ue; // Endpoint is opaque, but we don't have a factory for its type. } @@ -122,23 +144,30 @@ public final class EndpointFactoryManager return null; } - public synchronized EndpointI - read(BasicStream s) + public synchronized EndpointI read(BasicStream s) { short type = s.readShort(); - for(int i = 0; i < _factories.size(); i++) + + EndpointFactory factory = get(type); + EndpointI e = null; + + s.startReadEncaps(); + + if(factory != null) { - EndpointFactory f = _factories.get(i); - if(f.type() == type) - { - return f.read(s); - } + e = factory.read(s); } - return new OpaqueEndpointI(type, s); + else + { + e = new OpaqueEndpointI(type, s); + } + + s.endReadEncaps(); + + return e; } - void - destroy() + void destroy() { for(int i = 0; i < _factories.size(); i++) { diff --git a/java/src/IceInternal/EndpointHostResolver.java b/java/src/IceInternal/EndpointHostResolver.java index 43d646c6fb9..898055c102b 100644 --- a/java/src/IceInternal/EndpointHostResolver.java +++ b/java/src/IceInternal/EndpointHostResolver.java @@ -34,8 +34,8 @@ public class EndpointHostResolver } } - public java.util.List<Connector> - resolve(String host, int port, Ice.EndpointSelectionType selType, EndpointI endpoint) + public java.util.List<Connector> resolve(String host, int port, Ice.EndpointSelectionType selType, + IPEndpointI endpoint) { // // Try to get the addresses without DNS lookup. If this doesn't @@ -92,8 +92,8 @@ public class EndpointHostResolver return connectors; } - synchronized public void - resolve(String host, int port, Ice.EndpointSelectionType selType, EndpointI endpoint, EndpointI_connectors callback) + synchronized public void resolve(String host, int port, Ice.EndpointSelectionType selType, IPEndpointI endpoint, + EndpointI_connectors callback) { // // TODO: Optimize to avoid the lookup if the given host is a textual IPv4 or IPv6 @@ -124,16 +124,14 @@ public class EndpointHostResolver notify(); } - synchronized public void - destroy() + synchronized public void destroy() { assert(!_destroyed); _destroyed = true; notify(); } - public void - joinWithThread() + public void joinWithThread() { if(_thread != null) { @@ -151,8 +149,7 @@ public class EndpointHostResolver } } - public void - run() + public void run() { while(true) { @@ -236,8 +233,7 @@ public class EndpointHostResolver _queue.clear(); } - synchronized public void - updateObserver() + synchronized public void updateObserver() { Ice.Instrumentation.CommunicatorObserver obsv = _instance.getObserver(); if(obsv != null) @@ -258,7 +254,7 @@ public class EndpointHostResolver String host; int port; Ice.EndpointSelectionType selType; - EndpointI endpoint; + IPEndpointI endpoint; EndpointI_connectors callback; Ice.Instrumentation.Observer observer; } @@ -282,8 +278,7 @@ public class EndpointHostResolver setName(threadName + "Ice.HostResolver"); } - public void - run() + public void run() { try { diff --git a/java/src/IceInternal/EndpointI.java b/java/src/IceInternal/EndpointI.java index 99888b7ec85..6d91760b570 100644 --- a/java/src/IceInternal/EndpointI.java +++ b/java/src/IceInternal/EndpointI.java @@ -11,19 +11,21 @@ package IceInternal; abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<EndpointI> { - public EndpointI(String connectionId) - { - _connectionId = connectionId; - } - - public EndpointI() + public String toString() { + return _toString(); } - public String - toString() + public String _toString() { - return _toString(); + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + return protocol() + options(); } // @@ -35,12 +37,12 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En // Return the endpoint type. // public abstract short type(); - + // // Return the protocol name. // public abstract String protocol(); - + // // Return the timeout for the endpoint in milliseconds. 0 means // non-blocking, -1 means no timeout. @@ -55,6 +57,11 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En public abstract EndpointI timeout(int t); // + // Return the connection ID + // + public abstract String connectionId(); + + // // Return a new endpoint with a different connection id. // public abstract EndpointI connectionId(String connectionId); @@ -64,7 +71,7 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En // otherwise. // public abstract boolean compress(); - + // // Return a new endpoint with a different compression value, // provided that compression is supported by the @@ -83,14 +90,6 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En public abstract boolean secure(); // - // Return the connection ID - // - public String connectionId() - { - return _connectionId; - } - - // // Return a server side transceiver for this endpoint, or null if a // transceiver can only be created by an acceptor. In case a // transceiver is created, this operation also returns a new @@ -126,15 +125,53 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En // public abstract boolean equivalent(EndpointI endpoint); - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) + public abstract String options(); + + public void initWithOptions(java.util.ArrayList<String> args) { - // - // This method must be extended by endpoints which use the EndpointHostResolver to create - // connectors from IP addresses. - // - assert(false); - return null; + java.util.ArrayList<String> unknown = new java.util.ArrayList<String>(); + + String str = "`" + protocol() + " "; + for(String p : args) + { + if(IceUtilInternal.StringUtil.findFirstOf(p, " \t\n\r") != -1) + { + str += " \"" + p + "\""; + } + else + { + str += " " + p; + } + } + str += "'"; + + for(int n = 0; n < args.size(); ++n) + { + String option = args.get(n); + if(option.length() < 2 || option.charAt(0) != '-') + { + unknown.add(option); + continue; + } + + String argument = null; + if(n + 1 < args.size() && args.get(n + 1).charAt(0) != '-') + { + argument = args.get(++n); + } + + if(!checkOption(option, argument, str)) + { + unknown.add(option); + if(argument != null) + { + unknown.add(argument); + } + } + } + + args.clear(); + args.addAll(unknown); } // @@ -149,15 +186,9 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En return compareTo((EndpointI)obj) == 0; } - public int compareTo(EndpointI p) // From java.lang.Comparable. + protected boolean checkOption(String option, String argument, String endpoint) { - if(!_connectionId.equals(p._connectionId)) - { - return _connectionId.compareTo(p._connectionId); - } - - return 0; + // Must be overridden to check for options. + return false; } - - protected String _connectionId = ""; } diff --git a/java/src/IceInternal/EventHandler.java b/java/src/IceInternal/EventHandler.java index 0b8b0efaef8..5dc747b2118 100644 --- a/java/src/IceInternal/EventHandler.java +++ b/java/src/IceInternal/EventHandler.java @@ -31,17 +31,8 @@ public abstract class EventHandler // abstract public java.nio.channels.SelectableChannel fd(); - // - // In Java, it's possible that the transceiver reads more data than what was - // really asked. If this is the case, hasMoreData() returns true and the handler - // read() method should be called again (without doing a select()). This is - // handled by the Selector class (it adds the handler to a separate list of - // handlers if this method returns true.) - // - abstract public boolean hasMoreData(); - - int _disabled = 0; - int _registered = 0; - int _ready = 0; - java.nio.channels.SelectionKey _key = null; + public int _disabled = 0; + public Ice.BooleanHolder _hasMoreData = new Ice.BooleanHolder(false); + public int _registered = 0; + public java.nio.channels.SelectionKey _key = null; } diff --git a/java/src/IceInternal/EventHandlerOpPair.java b/java/src/IceInternal/EventHandlerOpPair.java new file mode 100644 index 00000000000..43325ecb4f5 --- /dev/null +++ b/java/src/IceInternal/EventHandlerOpPair.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class EventHandlerOpPair +{ + EventHandlerOpPair(EventHandler handler, int op) + { + this.handler = handler; + this.op = op; + } + + EventHandler handler; + int op; +} diff --git a/java/src/IceInternal/IPEndpointI.java b/java/src/IceInternal/IPEndpointI.java new file mode 100644 index 00000000000..7c860106754 --- /dev/null +++ b/java/src/IceInternal/IPEndpointI.java @@ -0,0 +1,327 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class IPEndpointI extends EndpointI +{ + protected IPEndpointI(ProtocolInstance instance, String host, int port, String connectionId) + { + _instance = instance; + _host = host; + _port = port; + _connectionId = connectionId; + _hashInitialized = false; + } + + protected IPEndpointI(ProtocolInstance instance) + { + _instance = instance; + _host = null; + _port = 0; + _connectionId = ""; + _hashInitialized = false; + } + + protected IPEndpointI(ProtocolInstance instance, BasicStream s) + { + _instance = instance; + _host = s.readString(); + _port = s.readInt(); + _connectionId = ""; + _hashInitialized = false; + } + + public void streamWrite(BasicStream s) + { + s.startWriteEncaps(); + streamWriteImpl(s); + s.endWriteEncaps(); + } + + public Ice.EndpointInfo getInfo() + { + Ice.IPEndpointInfo info = new Ice.IPEndpointInfo() + { + public short type() + { + return IPEndpointI.this.type(); + } + + public boolean datagram() + { + return IPEndpointI.this.datagram(); + } + + public boolean secure() + { + return IPEndpointI.this.secure(); + } + }; + fillEndpointInfo(info); + return info; + } + + public short type() + { + return _instance.type(); + } + + public String protocol() + { + return _instance.protocol(); + } + + public String connectionId() + { + return _connectionId; + } + + public EndpointI connectionId(String connectionId) + { + if(connectionId.equals(_connectionId)) + { + return this; + } + else + { + return createEndpoint(_host, _port, connectionId); + } + } + + public java.util.List<Connector> connectors(Ice.EndpointSelectionType selType) + { + return _instance.resolve(_host, _port, selType, this); + } + + public void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) + { + _instance.resolve(_host, _port, selType, this, callback); + } + + public java.util.List<EndpointI> expand() + { + java.util.List<EndpointI> endps = new java.util.ArrayList<EndpointI>(); + java.util.List<String> hosts = Network.getHostsForEndpointExpand(_host, _instance.protocolSupport(), false); + if(hosts == null || hosts.isEmpty()) + { + endps.add(this); + } + else + { + for(String h : hosts) + { + endps.add(createEndpoint(h, _port, _connectionId)); + } + } + return endps; + } + + public boolean equivalent(EndpointI endpoint) + { + if(!(endpoint instanceof IPEndpointI)) + { + return false; + } + IPEndpointI ipEndpointI = (IPEndpointI)endpoint; + return ipEndpointI.type() == type() && ipEndpointI._host.equals(_host) && ipEndpointI._port == _port; + } + + public java.util.List<Connector> connectors(java.util.List<java.net.InetSocketAddress> addresses, + NetworkProxy proxy) + { + java.util.List<Connector> connectors = new java.util.ArrayList<Connector>(); + for(java.net.InetSocketAddress p : addresses) + { + connectors.add(createConnector(p, proxy)); + } + return connectors; + } + + synchronized public int hashCode() + { + if(!_hashInitialized) + { + _hashValue = 5381; + _hashValue = HashUtil.hashAdd(_hashValue, type()); + _hashValue = hashInit(_hashValue); + } + return _hashValue; + } + + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = ""; + + if(_host != null && _host.length() > 0) + { + s += " -h "; + boolean addQuote = _host.indexOf(':') != -1; + if(addQuote) + { + s += "\""; + } + s += _host; + if(addQuote) + { + s += "\""; + } + } + + s += " -p " + _port; + + return s; + } + + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof IPEndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + IPEndpointI p = (IPEndpointI)obj; + if(this == p) + { + return 0; + } + + int v = _host.compareTo(p._host); + if(v != 0) + { + return v; + } + + if(_port < p._port) + { + return -1; + } + else if(p._port < _port) + { + return 1; + } + + return _connectionId.compareTo(p._connectionId); + } + + public String host() + { + return _host; + } + + public int port() + { + return _port; + } + + protected void streamWriteImpl(BasicStream s) + { + s.writeString(_host); + s.writeInt(_port); + } + + protected int hashInit(int h) + { + h = HashUtil.hashAdd(h, _host); + h = HashUtil.hashAdd(h, _port); + h = HashUtil.hashAdd(h, _connectionId); + return h; + } + + protected void fillEndpointInfo(Ice.IPEndpointInfo info) + { + info.host = _host; + info.port = _port; + } + + public void initWithOptions(java.util.ArrayList<String> args, boolean oaEndpoint) + { + super.initWithOptions(args); + + if(_host == null || _host.length() == 0) + { + _host = _instance.defaultHost(); + } + else if(_host.equals("*")) + { + if(oaEndpoint) + { + _host = ""; + } + else + { + throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `" + toString() + "'"); + } + } + } + + protected boolean checkOption(String option, String argument, String endpoint) + { + switch(option.charAt(1)) + { + case 'h': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -h option in endpoint " + endpoint); + } + _host = argument; + return true; + } + + case 'p': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -p option in endpoint " + endpoint); + } + + try + { + _port = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid port value `" + argument + + "' in endpoint " + endpoint); + } + + if(_port < 0 || _port > 65535) + { + throw new Ice.EndpointParseException("port value `" + argument + + "' out of range in endpoint " + endpoint); + } + + return true; + } + + default: + { + return false; + } + } + } + + protected abstract Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy); + protected abstract IPEndpointI createEndpoint(String host, int port, String connectionId); + + protected ProtocolInstance _instance; + protected String _host; + protected int _port; + protected String _connectionId; + private boolean _hashInitialized; + private int _hashValue; +} diff --git a/java/src/IceInternal/IncomingConnectionFactory.java b/java/src/IceInternal/IncomingConnectionFactory.java index 54a9076fde7..59c63fb3b2a 100644 --- a/java/src/IceInternal/IncomingConnectionFactory.java +++ b/java/src/IceInternal/IncomingConnectionFactory.java @@ -308,13 +308,6 @@ public final class IncomingConnectionFactory extends EventHandler implements Ice return _acceptor.fd(); } - public boolean - hasMoreData() - { - assert(_acceptor != null); - return false; - } - // // Operations from ConnectionI.StartCallback // diff --git a/java/src/IceInternal/Instance.java b/java/src/IceInternal/Instance.java index be091ba60e7..0fa8d7e4422 100644 --- a/java/src/IceInternal/Instance.java +++ b/java/src/IceInternal/Instance.java @@ -782,9 +782,11 @@ public final class Instance } _endpointFactoryManager = new EndpointFactoryManager(this); - EndpointFactory tcpEndpointFactory = new TcpEndpointFactory(this); + ProtocolInstance tcpProtocolInstance = new ProtocolInstance(this, Ice.TCPEndpointType.value, "tcp"); + EndpointFactory tcpEndpointFactory = new TcpEndpointFactory(tcpProtocolInstance); _endpointFactoryManager.add(tcpEndpointFactory); - EndpointFactory udpEndpointFactory = new UdpEndpointFactory(this); + ProtocolInstance udpProtocolInstance = new ProtocolInstance(this, Ice.UDPEndpointType.value, "udp"); + EndpointFactory udpEndpointFactory = new UdpEndpointFactory(udpProtocolInstance); _endpointFactoryManager.add(udpEndpointFactory); _pluginManager = new Ice.PluginManagerI(communicator, this); diff --git a/java/src/IceInternal/OpaqueEndpointI.java b/java/src/IceInternal/OpaqueEndpointI.java index 89c4305cbd0..70e3559a82b 100644 --- a/java/src/IceInternal/OpaqueEndpointI.java +++ b/java/src/IceInternal/OpaqueEndpointI.java @@ -11,179 +11,50 @@ package IceInternal; final class OpaqueEndpointI extends EndpointI { - public - OpaqueEndpointI(String str) + public OpaqueEndpointI(java.util.ArrayList<String> args) { - super(""); - + _type = -1; _rawEncoding = Ice.Util.Encoding_1_0; + _rawBytes = new byte[0]; - int topt = 0; - int vopt = 0; + initWithOptions(args); - String[] arr = str.split("[ \t\n\r]+"); - int i = 0; - while(i < arr.length) + if(_type < 0) { - if(arr[i].length() == 0) - { - i++; - continue; - } - - String option = arr[i++]; - if(option.length() != 2 || option.charAt(0) != '-') - { - throw new Ice.EndpointParseException("expected an endpoint option but found `" + option + - "' in endpoint `opaque " + str + "'"); - } - - String argument = null; - if(i < arr.length && arr[i].charAt(0) != '-') - { - argument = arr[i++]; - } - - switch(option.charAt(1)) - { - case 't': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -t option in endpoint `opaque " - + str + "'"); - } - - int t; - try - { - t = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid type value `" + argument + - "' in endpoint `opaque " + str + "'"); - } - - if(t < 0 || t > 65535) - { - throw new Ice.EndpointParseException("type value `" + argument + - "' out of range in endpoint `opaque " + str + "'"); - } - - _type = (short)t; - ++topt; - if(topt > 1) - { - throw new Ice.EndpointParseException("multiple -t options in endpoint `opaque " + str + "'"); - } - break; - } - - case 'e': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -e option in endpoint `opaque " - + str + "'"); - } - - try - { - _rawEncoding = Ice.Util.stringToEncodingVersion(argument); - } - catch(Ice.VersionParseException e) - { - throw new Ice.EndpointParseException("invalid encoding version `" + argument + - "' in endpoint `opaque " + str + "':\n" + e.str); - } - break; - } - - case 'v': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -v option in endpoint `opaque " - + str + "'"); - } - - for(int j = 0; j < argument.length(); ++j) - { - if(!IceUtilInternal.Base64.isBase64(argument.charAt(j))) - { - throw new Ice.EndpointParseException("invalid base64 character `" + argument.charAt(j) + - "' (ordinal " + ((int)argument.charAt(j)) + - ") in endpoint `opaque " + str + "'"); - } - } - _rawBytes = IceUtilInternal.Base64.decode(argument); - ++vopt; - if(vopt > 1) - { - throw new Ice.EndpointParseException("multiple -v options in endpoint `opaque " + str + "'"); - } - break; - } - - default: - { - throw new Ice.EndpointParseException("invalid option `" + option + "' in endpoint `opaque " + - str + "'"); - } - } + throw new Ice.EndpointParseException("no -t option in endpoint " + toString()); } - - if(topt != 1) + if(_rawBytes.length == 0) { - throw new Ice.EndpointParseException("no -t option in endpoint `opaque " + str + "'"); - } - if(vopt != 1) - { - throw new Ice.EndpointParseException("no -v option in endpoint `opaque " + str + "'"); + throw new Ice.EndpointParseException("no -v option in endpoint " + toString()); } + calcHashValue(); } - public - OpaqueEndpointI(short type, BasicStream s) + public OpaqueEndpointI(short type, BasicStream s) { - super(""); _type = type; - _rawEncoding = s.startReadEncaps(); + _rawEncoding = s.getReadEncoding(); int sz = s.getReadEncapsSize(); _rawBytes = s.readBlob(sz); - s.endReadEncaps(); + calcHashValue(); } // // Marshal the endpoint // - public void - streamWrite(BasicStream s) + public void streamWrite(BasicStream s) { - s.writeShort(_type); s.startWriteEncaps(_rawEncoding, Ice.FormatType.DefaultFormat); s.writeBlob(_rawBytes); s.endWriteEncaps(); } // - // Convert the endpoint to its string form - // - public String - _toString() - { - String val = IceUtilInternal.Base64.encode(_rawBytes); - return "opaque -t " + _type + " -e " + Ice.Util.encodingVersionToString(_rawEncoding) + " -v " + val; - } - - // // Return the endpoint information. // - public Ice.EndpointInfo - getInfo() + public Ice.EndpointInfo getInfo() { return new Ice.OpaqueEndpointInfo(-1, false, _rawEncoding, _rawBytes) { @@ -191,12 +62,12 @@ final class OpaqueEndpointI extends EndpointI { return _type; } - + public boolean datagram() { return false; } - + public boolean secure() { return false; @@ -207,8 +78,7 @@ final class OpaqueEndpointI extends EndpointI // // Return the endpoint type // - public short - type() + public short type() { return _type; } @@ -216,8 +86,7 @@ final class OpaqueEndpointI extends EndpointI // // Return the protocol name // - public String - protocol() + public String protocol() { return "opaque"; } @@ -226,38 +95,39 @@ final class OpaqueEndpointI extends EndpointI // Return the timeout for the endpoint in milliseconds. 0 means // non-blocking, -1 means no timeout. // - public int - timeout() + public int timeout() { return -1; } - + // // Return a new endpoint with a different timeout value, provided // that timeouts are supported by the endpoint. Otherwise the same // endpoint is returned. // - public EndpointI - timeout(int t) + public EndpointI timeout(int t) { return this; } + public String connectionId() + { + return ""; + } + // // Return a new endpoint with a different connection id. // - public EndpointI - connectionId(String connectionId) + public EndpointI connectionId(String connectionId) { return this; } - + // // Return true if the endpoints support bzip2 compress, or false // otherwise. // - public boolean - compress() + public boolean compress() { return false; } @@ -267,8 +137,7 @@ final class OpaqueEndpointI extends EndpointI // provided that compression is supported by the // endpoint. Otherwise the same endpoint is returned. // - public EndpointI - compress(boolean compress) + public EndpointI compress(boolean compress) { return this; } @@ -276,17 +145,15 @@ final class OpaqueEndpointI extends EndpointI // // Return true if the endpoint is datagram-based. // - public boolean - datagram() + public boolean datagram() { return false; } - + // // Return true if the endpoint is secure. // - public boolean - secure() + public boolean secure() { return false; } @@ -294,8 +161,7 @@ final class OpaqueEndpointI extends EndpointI // // Get the encoded endpoint. // - public byte[] - rawBytes() + public byte[] rawBytes() { return _rawBytes; } @@ -307,8 +173,7 @@ final class OpaqueEndpointI extends EndpointI // "effective" endpoint, which might differ from this endpoint, // for example, if a dynamic port number is assigned. // - public Transceiver - transceiver(EndpointIHolder endpoint) + public Transceiver transceiver(EndpointIHolder endpoint) { endpoint.value = null; return null; @@ -318,14 +183,12 @@ final class OpaqueEndpointI extends EndpointI // Return connectors for this endpoint, or empty list if no connector // is available. // - public java.util.List<Connector> - connectors(Ice.EndpointSelectionType selType) + public java.util.List<Connector> connectors(Ice.EndpointSelectionType selType) { return new java.util.ArrayList<Connector>(); } - public void - connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) + public void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) { callback.connectors(new java.util.ArrayList<Connector>()); } @@ -337,8 +200,7 @@ final class OpaqueEndpointI extends EndpointI // from this endpoint, for example, if a dynamic port number is // assigned. // - public Acceptor - acceptor(EndpointIHolder endpoint, String adapterName) + public Acceptor acceptor(EndpointIHolder endpoint, String adapterName) { endpoint.value = null; return null; @@ -349,8 +211,7 @@ final class OpaqueEndpointI extends EndpointI // host if listening on INADDR_ANY on server side or if no host // was specified on client side. // - public java.util.List<EndpointI> - expand() + public java.util.List<EndpointI> expand() { java.util.List<EndpointI> endps = new java.util.ArrayList<EndpointI>(); endps.add(this); @@ -360,23 +221,35 @@ final class OpaqueEndpointI extends EndpointI // // Check whether the endpoint is equivalent to another one. // - public boolean - equivalent(EndpointI endpoint) + public boolean equivalent(EndpointI endpoint) { return false; } - public int - hashCode() + public int hashCode() { return _hashCode; } - + + public String options() + { + String s = ""; + if(_type > -1) + { + s += " -t " + _type; + } + s += " -e " + Ice.Util.encodingVersionToString(_rawEncoding); + if(_rawBytes.length > 0) + { + s += " -v " + IceUtilInternal.Base64.encode(_rawBytes); + } + return s; + } + // // Compare endpoints for sorting purposes // - public int - compareTo(EndpointI obj) // From java.lang.Comparable + public int compareTo(EndpointI obj) // From java.lang.Comparable { if(!(obj instanceof OpaqueEndpointI)) { @@ -439,8 +312,92 @@ final class OpaqueEndpointI extends EndpointI return 0; } - private void - calcHashValue() + protected boolean checkOption(String option, String argument, String endpoint) + { + switch(option.charAt(1)) + { + case 't': + { + if(_type > -1) + { + throw new Ice.EndpointParseException("multiple -t options in endpoint " + endpoint); + } + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + int t; + try + { + t = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid type value `" + argument + "' in endpoint " + endpoint); + } + + if(t < 0 || t > 65535) + { + throw new Ice.EndpointParseException("type value `" + argument + "' out of range in endpoint " + + endpoint); + } + + _type = (short)t; + return true; + } + + case 'v': + { + if(_rawBytes.length > 0) + { + throw new Ice.EndpointParseException("multiple -v options in endpoint " + endpoint); + } + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -v option in endpoint " + endpoint); + } + + for(int j = 0; j < argument.length(); ++j) + { + if(!IceUtilInternal.Base64.isBase64(argument.charAt(j))) + { + throw new Ice.EndpointParseException("invalid base64 character `" + argument.charAt(j) + + "' (ordinal " + ((int)argument.charAt(j)) + + ") in endpoint " + endpoint); + } + } + _rawBytes = IceUtilInternal.Base64.decode(argument); + return true; + } + + case 'e': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -e option in endpoint " + endpoint); + } + + try + { + _rawEncoding = Ice.Util.stringToEncodingVersion(argument); + } + catch(Ice.VersionParseException e) + { + throw new Ice.EndpointParseException("invalid encoding version `" + argument + + "' in endpoint " + endpoint + ":\n" + e.str); + } + return true; + } + + default: + { + return false; + } + } + } + + private void calcHashValue() { int h = 5381; h = IceInternal.HashUtil.hashAdd(h, _type); diff --git a/java/src/IceInternal/OutgoingConnectionFactory.java b/java/src/IceInternal/OutgoingConnectionFactory.java index f4822753730..53a1abbfc90 100644 --- a/java/src/IceInternal/OutgoingConnectionFactory.java +++ b/java/src/IceInternal/OutgoingConnectionFactory.java @@ -28,6 +28,7 @@ public final class OutgoingConnectionFactory list.add(value); } + /* public void removeElementWithValue(K key, V value) { @@ -39,6 +40,20 @@ public final class OutgoingConnectionFactory this.remove(key); } } + */ + + public boolean + removeElementWithValue(K key, V value) + { + java.util.List<V> list = this.get(key); + assert(list != null); + boolean v = list.remove(value); + if(list.isEmpty()) + { + this.remove(key); + } + return v; + } }; interface CreateConnectionCallback diff --git a/java/src/IceInternal/ProtocolInstance.java b/java/src/IceInternal/ProtocolInstance.java new file mode 100644 index 00000000000..ee0b9074277 --- /dev/null +++ b/java/src/IceInternal/ProtocolInstance.java @@ -0,0 +1,114 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProtocolInstance +{ + public ProtocolInstance(Ice.Communicator communicator, short type, String protocol) + { + _instance = Util.getInstance(communicator); + _traceLevel = _instance.traceLevels().network; + _traceCategory = _instance.traceLevels().networkCat; + _logger = _instance.initializationData().logger; + _properties = _instance.initializationData().properties; + _type = type; + _protocol = protocol; + } + + public int traceLevel() + { + return _traceLevel; + } + + public String traceCategory() + { + return _traceCategory; + } + + public Ice.Logger logger() + { + return _logger; + } + + public String protocol() + { + return _protocol; + } + + public short type() + { + return _type; + } + + public Ice.Properties properties() + { + return _properties; + } + + public boolean preferIPv6() + { + return _instance.preferIPv6(); + } + + public int protocolSupport() + { + return _instance.protocolSupport(); + } + + public String defaultHost() + { + return _instance.defaultsAndOverrides().defaultHost; + } + + public Ice.EncodingVersion defaultEncoding() + { + return _instance.defaultsAndOverrides().defaultEncoding; + } + + public NetworkProxy networkProxy() + { + return _instance.networkProxy(); + } + + public int messageSizeMax() + { + return _instance.messageSizeMax(); + } + + public java.util.List<Connector> resolve(String host, int port, Ice.EndpointSelectionType type, IPEndpointI endpt) + { + return _instance.endpointHostResolver().resolve(host, port, type, endpt); + } + + public void resolve(String host, int port, Ice.EndpointSelectionType type, IPEndpointI endpt, + EndpointI_connectors callback) + { + _instance.endpointHostResolver().resolve(host, port, type, endpt, callback); + } + + ProtocolInstance(Instance instance, short type, String protocol) + { + _instance = instance; + _traceLevel = _instance.traceLevels().network; + _traceCategory = _instance.traceLevels().networkCat; + _logger = _instance.initializationData().logger; + _properties = _instance.initializationData().properties; + _type = type; + _protocol = protocol; + } + + protected Instance _instance; + protected int _traceLevel; + protected String _traceCategory; + protected Ice.Logger _logger; + protected Ice.Properties _properties; + protected String _protocol; + protected short _type; +} diff --git a/java/src/IceInternal/ProtocolPluginFacade.java b/java/src/IceInternal/ProtocolPluginFacade.java index c1834c1ae92..07080ea383e 100644 --- a/java/src/IceInternal/ProtocolPluginFacade.java +++ b/java/src/IceInternal/ProtocolPluginFacade.java @@ -18,42 +18,6 @@ public interface ProtocolPluginFacade Ice.Communicator getCommunicator(); // - // Get the endpoint host resolver. - // - IceInternal.EndpointHostResolver getEndpointHostResolver(); - - // - // Get the protocol support. - // - int getProtocolSupport(); - - // - // Get the protocol support. - // - boolean getPreferIPv6(); - - // - // Get the network proxy. - // - NetworkProxy getNetworkProxy(); - - // - // Get the default encoding to be used in endpoints. - // - Ice.EncodingVersion getDefaultEncoding(); - - // - // Get the default hostname to be used in endpoints. - // - String getDefaultHost(); - - // - // Get the network trace level and category name. - // - int getNetworkTraceLevel(); - String getNetworkTraceCategory(); - - // // Register an EndpointFactory. // void addEndpointFactory(EndpointFactory factory); diff --git a/java/src/IceInternal/ProtocolPluginFacadeI.java b/java/src/IceInternal/ProtocolPluginFacadeI.java index 0c51675b1e0..d4213bba8b8 100644 --- a/java/src/IceInternal/ProtocolPluginFacadeI.java +++ b/java/src/IceInternal/ProtocolPluginFacadeI.java @@ -11,8 +11,7 @@ package IceInternal; public class ProtocolPluginFacadeI implements ProtocolPluginFacade { - public - ProtocolPluginFacadeI(Ice.Communicator communicator) + public ProtocolPluginFacadeI(Ice.Communicator communicator) { _communicator = communicator; _instance = Util.getInstance(communicator); @@ -22,82 +21,15 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade // Get the Communicator instance with which this facade is // associated. // - public Ice.Communicator - getCommunicator() + public Ice.Communicator getCommunicator() { return _communicator; } // - // Get the endpoint host resolver. - // - public EndpointHostResolver - getEndpointHostResolver() - { - return _instance.endpointHostResolver(); - } - - // - // Get the protocol support. - // - public int - getProtocolSupport() - { - return _instance.protocolSupport(); - } - - public boolean - getPreferIPv6() - { - return _instance.preferIPv6(); - } - - // - // Get the network proxy. - // - public NetworkProxy getNetworkProxy() - { - return _instance.networkProxy(); - } - - // - // Get the default encoding to be used in endpoints. - // - public Ice.EncodingVersion - getDefaultEncoding() - { - return _instance.defaultsAndOverrides().defaultEncoding; - } - - // - // Get the default hostname to be used in endpoints. - // - public String - getDefaultHost() - { - return _instance.defaultsAndOverrides().defaultHost; - } - - // - // Get the network trace level and category name. - // - public int - getNetworkTraceLevel() - { - return _instance.traceLevels().network; - } - - public String - getNetworkTraceCategory() - { - return _instance.traceLevels().networkCat; - } - - // // Register an EndpointFactory. // - public void - addEndpointFactory(EndpointFactory factory) + public void addEndpointFactory(EndpointFactory factory) { _instance.endpointFactoryManager().add(factory); } @@ -105,8 +37,7 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade // // Register an EndpointFactory. // - public EndpointFactory - getEndpointFactory(short type) + public EndpointFactory getEndpointFactory(short type) { return _instance.endpointFactoryManager().get(type); } @@ -114,8 +45,7 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade // // Look up a Java class by name. // - public Class<?> - findClass(String className) + public Class<?> findClass(String className) { return _instance.findClass(className); } diff --git a/java/src/IceInternal/RoutableReference.java b/java/src/IceInternal/RoutableReference.java index 563cbb90297..de9d002f8b4 100644 --- a/java/src/IceInternal/RoutableReference.java +++ b/java/src/IceInternal/RoutableReference.java @@ -283,6 +283,7 @@ public class RoutableReference extends Reference assert(_adapterId.length() == 0); for(EndpointI endpoint : _endpoints) { + s.writeShort(endpoint.type()); endpoint.streamWrite(s); } } diff --git a/java/src/IceInternal/Selector.java b/java/src/IceInternal/Selector.java index 2ab11238b66..b23fbacb1b1 100644 --- a/java/src/IceInternal/Selector.java +++ b/java/src/IceInternal/Selector.java @@ -15,10 +15,11 @@ public final class Selector { } - public - Selector(Instance instance) + public Selector(Instance instance) { _instance = instance; + _selecting = false; + _interrupted = false; try { @@ -36,8 +37,7 @@ public final class Selector _keys = _selector.selectedKeys(); } - public void - destroy() + public void destroy() { try { @@ -49,14 +49,12 @@ public final class Selector _selector = null; } - public void - initialize(EventHandler handler) + public void initialize(EventHandler handler) { updateImpl(handler); } - public void - update(EventHandler handler, int remove, int add) + public void update(EventHandler handler, int remove, int add) { int previous = handler._registered; handler._registered = handler._registered & ~remove; @@ -65,23 +63,11 @@ public final class Selector { return; } - updateImpl(handler); - if(handler.hasMoreData() && (handler._disabled & SocketOperation.Read) == 0) - { - if((add & SocketOperation.Read) != 0) - { - _pendingHandlers.add(handler); - } - if((remove & SocketOperation.Read) != 0) - { - _pendingHandlers.remove(handler); - } - } + updateImpl(handler); } - public void - enable(EventHandler handler, int status) + public void enable(EventHandler handler, int status) { if((handler._disabled & status) == 0) { @@ -92,180 +78,85 @@ public final class Selector if((handler._registered & status) != 0) { updateImpl(handler); - - if((status & SocketOperation.Read) != 0 && handler.hasMoreData()) - { - // Add back the pending handler if reads are enabled. - _pendingHandlers.add(handler); - } } } - public void - disable(EventHandler handler, int status) + public void disable(EventHandler handler, int status) { if((handler._disabled & status) != 0) { return; } handler._disabled = handler._disabled | status; - + if((handler._registered & status) != 0) { updateImpl(handler); - - if((status & SocketOperation.Read) != 0 && handler.hasMoreData()) - { - // Remove the pending handler if reads are disabled. - _pendingHandlers.remove(handler); - } } } - public void - finish(EventHandler handler) + public void finish(EventHandler handler) { - handler._registered = 0; - - if(handler._key != null) + if(handler._registered != 0) { - handler._key.cancel(); - handler._key = null; - } - - _changes.remove(handler); - _pendingHandlers.remove(handler); - } + if(handler._key != null) + { + handler._key.cancel(); + handler._key = null; + } - public void - startSelect() - { - assert(_changes.isEmpty()); + _changes.remove(handler); - // - // Don't set _selecting = true if there are pending handlers, select() won't block - // and will just call selectNow(). - // - if(_pendingHandlers.isEmpty()) - { - _selecting = true; + update(handler, handler._registered, SocketOperation.None); } } - public void - finishSelect(java.util.List<EventHandler> handlers, long timeout) + public void startSelect() { - _selecting = false; - handlers.clear(); - - if(!_changes.isEmpty()) - { - for(EventHandler h : _changes) - { - updateImpl(h); - } - _changes.clear(); - } - else if(_keys.isEmpty() && _pendingHandlers.isEmpty() && timeout <= 0) + if(_interrupted) { - // - // This is necessary to prevent a busy loop in case of a spurious wake-up which - // sometime occurs in the client thread pool when the communicator is destroyed. - // If there are too many successive spurious wake-ups, we log an error. - // - try - { - Thread.sleep(1); - } - catch(java.lang.InterruptedException ex) - { - } - - if(++_spuriousWakeUp > 100) - { - _spuriousWakeUp = 0; - _instance.initializationData().logger.warning("spurious selector wake up"); - } - return; - } - - _spuriousWakeUp = 0; + _interrupted = false; - for(java.nio.channels.SelectionKey key : _keys) - { - EventHandler handler = (EventHandler)key.attachment(); - try - { - // - // It's important to check for interestOps here because the event handler - // registration might have changed above when _changes was processed. We - // don't want to return event handlers which aren't interested anymore in - // a given operation. - // - handler._ready = fromJavaOps(key.readyOps() & key.interestOps()); - if(handler.hasMoreData() && _pendingHandlers.remove(handler)) - { - handler._ready |= SocketOperation.Read; - } - handlers.add(handler); - } - catch(java.nio.channels.CancelledKeyException ex) + if(!_changes.isEmpty()) { - assert(handler._registered == 0); + updateSelector(); } } - _keys.clear(); + _selecting = true; + } - for(EventHandler handler : _pendingHandlers) - { - if(handler.hasMoreData()) - { - handler._ready = SocketOperation.Read; - handlers.add(handler); - } - } - _pendingHandlers.clear(); + public void finishSelect() + { + _selecting = false; } - public void - select(long timeout) + public void select(java.util.List<EventHandlerOpPair> handlers, long timeout) throws TimeoutException { while(true) { try { - // - // Only block if _selecting = true, otherwise we call selectNow() to retrieve new - // ready handlers and process handlers from _pendingHandlers. - // - if(_selecting) + if(timeout > 0) { - if(timeout > 0) + // + // NOTE: On some platforms, select() sometime returns slightly before + // the timeout (at least according to our monotonic time). To make sure + // timeouts are correctly detected, we wait for a little longer than + // the configured timeout (10ms). + // + long before = IceInternal.Time.currentMonotonicTimeMillis(); + if(_selector.select(timeout * 1000 + 10) == 0) { - // - // NOTE: On some platforms, select() sometime returns slightly before - // the timeout (at least according to our monotonic time). To make sure - // timeouts are correctly detected, we wait for a little longer than - // the configured timeout (10ms). - // - long before = IceInternal.Time.currentMonotonicTimeMillis(); - if(_selector.select(timeout * 1000 + 10) == 0) + if(IceInternal.Time.currentMonotonicTimeMillis() - before >= timeout * 1000) { - if(IceInternal.Time.currentMonotonicTimeMillis() - before >= timeout * 1000) - { - throw new TimeoutException(); - } + throw new TimeoutException(); } } - else - { - _selector.select(); - } } else { - _selector.selectNow(); + _selector.select(); } } catch(java.nio.channels.CancelledKeyException ex) @@ -299,63 +190,111 @@ public final class Selector break; } - } - public void - hasMoreData(EventHandler handler) - { - assert(!_selecting && handler.hasMoreData()); + handlers.clear(); - // - // Only add the handler if read is still registered and enabled. - // - if((handler._registered & ~handler._disabled & SocketOperation.Read) != 0) + if(_interrupted) // Interrupted, we have to process the interrupt before returning any handlers + { + return; + } + + if(_keys.isEmpty() && timeout <= 0) + { + // + // This is necessary to prevent a busy loop in case of a spurious wake-up which + // sometime occurs in the client thread pool when the communicator is destroyed. + // If there are too many successive spurious wake-ups, we log an error. + // + try + { + Thread.sleep(1); + } + catch(java.lang.InterruptedException ex) + { + } + + if(++_spuriousWakeUp > 100) + { + _spuriousWakeUp = 0; + _instance.initializationData().logger.warning("spurious selector wake up"); + } + return; + } + + _spuriousWakeUp = 0; + + for(java.nio.channels.SelectionKey key : _keys) { - _pendingHandlers.add(handler); + EventHandler handler = (EventHandler)key.attachment(); + try + { + // + // Use the intersection of readyOps and interestOps because we only want to + // report the operations in which the handler is still interested. + // + final int op = fromJavaOps(key.readyOps() & key.interestOps()); + handlers.add(new EventHandlerOpPair(handler, op)); + } + catch(java.nio.channels.CancelledKeyException ex) + { + assert(handler._registered == 0); + } } + _keys.clear(); } - private void - updateImpl(EventHandler handler) + private void updateImpl(EventHandler handler) { + _changes.add(handler); if(_selecting) { - // - // Queue the change since we can't change the selection key interest ops while a select - // operation is in progress (it could block depending on the underlying implementaiton - // of the Java selector). - // - if(_changes.isEmpty()) + if(!_interrupted) { + // + // We can't change the selection key interest ops while a select operation is in progress + // (it could block depending on the underlying implementation of the Java selector). + // + // Wake up the selector if necessary. + // _selector.wakeup(); + _interrupted = true; } - _changes.add(handler); - return; } + else + { + updateSelector(); + } + } - int ops = toJavaOps(handler, handler._registered & ~handler._disabled); - if(handler._key == null) + private void updateSelector() + { + for(EventHandler handler : _changes) { - if(handler._registered != 0) + int status = handler._registered & ~handler._disabled; + int ops = toJavaOps(handler, status); + if(handler._key == null) { - try + if(handler._registered != 0) { - handler._key = handler.fd().register(_selector, ops, handler); - } - catch(java.nio.channels.ClosedChannelException ex) - { - assert(false); + try + { + handler._key = handler.fd().register(_selector, ops, handler); + } + catch(java.nio.channels.ClosedChannelException ex) + { + assert(false); + } } } + else + { + handler._key.interestOps(ops); + } } - else - { - handler._key.interestOps(ops); - } + _changes.clear(); } - int - toJavaOps(EventHandler handler, int o) + int toJavaOps(EventHandler handler, int o) { int op = 0; if((o & SocketOperation.Read) != 0) @@ -380,8 +319,7 @@ public final class Selector return op; } - int - fromJavaOps(int o) + int fromJavaOps(int o) { int op = 0; if((o & (java.nio.channels.SelectionKey.OP_READ | java.nio.channels.SelectionKey.OP_ACCEPT)) != 0) @@ -399,7 +337,6 @@ public final class Selector return op; } - final private Instance _instance; private java.nio.channels.Selector _selector; @@ -408,5 +345,6 @@ public final class Selector private java.util.HashSet<EventHandler> _changes = new java.util.HashSet<EventHandler>(); private java.util.HashSet<EventHandler> _pendingHandlers = new java.util.HashSet<EventHandler>(); private boolean _selecting; + private boolean _interrupted; private int _spuriousWakeUp; } diff --git a/java/src/IceInternal/TcpAcceptor.java b/java/src/IceInternal/TcpAcceptor.java index 301577f3286..d8f35bb625a 100644 --- a/java/src/IceInternal/TcpAcceptor.java +++ b/java/src/IceInternal/TcpAcceptor.java @@ -20,10 +20,10 @@ class TcpAcceptor implements Acceptor public void close() { - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { String s = "stopping to accept tcp connections at " + toString(); - _logger.trace(_traceLevels.networkCat, s); + _instance.logger().trace(_instance.traceCategory(), s); } assert(_fd != null); @@ -36,7 +36,7 @@ class TcpAcceptor implements Acceptor { // Nothing to do. - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { StringBuffer s = new StringBuffer("listening for tcp connections at "); s.append(toString()); @@ -49,7 +49,7 @@ class TcpAcceptor implements Acceptor s.append("\nlocal interfaces: "); s.append(IceUtilInternal.StringUtil.joinString(interfaces, ", ")); } - _logger.trace(_traceLevels.networkCat, s.toString()); + _instance.logger().trace(_instance.traceCategory(), s.toString()); } } @@ -58,18 +58,24 @@ class TcpAcceptor implements Acceptor { java.nio.channels.SocketChannel fd = Network.doAccept(_fd); Network.setBlock(fd, false); - Network.setTcpBufSize(fd, _instance.initializationData().properties, _logger); + Network.setTcpBufSize(fd, _instance.properties(), _instance.logger()); - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { String s = "accepted tcp connection\n" + Network.fdToString(fd); - _logger.trace(_traceLevels.networkCat, s); + _instance.logger().trace(_instance.traceCategory(), s); } return new TcpTransceiver(_instance, fd); } public String + protocol() + { + return _instance.protocol(); + } + + public String toString() { return Network.addrToString(_addr); @@ -81,18 +87,16 @@ class TcpAcceptor implements Acceptor return _addr.getPort(); } - TcpAcceptor(Instance instance, String host, int port) + TcpAcceptor(ProtocolInstance instance, String host, int port) { _instance = instance; - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; - _backlog = instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511); + _backlog = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511); try { _fd = Network.createTcpServerSocket(); Network.setBlock(_fd, false); - Network.setTcpBufSize(_fd, _instance.initializationData().properties, _logger); + Network.setTcpBufSize(_fd, instance.properties(), _instance.logger()); if(!System.getProperty("os.name").startsWith("Windows")) { // @@ -110,11 +114,11 @@ class TcpAcceptor implements Acceptor // Network.setReuseAddress(_fd, true); } - _addr = Network.getAddressForServer(host, port, _instance.protocolSupport(), _instance.preferIPv6()); - if(_traceLevels.network >= 2) + _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6()); + if(instance.traceLevel() >= 2) { String s = "attempting to bind to tcp socket " + toString(); - _logger.trace(_traceLevels.networkCat, s); + instance.logger().trace(instance.traceCategory(), s); } _addr = Network.doBind(_fd, _addr, _backlog); } @@ -142,9 +146,7 @@ class TcpAcceptor implements Acceptor } } - private Instance _instance; - private TraceLevels _traceLevels; - private Ice.Logger _logger; + private ProtocolInstance _instance; private java.nio.channels.ServerSocketChannel _fd; private int _backlog; private java.net.InetSocketAddress _addr; diff --git a/java/src/IceInternal/TcpConnector.java b/java/src/IceInternal/TcpConnector.java index e4289f27a17..4e1ff9ff5e1 100644 --- a/java/src/IceInternal/TcpConnector.java +++ b/java/src/IceInternal/TcpConnector.java @@ -11,49 +11,45 @@ package IceInternal; final class TcpConnector implements Connector { - public Transceiver - connect() + public Transceiver connect() { - if(_traceLevels.network >= 2) + if(_instance.traceLevel() >= 2) { - String s = "trying to establish tcp connection to " + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "trying to establish " + _instance.protocol() + " connection to " + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } try { java.nio.channels.SocketChannel fd = Network.createTcpSocket(); Network.setBlock(fd, false); - Network.setTcpBufSize(fd, _instance.initializationData().properties, _logger); + Network.setTcpBufSize(fd, _instance.properties(), _instance.logger()); final java.net.InetSocketAddress addr = _proxy != null ? _proxy.getAddress() : _addr; Network.doConnect(fd, addr); return new TcpTransceiver(_instance, fd, _proxy, _addr); } catch(Ice.LocalException ex) { - if(_traceLevels.network >= 2) + if(_instance.traceLevel() >= 2) { - String s = "failed to establish tcp connection to " + toString() + "\n" + ex; - _logger.trace(_traceLevels.networkCat, s); + String s = "failed to establish " + _instance.protocol() + " connection to " + toString() + "\n" + ex; + _instance.logger().trace(_instance.traceCategory(), s); } throw ex; } } - public short - type() + public short type() { - return Ice.TCPEndpointType.value; + return _instance.type(); } - public String - toString() + public String toString() { return Network.addrToString(_proxy == null ? _addr : _proxy.getAddress()); } - public int - hashCode() + public int hashCode() { return _hashCode; } @@ -61,12 +57,10 @@ final class TcpConnector implements Connector // // Only for use by TcpEndpoint // - TcpConnector(Instance instance, java.net.InetSocketAddress addr, NetworkProxy proxy, int timeout, + TcpConnector(ProtocolInstance instance, java.net.InetSocketAddress addr, NetworkProxy proxy, int timeout, String connectionId) { _instance = instance; - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; _addr = addr; _proxy = proxy; _timeout = timeout; @@ -79,8 +73,7 @@ final class TcpConnector implements Connector _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); } - public boolean - equals(java.lang.Object obj) + public boolean equals(java.lang.Object obj) { if(!(obj instanceof TcpConnector)) { @@ -106,9 +99,7 @@ final class TcpConnector implements Connector return Network.compareAddress(_addr, p._addr) == 0; } - private Instance _instance; - private TraceLevels _traceLevels; - private Ice.Logger _logger; + private ProtocolInstance _instance; private java.net.InetSocketAddress _addr; private NetworkProxy _proxy; private int _timeout; diff --git a/java/src/IceInternal/TcpEndpointFactory.java b/java/src/IceInternal/TcpEndpointFactory.java index 6d0df0e77c3..d50fb5c37c7 100644 --- a/java/src/IceInternal/TcpEndpointFactory.java +++ b/java/src/IceInternal/TcpEndpointFactory.java @@ -11,40 +11,42 @@ package IceInternal; final class TcpEndpointFactory implements EndpointFactory { - TcpEndpointFactory(Instance instance) + TcpEndpointFactory(ProtocolInstance instance) { _instance = instance; } - public short - type() + public short type() { - return Ice.TCPEndpointType.value; + return _instance.type(); } - public String - protocol() + public String protocol() { - return "tcp"; + return _instance.protocol(); } - public EndpointI - create(String str, boolean oaEndpoint) + public EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) { - return new TcpEndpointI(_instance, str, oaEndpoint); + IPEndpointI endpt = new TcpEndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; } - public EndpointI - read(BasicStream s) + public EndpointI read(BasicStream s) { - return new TcpEndpointI(s); + return new TcpEndpointI(_instance, s); } - public void - destroy() + public void destroy() { _instance = null; } - private Instance _instance; + public EndpointFactory clone(ProtocolInstance instance) + { + return new TcpEndpointFactory(instance); + } + + private ProtocolInstance _instance; } diff --git a/java/src/IceInternal/TcpEndpointI.java b/java/src/IceInternal/TcpEndpointI.java index 9e6594b20ad..6fb7a7e9ce1 100644 --- a/java/src/IceInternal/TcpEndpointI.java +++ b/java/src/IceInternal/TcpEndpointI.java @@ -9,284 +9,61 @@ package IceInternal; -final class TcpEndpointI extends EndpointI +final class TcpEndpointI extends IPEndpointI { - public - TcpEndpointI(Instance instance, String ho, int po, int ti, String conId, boolean co) + public TcpEndpointI(ProtocolInstance instance, String ho, int po, int ti, String conId, boolean co) { - super(conId); - _instance = instance; - _host = ho; - _port = po; + super(instance, ho, po, conId); _timeout = ti; _compress = co; - calcHashValue(); } - public - TcpEndpointI(Instance instance, String str, boolean oaEndpoint) + public TcpEndpointI(ProtocolInstance instance) { - super(""); - _instance = instance; - _host = null; - _port = 0; + super(instance); _timeout = -1; _compress = false; - - String[] arr = str.split("[ \t\n\r]+"); - - int i = 0; - while(i < arr.length) - { - if(arr[i].length() == 0) - { - i++; - continue; - } - - String option = arr[i++]; - if(option.length() != 2 || option.charAt(0) != '-') - { - throw new Ice.EndpointParseException("expected an endpoint option but found `" + option + - "' in endpoint `tcp " + str + "'"); - } - - String argument = null; - if(i < arr.length && arr[i].charAt(0) != '-') - { - argument = arr[i++]; - if(argument.charAt(0) == '\"' && argument.charAt(argument.length() - 1) == '\"') - { - argument = argument.substring(1, argument.length() - 1); - } - } - - switch(option.charAt(1)) - { - case 'h': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -h option in endpoint `tcp " - + str + "'"); - } - - _host = argument; - break; - } - - case 'p': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -p option in endpoint `tcp " - + str + "'"); - } - - try - { - _port = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid port value `" + argument + - "' in endpoint `tcp " + str + "'"); - } - - if(_port < 0 || _port > 65535) - { - throw new Ice.EndpointParseException("port value `" + argument + - "' out of range in endpoint `tcp " + str + "'"); - } - - break; - } - - case 't': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -t option in endpoint `tcp " - + str + "'"); - } - - try - { - _timeout = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid timeout value `" + argument + - "' in endpoint `tcp " + str + "'"); - } - - break; - } - - case 'z': - { - if(argument != null) - { - throw new Ice.EndpointParseException("unexpected argument `" + argument + - "' provided for -z option in `tcp " + str + "'"); - } - - _compress = true; - break; - } - - default: - { - throw new Ice.EndpointParseException("unknown option `" + option + "' in `tcp " + str + "'"); - } - } - } - - if(_host == null) - { - _host = _instance.defaultsAndOverrides().defaultHost; - } - else if(_host.equals("*")) - { - if(oaEndpoint) - { - _host = null; - } - else - { - throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `tcp " + str + "'"); - } - } - - if(_host == null) - { - _host = ""; - } - - calcHashValue(); } - public - TcpEndpointI(BasicStream s) + public TcpEndpointI(ProtocolInstance instance, BasicStream s) { - super(""); - _instance = s.instance(); - s.startReadEncaps(); - _host = s.readString(); - _port = s.readInt(); + super(instance, s); _timeout = s.readInt(); _compress = s.readBool(); - s.endReadEncaps(); - calcHashValue(); - } - - // - // Marshal the endpoint - // - public void - streamWrite(BasicStream s) - { - s.writeShort(Ice.TCPEndpointType.value); - s.startWriteEncaps(); - s.writeString(_host); - s.writeInt(_port); - s.writeInt(_timeout); - s.writeBool(_compress); - s.endWriteEncaps(); - } - - // - // Convert the endpoint to its string form - // - public String - _toString() - { - // - // WARNING: Certain features, such as proxy validation in Glacier2, - // depend on the format of proxy strings. Changes to toString() and - // methods called to generate parts of the reference string could break - // these features. Please review for all features that depend on the - // format of proxyToString() before changing this and related code. - // - String s = "tcp"; - - if(_host != null && _host.length() > 0) - { - s += " -h "; - boolean addQuote = _host.indexOf(':') != -1; - if(addQuote) - { - s += "\""; - } - s += _host; - if(addQuote) - { - s += "\""; - } - } - - s += " -p " + _port; - - if(_timeout != -1) - { - s += " -t " + _timeout; - } - if(_compress) - { - s += " -z"; - } - return s; } // // Return the endpoint information. // - public Ice.EndpointInfo - getInfo() + public Ice.EndpointInfo getInfo() { - return new Ice.TCPEndpointInfo(_timeout, _compress, _host, _port) + Ice.TCPEndpointInfo info = new Ice.TCPEndpointInfo() { public short type() { - return Ice.TCPEndpointType.value; + return TcpEndpointI.this.type(); } - + public boolean datagram() { - return false; + return TcpEndpointI.this.datagram(); } - + public boolean secure() { - return false; + return TcpEndpointI.this.secure(); } - }; - } - - // - // Return the endpoint type - // - public short - type() - { - return Ice.TCPEndpointType.value; - } + }; - // - // Return the protocol name - // - public String - protocol() - { - return "tcp"; + fillEndpointInfo(info); + return info; } // // Return the timeout for the endpoint in milliseconds. 0 means // non-blocking, -1 means no timeout. // - public int - timeout() + public int timeout() { return _timeout; } @@ -296,8 +73,7 @@ final class TcpEndpointI extends EndpointI // that timeouts are supported by the endpoint. Otherwise the same // endpoint is returned. // - public EndpointI - timeout(int timeout) + public EndpointI timeout(int timeout) { if(timeout == _timeout) { @@ -310,27 +86,10 @@ final class TcpEndpointI extends EndpointI } // - // Return a new endpoint with a different connection id. - // - public EndpointI - connectionId(String connectionId) - { - if(connectionId.equals(_connectionId)) - { - return this; - } - else - { - return new TcpEndpointI(_instance, _host, _port, _timeout, connectionId, _compress); - } - } - - // // Return true if the endpoints support bzip2 compress, or false // otherwise. // - public boolean - compress() + public boolean compress() { return _compress; } @@ -340,8 +99,7 @@ final class TcpEndpointI extends EndpointI // provided that compression is supported by the // endpoint. Otherwise the same endpoint is returned. // - public EndpointI - compress(boolean compress) + public EndpointI compress(boolean compress) { if(compress == _compress) { @@ -356,8 +114,7 @@ final class TcpEndpointI extends EndpointI // // Return true if the endpoint is datagram-based. // - public boolean - datagram() + public boolean datagram() { return false; } @@ -365,8 +122,7 @@ final class TcpEndpointI extends EndpointI // // Return true if the endpoint is secure. // - public boolean - secure() + public boolean secure() { return false; } @@ -378,103 +134,54 @@ final class TcpEndpointI extends EndpointI // "effective" endpoint, which might differ from this endpoint, // for example, if a dynamic port number is assigned. // - public Transceiver - transceiver(EndpointIHolder endpoint) + public Transceiver transceiver(EndpointIHolder endpoint) { endpoint.value = this; return null; } // - // Return connectors for this endpoint, or empty list if no connector - // is available. - // - public java.util.List<Connector> - connectors(Ice.EndpointSelectionType selType) - { - return _instance.endpointHostResolver().resolve(_host, _port, selType, this); - } - - public void - connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) - { - _instance.endpointHostResolver().resolve(_host, _port, selType, this, callback); - } - - // // Return an acceptor for this endpoint, or null if no acceptors // is available. In case an acceptor is created, this operation // also returns a new "effective" endpoint, which might differ // from this endpoint, for example, if a dynamic port number is // assigned. // - public Acceptor - acceptor(EndpointIHolder endpoint, String adapterName) + public Acceptor acceptor(EndpointIHolder endpoint, String adapterName) { TcpAcceptor p = new TcpAcceptor(_instance, _host, _port); - endpoint.value = new TcpEndpointI(_instance, _host, p.effectivePort(), _timeout, _connectionId, _compress); + endpoint.value = createEndpoint(_host, p.effectivePort(), _connectionId); return p; } - // - // Expand endpoint out in to separate endpoints for each local - // host if listening on INADDR_ANY. - // - public java.util.List<EndpointI> - expand() + public String options() { - java.util.List<EndpointI> endps = new java.util.ArrayList<EndpointI>(); - java.util.List<String> hosts = Network.getHostsForEndpointExpand(_host, _instance.protocolSupport(), false); - if(hosts == null || hosts.isEmpty()) - { - endps.add(this); - } - else - { - for(String h : hosts) - { - endps.add(new TcpEndpointI(_instance, h, _port, _timeout, _connectionId, _compress)); - } - } - return endps; - } + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = super.options(); - // - // Check whether the endpoint is equivalent to another one. - // - public boolean - equivalent(EndpointI endpoint) - { - if(!(endpoint instanceof TcpEndpointI)) + if(_timeout != -1) { - return false; + s += " -t " + _timeout; } - TcpEndpointI tcpEndpointI = (TcpEndpointI)endpoint; - return tcpEndpointI._host.equals(_host) && tcpEndpointI._port == _port; - } - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) - { - java.util.List<Connector> connectors = new java.util.ArrayList<Connector>(); - for(java.net.InetSocketAddress p : addresses) + if(_compress) { - connectors.add(new TcpConnector(_instance, p, proxy, _timeout, _connectionId)); + s += " -z"; } - return connectors; - } - public int - hashCode() - { - return _hashCode; + return s; } // // Compare endpoints for sorting purposes // - public int - compareTo(EndpointI obj) // From java.lang.Comparable + public int compareTo(EndpointI obj) // From java.lang.Comparable { if(!(obj instanceof TcpEndpointI)) { @@ -486,23 +193,6 @@ final class TcpEndpointI extends EndpointI { return 0; } - else - { - int r = super.compareTo(p); - if(r != 0) - { - return r; - } - } - - if(_port < p._port) - { - return -1; - } - else if(p._port < _port) - { - return 1; - } if(_timeout < p._timeout) { @@ -522,26 +212,94 @@ final class TcpEndpointI extends EndpointI return 1; } - return _host.compareTo(p._host); + return super.compareTo(obj); } - private void - calcHashValue() + protected void streamWriteImpl(BasicStream s) { - int h = 5381; - h = IceInternal.HashUtil.hashAdd(h, Ice.TCPEndpointType.value); - h = IceInternal.HashUtil.hashAdd(h, _host); - h = IceInternal.HashUtil.hashAdd(h, _port); + super.streamWriteImpl(s); + s.writeInt(_timeout); + s.writeBool(_compress); + } + + protected int hashInit(int h) + { + h = super.hashInit(h); h = IceInternal.HashUtil.hashAdd(h, _timeout); - h = IceInternal.HashUtil.hashAdd(h, _connectionId); h = IceInternal.HashUtil.hashAdd(h, _compress); - _hashCode = h; + return h; + } + + protected void fillEndpointInfo(Ice.IPEndpointInfo info) + { + super.fillEndpointInfo(info); + if(info instanceof Ice.TCPEndpointInfo) + { + Ice.TCPEndpointInfo tcpInfo = (Ice.TCPEndpointInfo)info; + tcpInfo.timeout = _timeout; + tcpInfo.compress = _compress; + } + } + + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + switch(option.charAt(1)) + { + case 't': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + try + { + _timeout = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + + "' in endpoint " + endpoint); + } + + return true; + } + + case 'z': + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + + return true; + } + + default: + { + return false; + } + } + } + + protected Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy) + { + return new TcpConnector(_instance, addr, proxy, _timeout, _connectionId); + } + + protected IPEndpointI createEndpoint(String host, int port, String connectionId) + { + return new TcpEndpointI(_instance, host, port, _timeout, connectionId, _compress); } - private Instance _instance; - private String _host; - private int _port; private int _timeout; private boolean _compress; - private int _hashCode; } diff --git a/java/src/IceInternal/TcpTransceiver.java b/java/src/IceInternal/TcpTransceiver.java index 7122f8ff7cf..fd8bcc9ba54 100644 --- a/java/src/IceInternal/TcpTransceiver.java +++ b/java/src/IceInternal/TcpTransceiver.java @@ -11,15 +11,13 @@ package IceInternal; final class TcpTransceiver implements Transceiver { - public java.nio.channels.SelectableChannel - fd() + public java.nio.channels.SelectableChannel fd() { assert(_fd != null); return _fd; } - public int - initialize(Buffer readBuffer, Buffer writeBuffer) + public int initialize(Buffer readBuffer, Buffer writeBuffer, Ice.BooleanHolder moreData) { try { @@ -28,7 +26,7 @@ final class TcpTransceiver implements Transceiver _state = StateConnectPending; return SocketOperation.Connect; } - else if(_state == StateConnectPending) + else if(_state <= StateConnectPending) { Network.doFinishConnect(_fd); _desc = Network.fdToString(_fd, _proxy, _addr); @@ -44,7 +42,7 @@ final class TcpTransceiver implements Transceiver // // Write the proxy connection message. // - if(write(writeBuffer)) + if(write(writeBuffer) == SocketOperation.None) { // // Write completed without blocking. @@ -54,8 +52,7 @@ final class TcpTransceiver implements Transceiver // // Try to read the response. // - Ice.BooleanHolder dummy = new Ice.BooleanHolder(); - if(read(readBuffer, dummy)) + if(read(readBuffer, moreData) == SocketOperation.None) { // // Read completed without blocking - fall through. @@ -103,32 +100,38 @@ final class TcpTransceiver implements Transceiver } catch(Ice.LocalException ex) { - if(_traceLevels.network >= 2) + if(_instance.traceLevel() >= 2) { StringBuilder s = new StringBuilder(128); - s.append("failed to establish tcp connection\n"); + s.append("failed to establish " + _instance.protocol() + " connection\n"); s.append(Network.fdToString(_fd, _proxy, _addr)); - _logger.trace(_traceLevels.networkCat, s.toString()); + _instance.logger().trace(_instance.traceCategory(), s.toString()); } throw ex; } assert(_state == StateConnected); - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { - String s = "tcp connection established\n" + _desc; - _logger.trace(_traceLevels.networkCat, s); + String s = _instance.protocol() + " connection established\n" + _desc; + _instance.logger().trace(_instance.traceCategory(), s); } return SocketOperation.None; } - public void - close() + public int closing(boolean initiator, Ice.LocalException ex) { - if(_state == StateConnected && _traceLevels.network >= 1) + // If we are initiating the connection closure, wait for the peer + // to close the TCP/IP connection. Otherwise, close immediately. + return initiator ? SocketOperation.Read : SocketOperation.None; + } + + public void close() + { + if(_state == StateConnected && _instance.traceLevel() >= 1) { - String s = "closing tcp connection\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "closing " + _instance.protocol() + " connection\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } assert(_fd != null); @@ -147,22 +150,26 @@ final class TcpTransceiver implements Transceiver } @SuppressWarnings("deprecation") - public boolean - write(Buffer buf) + public int write(Buffer buf) { + final int size = buf.b.limit(); + int packetSize = size - buf.b.position(); + + if(packetSize == 0) + { + return SocketOperation.None; + } + // - // We don't want write to be called on android main thread as this will cause - // NetworkOnMainThreadException to be thrown. If that is the android main thread - // we return false and this method will be later called from the thread pool. + // We don't want write to be called on Android's main thread as this will cause + // NetworkOnMainThreadException to be thrown. If this is the Android main thread + // we return false and this method will be called later from the thread pool. // if(Util.isAndroidMainThread(Thread.currentThread())) { - return false; + return SocketOperation.Write; } - final int size = buf.b.limit(); - int packetSize = size - buf.b.position(); - // // Limit packet size to avoid performance problems on WIN32 // @@ -177,8 +184,8 @@ final class TcpTransceiver implements Transceiver try { assert(_fd != null); - int ret = _fd.write(buf.b); + int ret = _fd.write(buf.b); if(ret == -1) { throw new Ice.ConnectionLostException(); @@ -186,20 +193,21 @@ final class TcpTransceiver implements Transceiver else if(ret == 0) { // - // Writing would block, so we reset the limit (if necessary) and return false to indicate + // Writing would block, so we reset the limit (if necessary) and indicate // that more data must be sent. // if(packetSize == _maxSendPacketSize) { buf.b.limit(size); } - return false; + return SocketOperation.Write; } - if(_traceLevels.network >= 3) + if(_instance.traceLevel() >= 3) { - String s = "sent " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "sent " + ret + " of " + packetSize + " bytes via " + _instance.protocol() + "\n" + + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } if(packetSize == _maxSendPacketSize) @@ -222,15 +230,18 @@ final class TcpTransceiver implements Transceiver throw new Ice.SocketException(ex); } } - return true; + + return SocketOperation.None; } @SuppressWarnings("deprecation") - public boolean - read(Buffer buf, Ice.BooleanHolder moreData) + public int read(Buffer buf, Ice.BooleanHolder moreData) { int packetSize = buf.b.remaining(); - moreData.value = false; + if(packetSize == 0) + { + return SocketOperation.None; + } while(buf.b.hasRemaining()) { @@ -246,15 +257,16 @@ final class TcpTransceiver implements Transceiver if(ret == 0) { - return false; + return SocketOperation.Read; } if(ret > 0) { - if(_traceLevels.network >= 3) + if(_instance.traceLevel() >= 3) { - String s = "received " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "received " + ret + " of " + packetSize + " bytes via " + _instance.protocol() + + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } @@ -270,23 +282,20 @@ final class TcpTransceiver implements Transceiver } } - return true; + return SocketOperation.None; } - public String - type() + public String protocol() { - return "tcp"; + return _instance.protocol(); } - public String - toString() + public String toString() { return _desc; } - public Ice.ConnectionInfo - getInfo() + public Ice.ConnectionInfo getInfo() { Ice.TCPConnectionInfo info = new Ice.TCPConnectionInfo(); if(_fd != null) @@ -303,8 +312,7 @@ final class TcpTransceiver implements Transceiver return info; } - public void - checkSendSize(Buffer buf, int messageSizeMax) + public void checkSendSize(Buffer buf, int messageSizeMax) { if(buf.size() > messageSizeMax) { @@ -313,14 +321,13 @@ final class TcpTransceiver implements Transceiver } @SuppressWarnings("deprecation") - TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd, NetworkProxy proxy, + TcpTransceiver(ProtocolInstance instance, java.nio.channels.SocketChannel fd, NetworkProxy proxy, java.net.InetSocketAddress addr) { + _instance = instance; _fd = fd; _proxy = proxy; _addr = addr; - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; _state = StateNeedConnect; _desc = ""; @@ -341,11 +348,10 @@ final class TcpTransceiver implements Transceiver } @SuppressWarnings("deprecation") - TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd) + TcpTransceiver(ProtocolInstance instance, java.nio.channels.SocketChannel fd) { + _instance = instance; _fd = fd; - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; _state = StateConnected; _desc = Network.fdToString(_fd); @@ -382,14 +388,13 @@ final class TcpTransceiver implements Transceiver } } + private ProtocolInstance _instance; private java.nio.channels.SocketChannel _fd; private NetworkProxy _proxy; private java.net.InetSocketAddress _addr; - private TraceLevels _traceLevels; - private Ice.Logger _logger; - private String _desc; private int _state; + private String _desc; private int _maxSendPacketSize; private static final int StateNeedConnect = 0; diff --git a/java/src/IceInternal/ThreadPool.java b/java/src/IceInternal/ThreadPool.java index 03e3713fe93..8ab584e9623 100644 --- a/java/src/IceInternal/ThreadPool.java +++ b/java/src/IceInternal/ThreadPool.java @@ -25,7 +25,7 @@ public final class ThreadPool } } } - + static final class FinishedWorkItem implements ThreadPoolWorkItem { public @@ -60,6 +60,16 @@ public final class ThreadPool private final EventHandlerThread _thread; } + static final class InterruptWorkItem implements ThreadPoolWorkItem + { + public void execute(ThreadPoolCurrent current) + { + // Nothing to do, this is just used to interrupt the thread pool selector. + } + } + + private static ThreadPoolWorkItem _interruptWorkItem = new InterruptWorkItem(); + // // Exception raised by the thread pool work queue when the thread pool // is destroyed. @@ -257,7 +267,33 @@ public final class ThreadPool update(EventHandler handler, int remove, int add) { assert(!_destroyed); + + // Don't remove what needs to be added + remove &= ~add; + + // Don't remove/add if already un-registered or registered + remove = handler._registered & remove; + add = ~handler._registered & add; + if(remove == add) + { + return; + } + _selector.update(handler, remove, add); + + if((add & SocketOperation.Read) != 0 && handler._hasMoreData.value && + (handler._disabled & SocketOperation.Read) == 0) + { + if(_pendingHandlers.isEmpty()) + { + _workQueue.queue(_interruptWorkItem); // Interrupt select() + } + _pendingHandlers.add(handler); + } + else if((remove & SocketOperation.Read) != 0) + { + _pendingHandlers.remove(handler); + } } public void @@ -312,6 +348,8 @@ public final class ThreadPool { ThreadPoolCurrent current = new ThreadPoolCurrent(_instance, this, thread); boolean select = false; + java.util.List<EventHandlerOpPair> handlers = new java.util.ArrayList<EventHandlerOpPair>(); + while(true) { if(current._handler != null) @@ -335,7 +373,7 @@ public final class ThreadPool { try { - _selector.select(_serverIdleTime); + _selector.select(handlers, _serverIdleTime); } catch(Selector.TimeoutException ex) { @@ -356,8 +394,25 @@ public final class ThreadPool { if(select) { - _selector.finishSelect(_handlers, _serverIdleTime); + java.util.List<EventHandlerOpPair> tmp = _handlers; + _handlers = handlers; + handlers = tmp; + + if(!_pendingHandlers.isEmpty()) + { + for(EventHandlerOpPair pair : _handlers) + { + _pendingHandlers.remove(pair.handler); + } + for(EventHandler p : _pendingHandlers) + { + _handlers.add(new EventHandlerOpPair(p, SocketOperation.Read)); + } + _pendingHandlers.clear(); + } + _nextHandler = _handlers.iterator(); + _selector.finishSelect(); select = false; } else if(!current._leader && followerWait(current)) @@ -375,9 +430,14 @@ public final class ThreadPool // --_inUseIO; - if((current.operation & SocketOperation.Read) != 0 && current._handler.hasMoreData()) + if(current._handler._hasMoreData.value && + (current._handler._registered & SocketOperation.Read) != 0) { - _selector.hasMoreData(current._handler); + if(_pendingHandlers.isEmpty()) + { + _workQueue.queue(_interruptWorkItem); + } + _pendingHandlers.add(current._handler); } } else @@ -386,7 +446,19 @@ public final class ThreadPool // If the handler called ioCompleted(), we re-enable the handler in // case it was disabled and we decrease the number of thread in use. // - _selector.enable(current._handler, current.operation); + if(_serialize) + { + _selector.enable(current._handler, current.operation); + if(current._handler._hasMoreData.value && + (current._handler._registered & SocketOperation.Read) != 0) + { + if(_pendingHandlers.isEmpty()) + { + _workQueue.queue(_interruptWorkItem); // Interrupt select() + } + _pendingHandlers.add(current._handler); + } + } assert(_inUse > 0); --_inUse; } @@ -396,20 +468,34 @@ public final class ThreadPool return; // Wait timed-out. } } - else if(!current._ioCompleted && - (current.operation & SocketOperation.Read) != 0 && current._handler.hasMoreData()) + else if(current._handler._hasMoreData.value && + (current._handler._registered & SocketOperation.Read) != 0) { - _selector.hasMoreData(current._handler); + if(_pendingHandlers.isEmpty()) + { + _workQueue.queue(_interruptWorkItem); // Interrupt select() + } + _pendingHandlers.add(current._handler); } // // Get the next ready handler. // - if(_nextHandler.hasNext()) + EventHandlerOpPair next = null; + while(_nextHandler.hasNext()) + { + EventHandlerOpPair n = _nextHandler.next(); + if((n.op & n.handler._registered) != 0) + { + next = n; + break; + } + } + if(next != null) { current._ioCompleted = false; - current._handler = _nextHandler.next(); - current.operation = current._handler._ready; + current._handler = next.handler; + current.operation = next.op; thread.setState(Ice.Instrumentation.ThreadState.ThreadStateInUseForIO); } else @@ -431,6 +517,7 @@ public final class ThreadPool } else { + _handlers.clear(); _selector.startSelect(); select = true; thread.setState(Ice.Instrumentation.ThreadState.ThreadStateIdle); @@ -462,17 +549,29 @@ public final class ThreadPool if(_sizeMax > 1) { --_inUseIO; - - if((current.operation & SocketOperation.Read) != 0 && current._handler.hasMoreData()) + + if(!_destroyed) { - _selector.hasMoreData(current._handler); + if(_serialize) + { + _selector.disable(current._handler, current.operation); + + // Make sure the handler isn't in the set of pending handlers (this can + // for example occur if the handler is has more data and its added by + // ThreadPool::update while we were processing IO). + _pendingHandlers.remove(current._handler); + } + else if(current._handler._hasMoreData.value && + (current._handler._registered & SocketOperation.Read) != 0) + { + if(_pendingHandlers.isEmpty()) + { + _workQueue.queue(_interruptWorkItem); // Interrupt select() + } + _pendingHandlers.add(current._handler); + } } - - if(_serialize && !_destroyed) - { - _selector.disable(current._handler, current.operation); - } - + if(current._leader) { // @@ -527,10 +626,6 @@ public final class ThreadPool } } } - else if((current.operation & SocketOperation.Read) != 0 && current._handler.hasMoreData()) - { - _selector.hasMoreData(current._handler); - } } private synchronized void @@ -563,7 +658,7 @@ public final class ThreadPool // // Wait to be promoted and for all the IO threads to be done. // - while(!_promote || _inUseIO == _sizeIO || !_nextHandler.hasNext() && _inUseIO > 0) + while(!_promote || _inUseIO == _sizeIO || (!_nextHandler.hasNext() && _inUseIO > 0)) { try { @@ -740,8 +835,9 @@ public final class ThreadPool private int _inUse; // Number of threads that are currently in use. private int _inUseIO; // Number of threads that are currently performing IO. - private java.util.List<EventHandler> _handlers = new java.util.ArrayList<EventHandler>(); - private java.util.Iterator<EventHandler> _nextHandler; + private java.util.List<EventHandlerOpPair> _handlers = new java.util.ArrayList<EventHandlerOpPair>(); + private java.util.Iterator<EventHandlerOpPair> _nextHandler; + private java.util.HashSet<EventHandler> _pendingHandlers = new java.util.HashSet<EventHandler>(); private boolean _promote; } diff --git a/java/src/IceInternal/ThreadPoolWorkQueue.java b/java/src/IceInternal/ThreadPoolWorkQueue.java index eab2b4d2b88..ba3c19eaea8 100644 --- a/java/src/IceInternal/ThreadPoolWorkQueue.java +++ b/java/src/IceInternal/ThreadPoolWorkQueue.java @@ -149,12 +149,6 @@ final class ThreadPoolWorkQueue extends EventHandler { return (java.nio.channels.SelectableChannel)_fdIntrRead; } - - public boolean - hasMoreData() - { - return false; - } public void postMessage() diff --git a/java/src/IceInternal/Transceiver.java b/java/src/IceInternal/Transceiver.java index 329ff3e1386..ad372615208 100644 --- a/java/src/IceInternal/Transceiver.java +++ b/java/src/IceInternal/Transceiver.java @@ -13,35 +13,14 @@ public interface Transceiver { java.nio.channels.SelectableChannel fd(); - // - // Initialize the transceiver. - // - // Returns the status if the initialize operation. - // - int initialize(Buffer readBuffer, Buffer writeBuffer); - + int initialize(Buffer readBuffer, Buffer writeBuffer, Ice.BooleanHolder moreData); + int closing(boolean initiator, Ice.LocalException ex); void close(); - // - // Write data. - // - // Returns true if all the data was written, false otherwise. - // - boolean write(Buffer buf); - - // - // Read data. - // - // Returns true if all the requested data was read, false otherwise. - // - // NOTE: In Java, read() returns a boolean in moreData to indicate - // whether the transceiver has read more data than requested. - // If moreData is true, read should be called again without - // calling select on the FD. - // - boolean read(Buffer buf, Ice.BooleanHolder moreData); + int write(Buffer buf); + int read(Buffer buf, Ice.BooleanHolder moreData); - String type(); + String protocol(); String toString(); Ice.ConnectionInfo getInfo(); void checkSendSize(Buffer buf, int messageSizeMax); diff --git a/java/src/IceInternal/UdpConnector.java b/java/src/IceInternal/UdpConnector.java index b70e1b4c8ec..054014efc2c 100644 --- a/java/src/IceInternal/UdpConnector.java +++ b/java/src/IceInternal/UdpConnector.java @@ -11,33 +11,28 @@ package IceInternal; final class UdpConnector implements Connector { - public Transceiver - connect() + public Transceiver connect() { return new UdpTransceiver(_instance, _addr, _mcastInterface, _mcastTtl); } - public java.nio.channels.SelectableChannel - fd() + public java.nio.channels.SelectableChannel fd() { assert(false); // Shouldn't be called, startConnect always completes immediately. return null; } - public short - type() + public short type() { - return Ice.UDPEndpointType.value; + return _instance.type(); } - public String - toString() + public String toString() { return Network.addrToString(_addr); } - public int - hashCode() + public int hashCode() { return _hashCode; } @@ -45,7 +40,7 @@ final class UdpConnector implements Connector // // Only for use by TcpEndpoint // - UdpConnector(Instance instance, java.net.InetSocketAddress addr, String mcastInterface, int mcastTtl, + UdpConnector(ProtocolInstance instance, java.net.InetSocketAddress addr, String mcastInterface, int mcastTtl, String connectionId) { _instance = instance; @@ -62,8 +57,7 @@ final class UdpConnector implements Connector _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); } - public boolean - equals(java.lang.Object obj) + public boolean equals(java.lang.Object obj) { if(!(obj instanceof UdpConnector)) { @@ -92,9 +86,9 @@ final class UdpConnector implements Connector } return Network.compareAddress(_addr, p._addr) == 0; - } + } - private Instance _instance; + private ProtocolInstance _instance; private java.net.InetSocketAddress _addr; private String _mcastInterface; private int _mcastTtl; diff --git a/java/src/IceInternal/UdpEndpointFactory.java b/java/src/IceInternal/UdpEndpointFactory.java index e45e12d2ea6..8e4301d358b 100644 --- a/java/src/IceInternal/UdpEndpointFactory.java +++ b/java/src/IceInternal/UdpEndpointFactory.java @@ -11,40 +11,42 @@ package IceInternal; final class UdpEndpointFactory implements EndpointFactory { - UdpEndpointFactory(Instance instance) + UdpEndpointFactory(ProtocolInstance instance) { _instance = instance; } - public short - type() + public short type() { - return Ice.UDPEndpointType.value; + return _instance.type(); } - public String - protocol() + public String protocol() { - return "udp"; + return _instance.protocol(); } - public EndpointI - create(String str, boolean oaEndpoint) + public EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) { - return new UdpEndpointI(_instance, str, oaEndpoint); + IPEndpointI endpt = new UdpEndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; } - public EndpointI - read(BasicStream s) + public EndpointI read(BasicStream s) { - return new UdpEndpointI(s); + return new UdpEndpointI(_instance, s); } - public void - destroy() + public void destroy() { _instance = null; } - private Instance _instance; + public EndpointFactory clone(ProtocolInstance instance) + { + return new UdpEndpointFactory(instance); + } + + private ProtocolInstance _instance; } diff --git a/java/src/IceInternal/UdpEndpointI.java b/java/src/IceInternal/UdpEndpointI.java index 24a0fcaf29f..43b5ba48d50 100644 --- a/java/src/IceInternal/UdpEndpointI.java +++ b/java/src/IceInternal/UdpEndpointI.java @@ -9,208 +9,28 @@ package IceInternal; -final class UdpEndpointI extends EndpointI +final class UdpEndpointI extends IPEndpointI { - public - UdpEndpointI(Instance instance, String ho, int po, String mif, int mttl, boolean conn, String conId, boolean co) + public UdpEndpointI(ProtocolInstance instance, String ho, int po, String mif, int mttl, boolean conn, String conId, + boolean co) { - super(conId); - _instance = instance; - _host = ho; - _port = po; + super(instance, ho, po, conId); _mcastInterface = mif; _mcastTtl = mttl; _connect = conn; _compress = co; - calcHashValue(); } - public - UdpEndpointI(Instance instance, String str, boolean oaEndpoint) + public UdpEndpointI(ProtocolInstance instance) { - super(""); - _instance = instance; - _host = null; - _port = 0; + super(instance); _connect = false; _compress = false; - - String[] arr = str.split("[ \t\n\r]+"); - - int i = 0; - while(i < arr.length) - { - if(arr[i].length() == 0) - { - i++; - continue; - } - - String option = arr[i++]; - if(option.charAt(0) != '-') - { - throw new Ice.EndpointParseException("expected an endpoint option but found `" + option + - "' in endpoint `udp " + str + "'"); - } - - String argument = null; - if(i < arr.length && arr[i].charAt(0) != '-') - { - argument = arr[i++]; - if(argument.charAt(0) == '\"' && argument.charAt(argument.length() - 1) == '\"') - { - argument = argument.substring(1, argument.length() - 1); - } - } - - if(option.equals("-h")) - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -h option in endpoint `udp " - + str + "'"); - } - - _host = argument; - } - else if(option.equals("-p")) - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -p option in endpoint `udp " - + str + "'"); - } - - try - { - _port = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid port value `" + argument + "' in endpoint `udp " + - str + "'"); - } - - if(_port < 0 || _port > 65535) - { - throw new Ice.EndpointParseException("port value `" + argument + - "' out of range in endpoint `udp " + str + "'"); - } - } - else if(option.equals("-c")) - { - if(argument != null) - { - throw new Ice.EndpointParseException("unexpected argument `" + argument + - "' provided for -c option in `udp " + str + "'"); - } - - _connect = true; - } - else if(option.equals("-z")) - { - if(argument != null) - { - throw new Ice.EndpointParseException("unexpected argument `" + argument + - "' provided for -z option in `udp " + str + "'"); - } - - _compress = true; - } - else if(option.equals("-v") || option.equals("-e")) - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for " + option + " option in endpoint " + - "`udp " + str + "'"); - } - - try - { - Ice.EncodingVersion v = Ice.Util.stringToEncodingVersion(argument); - if(v.major != 1 || v.minor != 0) - { - _instance.initializationData().logger.warning("deprecated udp endpoint option: " + option); - } - } - catch(Ice.VersionParseException e) - { - throw new Ice.EndpointParseException("invalid version `" + argument + "' in endpoint `udp " + - str + "':\n" + e.str); - } - } - else if(option.equals("--interface")) - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for --interface option in endpoint `udp " - + str + "'"); - } - - _mcastInterface = argument; - } - else if(option.equals("--ttl")) - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for --ttl option in endpoint `udp " - + str + "'"); - } - - try - { - _mcastTtl = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid TTL value `" + argument + "' in endpoint `udp " + - str + "'"); - } - - if(_mcastTtl < 0) - { - throw new Ice.EndpointParseException("TTL value `" + argument + - "' out of range in endpoint `udp " + str + "'"); - } - } - else - { - throw new Ice.EndpointParseException("unknown option `" + option + "' in `udp " + str + "'"); - } - } - - if(_host == null) - { - _host = _instance.defaultsAndOverrides().defaultHost; - } - else if(_host.equals("*")) - { - if(oaEndpoint) - { - _host = null; - } - else - { - throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `udp " + str + "'"); - } - } - - if(_host == null) - { - _host = ""; - } - - calcHashValue(); } - public - UdpEndpointI(BasicStream s) + public UdpEndpointI(ProtocolInstance instance, BasicStream s) { - super(""); - _instance = s.instance(); - s.startReadEncaps(); - _host = s.readString(); - _port = s.readInt(); + super(instance, s); if(s.getReadEncoding().equals(Ice.Util.Encoding_1_0)) { s.readByte(); @@ -222,145 +42,59 @@ final class UdpEndpointI extends EndpointI //_connect = s.readBool(); _connect = false; _compress = s.readBool(); - s.endReadEncaps(); - calcHashValue(); - } - - // - // Marshal the endpoint - // - public void - streamWrite(BasicStream s) - { - s.writeShort(Ice.UDPEndpointType.value); - s.startWriteEncaps(); - s.writeString(_host); - s.writeInt(_port); - if(s.getWriteEncoding().equals(Ice.Util.Encoding_1_0)) - { - Ice.Util.Protocol_1_0.__write(s); - Ice.Util.Encoding_1_0.__write(s); - } - // Not transmitted. - //s.writeBool(_connect); - s.writeBool(_compress); - s.endWriteEncaps(); - } - - // - // Convert the endpoint to its string form - // - public String - _toString() - { - // - // WARNING: Certain features, such as proxy validation in Glacier2, - // depend on the format of proxy strings. Changes to toString() and - // methods called to generate parts of the reference string could break - // these features. Please review for all features that depend on the - // format of proxyToString() before changing this and related code. - // - String s = "udp"; - - if(_host != null && _host.length() > 0) - { - s += " -h "; - boolean addQuote = _host.indexOf(':') != -1; - if(addQuote) - { - s += "\""; - } - s += _host; - if(addQuote) - { - s += "\""; - } - } - - s += " -p " + _port; - - if(_mcastInterface.length() != 0) - { - s += " --interface " + _mcastInterface; - } - - if(_mcastTtl != -1) - { - s += " --ttl " + _mcastTtl; - } - - if(_connect) - { - s += " -c"; - } - - if(_compress) - { - s += " -z"; - } - - return s; } // // Return the endpoint information. // - public Ice.EndpointInfo - getInfo() + public Ice.EndpointInfo getInfo() { - return new Ice.UDPEndpointInfo(-1, _compress, _host, _port, _mcastInterface, _mcastTtl) + Ice.UDPEndpointInfo info = new Ice.UDPEndpointInfo() { public short type() { - return Ice.UDPEndpointType.value; + return UdpEndpointI.this.type(); } - + public boolean datagram() { - return true; + return UdpEndpointI.this.datagram(); } - + public boolean secure() { - return false; + return UdpEndpointI.this.secure(); } }; - } - // - // Return the endpoint type - // - public short - type() - { - return Ice.UDPEndpointType.value; + fillEndpointInfo(info); + return info; } // - // Return the protocol name + // Return the timeout for the endpoint in milliseconds. 0 means + // non-blocking, -1 means no timeout. // - public String - protocol() + public int timeout() { - return "udp"; + return -1; } // - // Return the timeout for the endpoint in milliseconds. 0 means - // non-blocking, -1 means no timeout. + // Return a new endpoint with a different timeout value, provided + // that timeouts are supported by the endpoint. Otherwise the same + // endpoint is returned. // - public int - timeout() + public EndpointI timeout(int timeout) { - return -1; + return this; } // // Return true if the endpoints support bzip2 compress, or false // otherwise. // - public boolean - compress() + public boolean compress() { return _compress; } @@ -370,8 +104,7 @@ final class UdpEndpointI extends EndpointI // provided that compression is supported by the // endpoint. Otherwise the same endpoint is returned. // - public EndpointI - compress(boolean compress) + public EndpointI compress(boolean compress) { if(compress == _compress) { @@ -385,38 +118,9 @@ final class UdpEndpointI extends EndpointI } // - // Return a new endpoint with a different connection id. - // - public EndpointI - connectionId(String connectionId) - { - if(connectionId.equals(_connectionId)) - { - return this; - } - else - { - return new UdpEndpointI(_instance, _host, _port, _mcastInterface, _mcastTtl, _connect, connectionId, - _compress); - } - } - - // - // Return a new endpoint with a different timeout value, provided - // that timeouts are supported by the endpoint. Otherwise the same - // endpoint is returned. - // - public EndpointI - timeout(int timeout) - { - return this; - } - - // // Return true if the endpoint is datagram-based. // - public boolean - datagram() + public boolean datagram() { return true; } @@ -424,8 +128,7 @@ final class UdpEndpointI extends EndpointI // // Return true if the endpoint is secure. // - public boolean - secure() + public boolean secure() { return false; } @@ -437,103 +140,64 @@ final class UdpEndpointI extends EndpointI // "effective" endpoint, which might differ from this endpoint, // for example, if a dynamic port number is assigned. // - public Transceiver - transceiver(EndpointIHolder endpoint) + public Transceiver transceiver(EndpointIHolder endpoint) { UdpTransceiver p = new UdpTransceiver(_instance, _host, _port, _mcastInterface, _connect); - endpoint.value = new UdpEndpointI(_instance, _host, p.effectivePort(), _mcastInterface, _mcastTtl, - _connect, _connectionId, _compress); + endpoint.value = createEndpoint(_host, p.effectivePort(), _connectionId); return p; } // - // Return connectors for this endpoint, or empty list if no connector - // is available. - // - public java.util.List<Connector> - connectors(Ice.EndpointSelectionType selType) - { - return _instance.endpointHostResolver().resolve(_host, _port, selType, this); - } - - public void - connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) - { - _instance.endpointHostResolver().resolve(_host, _port, selType, this, callback); - } - - // // Return an acceptor for this endpoint, or null if no acceptors // is available. In case an acceptor is created, this operation // also returns a new "effective" endpoint, which might differ // from this endpoint, for example, if a dynamic port number is // assigned. // - public Acceptor - acceptor(EndpointIHolder endpoint, String adapterName) + public Acceptor acceptor(EndpointIHolder endpoint, String adapterName) { endpoint.value = this; return null; } // - // Expand endpoint out in to separate endpoints for each local - // host if listening on INADDR_ANY. + // Convert the endpoint to its string form // - public java.util.List<EndpointI> - expand() + public String options() { - java.util.ArrayList<EndpointI> endps = new java.util.ArrayList<EndpointI>(); - java.util.ArrayList<String> hosts = - Network.getHostsForEndpointExpand(_host, _instance.protocolSupport(), false); - if(hosts == null || hosts.isEmpty()) + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = super.options(); + + if(_mcastInterface.length() != 0) { - endps.add(this); + s += " --interface " + _mcastInterface; } - else + + if(_mcastTtl != -1) { - for(String host : hosts) - { - endps.add(new UdpEndpointI(_instance, host, _port, _mcastInterface, _mcastTtl, _connect, _connectionId, - _compress)); - } + s += " --ttl " + _mcastTtl; } - return endps; - } - // - // Check whether the endpoint is equivalent to another one. - // - public boolean - equivalent(EndpointI endpoint) - { - if(!(endpoint instanceof UdpEndpointI)) + if(_connect) { - return false; + s += " -c"; } - UdpEndpointI udpEndpointI = (UdpEndpointI)endpoint; - return udpEndpointI._host.equals(_host) && udpEndpointI._port == _port; - } - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) - { - java.util.ArrayList<Connector> connectors = new java.util.ArrayList<Connector>(); - for(java.net.InetSocketAddress p : addresses) + if(_compress) { - connectors.add(new UdpConnector(_instance, p, _mcastInterface, _mcastTtl, _connectionId)); + s += " -z"; } - return connectors; - } - public int - hashCode() - { - return _hashCode; + return s; } - public int - compareTo(EndpointI obj) // From java.lang.Comparable + public int compareTo(EndpointI obj) // From java.lang.Comparable { if(!(obj instanceof UdpEndpointI)) { @@ -545,23 +209,6 @@ final class UdpEndpointI extends EndpointI { return 0; } - else - { - int r = super.compareTo(p); - if(r != 0) - { - return r; - } - } - - if(_port < p._port) - { - return -1; - } - else if(p._port < _port) - { - return 1; - } if(!_connect && p._connect) { @@ -596,30 +243,148 @@ final class UdpEndpointI extends EndpointI return rc; } - return _host.compareTo(p._host); + return super.compareTo(obj); } - private void - calcHashValue() + // + // Marshal the endpoint + // + protected void streamWriteImpl(BasicStream s) { - int h = 5381; - h = IceInternal.HashUtil.hashAdd(h, Ice.UDPEndpointType.value); - h = IceInternal.HashUtil.hashAdd(h, _host); - h = IceInternal.HashUtil.hashAdd(h, _port); + super.streamWriteImpl(s); + if(s.getWriteEncoding().equals(Ice.Util.Encoding_1_0)) + { + Ice.Util.Protocol_1_0.__write(s); + Ice.Util.Encoding_1_0.__write(s); + } + // Not transmitted. + //s.writeBool(_connect); + s.writeBool(_compress); + } + + protected int hashInit(int h) + { + h = super.hashInit(h); h = IceInternal.HashUtil.hashAdd(h, _mcastInterface); h = IceInternal.HashUtil.hashAdd(h, _mcastTtl); h = IceInternal.HashUtil.hashAdd(h, _connect); - h = IceInternal.HashUtil.hashAdd(h, _connectionId); h = IceInternal.HashUtil.hashAdd(h, _compress); - _hashCode = h; + return h; + } + + protected void fillEndpointInfo(Ice.IPEndpointInfo info) + { + super.fillEndpointInfo(info); + if(info instanceof Ice.UDPEndpointInfo) + { + Ice.UDPEndpointInfo udpInfo = (Ice.UDPEndpointInfo)info; + udpInfo.timeout = -1; + udpInfo.compress = _compress; + udpInfo.mcastInterface = _mcastInterface; + udpInfo.mcastTtl = _mcastTtl; + } + } + + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + if(option.equals("-c")) + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -c option in " + endpoint); + } + + _connect = true; + } + else if(option.equals("-z")) + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + } + else if(option.equals("-v") || option.equals("-e")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for " + option + " option in endpoint " + + endpoint); + } + + try + { + Ice.EncodingVersion v = Ice.Util.stringToEncodingVersion(argument); + if(v.major != 1 || v.minor != 0) + { + _instance.logger().warning("deprecated udp endpoint option: " + option); + } + } + catch(Ice.VersionParseException e) + { + throw new Ice.EndpointParseException("invalid version `" + argument + "' in endpoint " + + endpoint + ":\n" + e.str); + } + } + else if(option.equals("--interface")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --interface option in endpoint " + + endpoint); + } + + _mcastInterface = argument; + } + else if(option.equals("--ttl")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --ttl option in endpoint " + endpoint); + } + + try + { + _mcastTtl = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid TTL value `" + argument + "' in endpoint " + endpoint); + } + + if(_mcastTtl < 0) + { + throw new Ice.EndpointParseException("TTL value `" + argument + "' out of range in endpoint " + + endpoint); + } + } + else + { + return false; + } + return true; + } + + protected Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy) + { + return new UdpConnector(_instance, addr, _mcastInterface, _mcastTtl, _connectionId); + } + + protected IPEndpointI createEndpoint(String host, int port, String connectionId) + { + return new UdpEndpointI(_instance, host, port, _mcastInterface, _mcastTtl, _connect, connectionId, _compress); } - private Instance _instance; - private String _host; - private int _port; private String _mcastInterface = ""; private int _mcastTtl = -1; private boolean _connect; private boolean _compress; - private int _hashCode; } diff --git a/java/src/IceInternal/UdpTransceiver.java b/java/src/IceInternal/UdpTransceiver.java index 96174b95c26..15f1683cf4e 100644 --- a/java/src/IceInternal/UdpTransceiver.java +++ b/java/src/IceInternal/UdpTransceiver.java @@ -11,15 +11,13 @@ package IceInternal; final class UdpTransceiver implements Transceiver { - public java.nio.channels.SelectableChannel - fd() + public java.nio.channels.SelectableChannel fd() { assert(_fd != null); return _fd; } - public int - initialize(Buffer readBuffer, Buffer writeBuffer) + public int initialize(Buffer readBuffer, Buffer writeBuffer, Ice.BooleanHolder moreData) { // // Nothing to do. @@ -27,17 +25,24 @@ final class UdpTransceiver implements Transceiver return SocketOperation.None; } - public void - close() + public int closing(boolean initiator, Ice.LocalException ex) + { + // + // Nothing to do. + // + return SocketOperation.None; + } + + public void close() { assert(_fd != null); - - if(_state >= StateConnected && _traceLevels.network >= 1) + + if(_state >= StateConnected && _instance.traceLevel() >= 1) { - String s = "closing udp connection\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "closing " + _instance.protocol() + " connection\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } - + try { _fd.close(); @@ -48,9 +53,8 @@ final class UdpTransceiver implements Transceiver _fd = null; } - @SuppressWarnings("deprecation") - public boolean - write(Buffer buf) + @SuppressWarnings("deprecation") + public int write(Buffer buf) { // // We don't want write or send to be called on android main thread as this will cause @@ -59,12 +63,12 @@ final class UdpTransceiver implements Transceiver // if(Util.isAndroidMainThread(Thread.currentThread())) { - return false; + return SocketOperation.Write; } assert(buf.b.position() == 0); assert(_fd != null && _state >= StateConnected); - + // The caller is supposed to check the send size before by calling checkSendSize assert(java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size()); @@ -107,25 +111,23 @@ final class UdpTransceiver implements Transceiver if(ret == 0) { - return false; + return SocketOperation.Write; } - if(_traceLevels.network >= 3) + if(_instance.traceLevel() >= 3) { - String s = "sent " + ret + " bytes via udp\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "sent " + ret + " bytes via " + _instance.protocol() + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } assert(ret == buf.b.limit()); - return true; + return SocketOperation.None; } - + @SuppressWarnings("deprecation") - public boolean - read(Buffer buf, Ice.BooleanHolder moreData) + public int read(Buffer buf, Ice.BooleanHolder moreData) { assert(buf.b.position() == 0); - moreData.value = false; final int packetSize = java.lang.Math.min(_maxPacketSize, _rcvSize - _udpOverhead); buf.resize(packetSize, true); @@ -139,7 +141,7 @@ final class UdpTransceiver implements Transceiver java.net.SocketAddress peerAddr = _fd.receive(buf.b); if(peerAddr == null || buf.b.position() == 0) { - return false; + return SocketOperation.Read; } _peerAddr = (java.net.InetSocketAddress)peerAddr; @@ -172,33 +174,31 @@ final class UdpTransceiver implements Transceiver Network.doConnect(_fd, _peerAddr); _state = StateConnected; - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { - String s = "connected udp socket\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "connected " + _instance.protocol() + " socket\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } - if(_traceLevels.network >= 3) + if(_instance.traceLevel() >= 3) { - String s = "received " + ret + " bytes via udp\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "received " + ret + " bytes via " + _instance.protocol() + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } buf.resize(ret, true); buf.b.position(ret); - return true; + return SocketOperation.None; } - public String - type() + public String protocol() { - return "udp"; + return _instance.protocol(); } - public String - toString() + public String toString() { if(_fd == null) { @@ -227,8 +227,7 @@ final class UdpTransceiver implements Transceiver return s; } - public Ice.ConnectionInfo - getInfo() + public Ice.ConnectionInfo getInfo() { Ice.UDPConnectionInfo info = new Ice.UDPConnectionInfo(); if(_fd != null) @@ -261,16 +260,15 @@ final class UdpTransceiver implements Transceiver return info; } - public void - checkSendSize(Buffer buf, int messageSizeMax) + public void checkSendSize(Buffer buf, int messageSizeMax) { if(buf.size() > messageSizeMax) { Ex.throwMemoryLimitException(buf.size(), messageSizeMax); } - + // - // The maximum packetSize is either the maximum allowable UDP packet size, or + // The maximum packetSize is either the maximum allowable UDP packet size, or // the UDP send buffer size (which ever is smaller). // final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead); @@ -280,8 +278,7 @@ final class UdpTransceiver implements Transceiver } } - public final int - effectivePort() + public final int effectivePort() { return _addr.getPort(); } @@ -290,17 +287,16 @@ final class UdpTransceiver implements Transceiver // Only for use by UdpEndpoint // @SuppressWarnings("deprecation") - UdpTransceiver(Instance instance, java.net.InetSocketAddress addr, String mcastInterface, int mcastTtl) + UdpTransceiver(ProtocolInstance instance, java.net.InetSocketAddress addr, String mcastInterface, int mcastTtl) { - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; + _instance = instance; _state = StateNeedConnect; _addr = addr; try { _fd = Network.createUdpSocket(_addr); - setBufSize(instance); + setBufSize(instance.properties()); Network.setBlock(_fd, false); // // NOTE: setting the multicast interface before performing the @@ -313,10 +309,10 @@ final class UdpTransceiver implements Transceiver Network.doConnect(_fd, _addr); _state = StateConnected; // We're connected now - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { - String s = "starting to send udp packets\n" + toString(); - _logger.trace(_traceLevels.networkCat, s); + String s = "starting to send " + _instance.protocol() + " packets\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } catch(Ice.LocalException ex) @@ -330,22 +326,21 @@ final class UdpTransceiver implements Transceiver // Only for use by UdpEndpoint // @SuppressWarnings("deprecation") - UdpTransceiver(Instance instance, String host, int port, String mcastInterface, boolean connect) + UdpTransceiver(ProtocolInstance instance, String host, int port, String mcastInterface, boolean connect) { - _traceLevels = instance.traceLevels(); - _logger = instance.initializationData().logger; + _instance = instance; _state = connect ? StateNeedConnect : StateNotConnected; try { _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6()); _fd = Network.createUdpSocket(_addr); - setBufSize(instance); + setBufSize(instance.properties()); Network.setBlock(_fd, false); - if(_traceLevels.network >= 2) + if(_instance.traceLevel() >= 2) { - String s = "attempting to bind to udp socket " + Network.addrToString(_addr); - _logger.trace(_traceLevels.networkCat, s); + String s = "attempting to bind to " + _instance.protocol() + " socket " + Network.addrToString(_addr); + _instance.logger().trace(_instance.traceCategory(), s); } if(_addr.getAddress().isMulticastAddress()) { @@ -357,11 +352,11 @@ final class UdpTransceiver implements Transceiver // // Windows does not allow binding to the mcast address itself // so we bind to INADDR_ANY (0.0.0.0) instead. As a result, - // bi-directional connection won't work because the source + // bi-directional connection won't work because the source // address won't be the multicast address and the client will // therefore reject the datagram. // - int protocol = + int protocol = _mcastAddr.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : Network.EnableIPv6; _addr = Network.getAddressForServer("", port, protocol, instance.preferIPv6()); } @@ -395,12 +390,12 @@ final class UdpTransceiver implements Transceiver _addr = Network.doBind(_fd, _addr); } - if(_traceLevels.network >= 1) + if(_instance.traceLevel() >= 1) { - StringBuffer s = new StringBuffer("starting to receive udp packets\n"); + StringBuffer s = new StringBuffer("starting to receive " + _instance.protocol() + " packets\n"); s.append(toString()); - java.util.List<String> interfaces = + java.util.List<String> interfaces = Network.getHostsForEndpointExpand(_addr.getAddress().getHostAddress(), instance.protocolSupport(), true); if(!interfaces.isEmpty()) @@ -408,7 +403,7 @@ final class UdpTransceiver implements Transceiver s.append("\nlocal interfaces: "); s.append(IceUtilInternal.StringUtil.joinString(interfaces, ", ")); } - _logger.trace(_traceLevels.networkCat, s.toString()); + _instance.logger().trace(_instance.traceCategory(), s.toString()); } } catch(Ice.LocalException ex) @@ -418,8 +413,7 @@ final class UdpTransceiver implements Transceiver } } - private synchronized void - setBufSize(Instance instance) + private synchronized void setBufSize(Ice.Properties properties) { assert(_fd != null); @@ -446,13 +440,14 @@ final class UdpTransceiver implements Transceiver // // Get property for buffer size and check for sanity. // - int sizeRequested = instance.initializationData().properties.getPropertyAsIntWithDefault(prop, dfltSize); + int sizeRequested = properties.getPropertyAsIntWithDefault(prop, dfltSize); if(sizeRequested < (_udpOverhead + IceInternal.Protocol.headerSize)) { - _logger.warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " + dfltSize); + _instance.logger().warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " + + dfltSize); sizeRequested = dfltSize; } - + if(sizeRequested != dfltSize) { // @@ -479,233 +474,106 @@ final class UdpTransceiver implements Transceiver // if(sizeSet < sizeRequested) { - _logger.warning("UDP " + direction + " buffer size: requested size of " + _instance.logger().warning("UDP " + direction + " buffer size: requested size of " + sizeRequested + " adjusted to " + sizeSet); } } } } - // - // The NIO classes before JDK 1.7 do not support multicast, at least not directly. - // This method works around that limitation by using reflection to configure the - // file descriptor of a DatagramChannel for multicast operation. Specifically, an - // instance of java.net.PlainDatagramSocketImpl is use to (temporarily) wrap the - // channel's file descriptor. - // - // If using JDK >= 1.7 we use the new added MulticastChannel via reflection to allow - // compilation with older JDK versions. - // - private void - configureMulticast(java.net.InetSocketAddress group, String interfaceAddr, int ttl) + private void configureMulticast(java.net.InetSocketAddress group, String interfaceAddr, int ttl) { try { - Class<?> cls = Util.findClass("java.nio.channels.MulticastChannel", null); - java.lang.reflect.Method m = null; - java.net.DatagramSocketImpl socketImpl = null; - java.lang.reflect.Field socketFd = null; java.net.NetworkInterface intf = null; - if(cls == null || !cls.isAssignableFrom(_fd.getClass())) + + if(interfaceAddr.length() != 0) { - cls = Util.findClass("java.net.PlainDatagramSocketImpl", null); - if(cls == null) + intf = java.net.NetworkInterface.getByName(interfaceAddr); + if(intf == null) { - throw new Ice.SocketException(); + try + { + intf = java.net.NetworkInterface.getByInetAddress( + java.net.InetAddress.getByName(interfaceAddr)); + } + catch(Exception ex) + { + } } - java.lang.reflect.Constructor<?> c = cls.getDeclaredConstructor((Class<?>[])null); - c.setAccessible(true); - socketImpl = (java.net.DatagramSocketImpl)c.newInstance((Object[])null); + } + if(group != null) + { // - // We have to invoke the protected create() method on the PlainDatagramSocketImpl object so - // that this hack works properly when IPv6 is enabled on Windows. + // Join multicast group. // - try - { - m = cls.getDeclaredMethod("create", (Class<?>[])null); - m.setAccessible(true); - m.invoke(socketImpl); - } - catch(java.lang.NoSuchMethodException ex) // OpenJDK + boolean join = false; + if(intf != null) { + _fd.join(group.getAddress(), intf); + join = true; } - - cls = Util.findClass("sun.nio.ch.DatagramChannelImpl", null); - if(cls == null) + else { - throw new Ice.SocketException(); - } - java.lang.reflect.Field channelFd = cls.getDeclaredField("fd"); - channelFd.setAccessible(true); - - socketFd = java.net.DatagramSocketImpl.class.getDeclaredField("fd"); - socketFd.setAccessible(true); - socketFd.set(socketImpl, channelFd.get(_fd)); - } + // + // If the user doesn't specify an interface, we join to the multicast group with every + // interface that supports multicast and has a configured address with the same protocol + // as the group address protocol. + // + int protocol = group.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : + Network.EnableIPv6; - try - { - if(interfaceAddr.length() != 0) - { - intf = java.net.NetworkInterface.getByName(interfaceAddr); - if(intf == null) + java.util.List<java.net.NetworkInterface> interfaces = + java.util.Collections.list(java.net.NetworkInterface.getNetworkInterfaces()); + for(java.net.NetworkInterface iface : interfaces) { - try - { - intf = java.net.NetworkInterface.getByInetAddress( - java.net.InetAddress.getByName(interfaceAddr)); - } - catch(Exception ex) + if(!iface.supportsMulticast()) { + continue; } - } - } - if(group != null) - { - // - // Join multicast group. - // - Class<?>[] types; - Object[] args; - if(socketImpl == null) - { - types = new Class<?>[]{ java.net.InetAddress.class, java.net.NetworkInterface.class }; - m = _fd.getClass().getDeclaredMethod("join", types); - m.setAccessible(true); - boolean join = false; - if(intf != null) + boolean hasProtocolAddress = false; + java.util.List<java.net.InetAddress> addresses = + java.util.Collections.list(iface.getInetAddresses()); + for(java.net.InetAddress address : addresses) { - m.invoke(_fd, new Object[] { group.getAddress(), intf }); - join = true; - } - else - { - // - // If the user doesn't specify an interface, we join to the multicast group with all the - // interfaces that support multicast and has a configured address with the same protocol - // as the group address protocol. - // - int protocol = group.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : - Network.EnableIPv6; - - java.util.List<java.net.NetworkInterface> interfaces = - java.util.Collections.list(java.net.NetworkInterface.getNetworkInterfaces()); - for(java.net.NetworkInterface iface : interfaces) + if(address.getAddress().length == 4 && protocol == Network.EnableIPv4 || + address.getAddress().length != 4 && protocol == Network.EnableIPv6) { - if(!iface.supportsMulticast()) - { - continue; - } - boolean hasProtocolAddress = false; - java.util.List<java.net.InetAddress> addresses = - java.util.Collections.list(iface.getInetAddresses()); - for(java.net.InetAddress address : addresses) - { - if(address.getAddress().length == 4 && protocol == Network.EnableIPv4 || - address.getAddress().length != 4 && protocol == Network.EnableIPv6) - { - hasProtocolAddress = true; - break; - } - } - - if(hasProtocolAddress) - { - m.invoke(_fd, new Object[] { group.getAddress(), iface }); - join = true; - } + hasProtocolAddress = true; + break; } - - if(!join) - { - throw new Ice.SocketException(new IllegalArgumentException( - "There aren't any interfaces that support multicast, " + - "or the interfaces that support it\n" + - "are not configured for the group protocol. " + - "Cannot join the mulitcast group.")); - } - } - } - else - { - try - { - types = new Class<?>[]{ java.net.SocketAddress.class, java.net.NetworkInterface.class }; - m = socketImpl.getClass().getDeclaredMethod("joinGroup", types); - args = new Object[]{ group, intf }; } - catch(java.lang.NoSuchMethodException ex) // OpenJDK - { - types = new Class<?>[]{ java.net.InetAddress.class, java.net.NetworkInterface.class }; - m = socketImpl.getClass().getDeclaredMethod("join", types); - args = new Object[]{ group.getAddress(), intf }; - } - m.setAccessible(true); - m.invoke(socketImpl, args); - } - } - else if(intf != null) - { - // - // Otherwise, set the multicast interface if specified. - // - Class<?>[] types = new Class<?>[]{ Integer.TYPE, Object.class }; - if(socketImpl == null) - { - Class<?> socketOption = Util.findClass("java.net.SocketOption", null); - Class<?> standardSocketOptions = Util.findClass("java.net.StandardSocketOptions", null); - m = _fd.getClass().getDeclaredMethod("setOption", new Class<?>[]{socketOption, Object.class}); - m.setAccessible(true); - java.lang.reflect.Field ipMcastIf = standardSocketOptions.getDeclaredField("IP_MULTICAST_IF"); - ipMcastIf.setAccessible(true); - m.invoke(_fd, new Object[]{ ipMcastIf.get(null), intf }); - } - else - { - try + if(hasProtocolAddress) { - m = socketImpl.getClass().getDeclaredMethod("setOption", types); - } - catch(java.lang.NoSuchMethodException ex) // OpenJDK - { - m = socketImpl.getClass().getDeclaredMethod("socketSetOption", types); + _fd.join(group.getAddress(), iface); + join = true; } - m.setAccessible(true); - Object[] args = new Object[]{ Integer.valueOf(java.net.SocketOptions.IP_MULTICAST_IF2), intf }; - m.invoke(socketImpl, args); } - } - if(ttl != -1) - { - if(socketImpl == null) + if(!join) { - Class<?> socketOption = Util.findClass("java.net.SocketOption", null); - Class<?> standardSocketOptions = Util.findClass("java.net.StandardSocketOptions", null); - m = _fd.getClass().getDeclaredMethod("setOption", new Class<?>[]{socketOption, Object.class}); - m.setAccessible(true); - java.lang.reflect.Field ipMcastTtl = standardSocketOptions.getDeclaredField("IP_MULTICAST_TTL"); - ipMcastTtl.setAccessible(true); - m.invoke(_fd, new Object[]{ ipMcastTtl.get(null), ttl }); - } - else - { - Class<?>[] types = new Class<?>[]{ Integer.TYPE }; - m = java.net.DatagramSocketImpl.class.getDeclaredMethod("setTimeToLive", types); - m.setAccessible(true); - m.invoke(socketImpl, new Object[]{ Integer.valueOf(ttl) }); + throw new Ice.SocketException(new IllegalArgumentException( + "There aren't any interfaces that support multicast, " + + "or the interfaces that support it\n" + + "are not configured for the group protocol. " + + "Cannot join the mulitcast group.")); } } } - finally + else if(intf != null) { - if(socketFd != null && socketImpl != null) - { - socketFd.set(socketImpl, null); - } + // + // Otherwise, set the multicast interface if specified. + // + _fd.setOption(java.net.StandardSocketOptions.IP_MULTICAST_IF, intf); + } + + if(ttl != -1) + { + _fd.setOption(java.net.StandardSocketOptions.IP_MULTICAST_TTL, ttl); } } catch(Exception ex) @@ -714,8 +582,7 @@ final class UdpTransceiver implements Transceiver } } - protected synchronized void - finalize() + protected synchronized void finalize() throws Throwable { try @@ -731,8 +598,7 @@ final class UdpTransceiver implements Transceiver } } - private TraceLevels _traceLevels; - private Ice.Logger _logger; + private ProtocolInstance _instance; private int _state; private int _rcvSize; diff --git a/java/src/IceSSL/AcceptorI.java b/java/src/IceSSL/AcceptorI.java index 42a4e336cb2..804f72b12ef 100644 --- a/java/src/IceSSL/AcceptorI.java +++ b/java/src/IceSSL/AcceptorI.java @@ -11,19 +11,17 @@ package IceSSL; final class AcceptorI implements IceInternal.Acceptor { - public java.nio.channels.ServerSocketChannel - fd() + public java.nio.channels.ServerSocketChannel fd() { return _fd; } - public void - close() + public void close() { - if(_instance.networkTraceLevel() >= 1) + if(_instance.traceLevel() >= 1) { - String s = "stopping to accept ssl connections at " + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "stopping to accept " + _instance.protocol() + " connections at " + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } assert(_fd != null); @@ -31,14 +29,13 @@ final class AcceptorI implements IceInternal.Acceptor _fd = null; } - public void - listen() + public void listen() { // Nothing to do. - if(_instance.networkTraceLevel() >= 1) + if(_instance.traceLevel() >= 1) { - StringBuffer s = new StringBuffer("listening for ssl connections at "); + StringBuffer s = new StringBuffer("listening for " + _instance.protocol() + " connections at "); s.append(toString()); java.util.List<String> interfaces = @@ -49,12 +46,11 @@ final class AcceptorI implements IceInternal.Acceptor s.append("\nlocal interfaces: "); s.append(IceUtilInternal.StringUtil.joinString(interfaces, ", ")); } - _logger.trace(_instance.networkTraceCategory(), s.toString()); + _instance.logger().trace(_instance.traceCategory(), s.toString()); } } - public IceInternal.Transceiver - accept() + public IceInternal.Transceiver accept() { // // The plug-in may not be fully initialized. @@ -72,7 +68,7 @@ final class AcceptorI implements IceInternal.Acceptor try { IceInternal.Network.setBlock(fd, false); - IceInternal.Network.setTcpBufSize(fd, _instance.communicator().getProperties(), _logger); + IceInternal.Network.setTcpBufSize(fd, _instance.properties(), _instance.logger()); java.net.InetSocketAddress peerAddr = (java.net.InetSocketAddress)fd.socket().getRemoteSocketAddress(); engine = _instance.createSSLEngine(true, peerAddr); @@ -83,23 +79,26 @@ final class AcceptorI implements IceInternal.Acceptor throw ex; } - if(_instance.networkTraceLevel() >= 1) + if(_instance.traceLevel() >= 1) { - _logger.trace(_instance.networkTraceCategory(), "accepting ssl connection\n" + - IceInternal.Network.fdToString(fd)); + _instance.logger().trace(_instance.traceCategory(), "accepting " + _instance.protocol() + " connection\n" + + IceInternal.Network.fdToString(fd)); } return new TransceiverI(_instance, engine, fd, _adapterName); } - public String - toString() + public String protocol() + { + return _instance.protocol(); + } + + public String toString() { return IceInternal.Network.addrToString(_addr); } - int - effectivePort() + int effectivePort() { return _addr.getPort(); } @@ -108,14 +107,13 @@ final class AcceptorI implements IceInternal.Acceptor { _instance = instance; _adapterName = adapterName; - _logger = instance.communicator().getLogger(); - _backlog = instance.communicator().getProperties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511); + _backlog = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511); try { _fd = IceInternal.Network.createTcpServerSocket(); IceInternal.Network.setBlock(_fd, false); - IceInternal.Network.setTcpBufSize(_fd, _instance.communicator().getProperties(), _logger); + IceInternal.Network.setTcpBufSize(_fd, _instance.properties(), _instance.logger()); if(!System.getProperty("os.name").startsWith("Windows")) { // @@ -135,10 +133,10 @@ final class AcceptorI implements IceInternal.Acceptor } _addr = IceInternal.Network.getAddressForServer(host, port, _instance.protocolSupport(), _instance.preferIPv6()); - if(_instance.networkTraceLevel() >= 2) + if(_instance.traceLevel() >= 2) { - String s = "attempting to bind to ssl socket " + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "attempting to bind to " + _instance.protocol() + " socket " + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } _addr = IceInternal.Network.doBind(_fd, _addr, _backlog); } @@ -149,8 +147,7 @@ final class AcceptorI implements IceInternal.Acceptor } } - protected synchronized void - finalize() + protected synchronized void finalize() throws Throwable { try @@ -168,7 +165,6 @@ final class AcceptorI implements IceInternal.Acceptor private Instance _instance; private String _adapterName; - private Ice.Logger _logger; private java.nio.channels.ServerSocketChannel _fd; private int _backlog; private java.net.InetSocketAddress _addr; diff --git a/java/src/IceSSL/ConnectorI.java b/java/src/IceSSL/ConnectorI.java index aae35bb55c2..a373c8e5084 100644 --- a/java/src/IceSSL/ConnectorI.java +++ b/java/src/IceSSL/ConnectorI.java @@ -11,8 +11,7 @@ package IceSSL; final class ConnectorI implements IceInternal.Connector { - public IceInternal.Transceiver - connect() + public IceInternal.Transceiver connect() { // // The plug-in may not be fully initialized. @@ -24,17 +23,17 @@ final class ConnectorI implements IceInternal.Connector throw ex; } - if(_instance.networkTraceLevel() >= 2) + if(_instance.traceLevel() >= 2) { - String s = "trying to establish ssl connection to " + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "trying to establish " + _instance.protocol() + " connection to " + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } try { java.nio.channels.SocketChannel fd = IceInternal.Network.createTcpSocket(); IceInternal.Network.setBlock(fd, false); - IceInternal.Network.setTcpBufSize(fd, _instance.communicator().getProperties(), _logger); + IceInternal.Network.setTcpBufSize(fd, _instance.properties(), _instance.logger()); final java.net.InetSocketAddress addr = _proxy != null ? _proxy.getAddress() : _addr; IceInternal.Network.doConnect(fd, addr); try @@ -50,29 +49,26 @@ final class ConnectorI implements IceInternal.Connector } catch(Ice.LocalException ex) { - if(_instance.networkTraceLevel() >= 2) + if(_instance.traceLevel() >= 2) { - String s = "failed to establish ssl connection to " + toString() + "\n" + ex; - _logger.trace(_instance.networkTraceCategory(), s); + String s = "failed to establish " + _instance.protocol() + " connection to " + toString() + "\n" + ex; + _instance.logger().trace(_instance.traceCategory(), s); } throw ex; } } - public short - type() + public short type() { - return EndpointType.value; + return _instance.type(); } - public String - toString() + public String toString() { return IceInternal.Network.addrToString(_proxy == null ? _addr : _proxy.getAddress()); } - public int - hashCode() + public int hashCode() { return _hashCode; } @@ -84,7 +80,6 @@ final class ConnectorI implements IceInternal.Connector int timeout, String connectionId) { _instance = instance; - _logger = instance.communicator().getLogger(); _host = host; _addr = addr; _proxy = proxy; @@ -98,8 +93,7 @@ final class ConnectorI implements IceInternal.Connector _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); } - public boolean - equals(java.lang.Object obj) + public boolean equals(java.lang.Object obj) { if(!(obj instanceof ConnectorI)) { @@ -126,7 +120,6 @@ final class ConnectorI implements IceInternal.Connector } private Instance _instance; - private Ice.Logger _logger; private String _host; private java.net.InetSocketAddress _addr; private IceInternal.NetworkProxy _proxy; diff --git a/java/src/IceSSL/EndpointFactoryI.java b/java/src/IceSSL/EndpointFactoryI.java index f573d9f6410..e566049db7d 100644 --- a/java/src/IceSSL/EndpointFactoryI.java +++ b/java/src/IceSSL/EndpointFactoryI.java @@ -16,35 +16,37 @@ final class EndpointFactoryI implements IceInternal.EndpointFactory _instance = instance; } - public short - type() + public short type() { - return EndpointType.value; + return _instance.type(); } - public String - protocol() + public String protocol() { - return "ssl"; + return _instance.protocol(); } - public IceInternal.EndpointI - create(String str, boolean oaEndpoint) + public IceInternal.EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) { - return new EndpointI(_instance, str, oaEndpoint); + IceInternal.IPEndpointI endpt = new EndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; } - public IceInternal.EndpointI - read(IceInternal.BasicStream s) + public IceInternal.EndpointI read(IceInternal.BasicStream s) { return new EndpointI(_instance, s); } - public void - destroy() + public void destroy() { _instance = null; } + public IceInternal.EndpointFactory clone(IceInternal.ProtocolInstance instance) + { + return new EndpointFactoryI(new Instance(_instance.sharedInstance(), instance.type(), instance.protocol())); + } + private Instance _instance; } diff --git a/java/src/IceSSL/EndpointI.java b/java/src/IceSSL/EndpointI.java index 8d57be9e157..c2d297a9e85 100644 --- a/java/src/IceSSL/EndpointI.java +++ b/java/src/IceSSL/EndpointI.java @@ -9,284 +9,64 @@ package IceSSL; -final class EndpointI extends IceInternal.EndpointI +final class EndpointI extends IceInternal.IPEndpointI { - public - EndpointI(Instance instance, String ho, int po, int ti, String conId, boolean co) + public EndpointI(Instance instance, String ho, int po, int ti, String conId, boolean co) { - super(conId); + super(instance, ho, po, conId); _instance = instance; - _host = ho; - _port = po; _timeout = ti; _compress = co; - calcHashValue(); } - public - EndpointI(Instance instance, String str, boolean oaEndpoint) + public EndpointI(Instance instance) { - super(""); + super(instance); _instance = instance; - _host = null; - _port = 0; _timeout = -1; _compress = false; - - String[] arr = str.split("[ \t\n\r]+"); - - int i = 0; - while(i < arr.length) - { - if(arr[i].length() == 0) - { - i++; - continue; - } - - String option = arr[i++]; - if(option.length() != 2 || option.charAt(0) != '-') - { - throw new Ice.EndpointParseException("expected an endpoint option but found `" + option + - "' in endpoint `ssl " + str + "'"); - } - - String argument = null; - if(i < arr.length && arr[i].charAt(0) != '-') - { - argument = arr[i++]; - if(argument.charAt(0) == '\"' && argument.charAt(argument.length() - 1) == '\"') - { - argument = argument.substring(1, argument.length() - 1); - } - } - - switch(option.charAt(1)) - { - case 'h': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -h option in endpoint `ssl " - + str + "'"); - } - - _host = argument; - break; - } - - case 'p': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -p option in endpoint `ssl " - + str + "'"); - } - - try - { - _port = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid port value `" + argument + - "' in endpoint `ssl " + str + "'"); - } - - if(_port < 0 || _port > 65535) - { - throw new Ice.EndpointParseException("port value `" + argument + - "' out of range in endpoint `ssl " + str + "'"); - } - - break; - } - - case 't': - { - if(argument == null) - { - throw new Ice.EndpointParseException("no argument provided for -t option in endpoint `ssl " - + str + "'"); - } - - try - { - _timeout = Integer.parseInt(argument); - } - catch(NumberFormatException ex) - { - throw new Ice.EndpointParseException("invalid timeout value `" + argument + - "' in endpoint `ssl " + str + "'"); - } - - break; - } - - case 'z': - { - if(argument != null) - { - throw new Ice.EndpointParseException("unexpected argument `" + argument + - "' provided for -z option in `ssl " + str + "'"); - } - - _compress = true; - break; - } - - default: - { - throw new Ice.EndpointParseException("unknown option `" + option + "' in `ssl " + str + "'"); - } - } - } - - if(_host == null) - { - _host = _instance.defaultHost(); - } - else if(_host.equals("*")) - { - if(oaEndpoint) - { - _host = null; - } - else - { - throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `ssl " + str + "'"); - } - } - - if(_host == null) - { - _host = ""; - } - - calcHashValue(); } - public - EndpointI(Instance instance, IceInternal.BasicStream s) + public EndpointI(Instance instance, IceInternal.BasicStream s) { - super(""); + super(instance, s); _instance = instance; - s.startReadEncaps(); - _host = s.readString(); - _port = s.readInt(); _timeout = s.readInt(); _compress = s.readBool(); - s.endReadEncaps(); - calcHashValue(); - } - - // - // Marshal the endpoint - // - public void - streamWrite(IceInternal.BasicStream s) - { - s.writeShort(EndpointType.value); - s.startWriteEncaps(); - s.writeString(_host); - s.writeInt(_port); - s.writeInt(_timeout); - s.writeBool(_compress); - s.endWriteEncaps(); - } - - // - // Convert the endpoint to its string form - // - public String - _toString() - { - // - // WARNING: Certain features, such as proxy validation in Glacier2, - // depend on the format of proxy strings. Changes to toString() and - // methods called to generate parts of the reference string could break - // these features. Please review for all features that depend on the - // format of proxyToString() before changing this and related code. - // - String s = "ssl"; - - if(_host != null && _host.length() > 0) - { - s += " -h "; - boolean addQuote = _host.indexOf(':') != -1; - if(addQuote) - { - s += "\""; - } - s += _host; - if(addQuote) - { - s += "\""; - } - } - - s += " -p " + _port; - - if(_timeout != -1) - { - s += " -t " + _timeout; - } - if(_compress) - { - s += " -z"; - } - return s; } // // Return the endpoint information. // - public Ice.EndpointInfo - getInfo() + public Ice.EndpointInfo getInfo() { - return new IceSSL.EndpointInfo(_timeout, _compress, _host, _port) + Ice.IPEndpointInfo info = new IceSSL.EndpointInfo() { public short type() { - return EndpointType.value; + return EndpointI.this.type(); } public boolean datagram() { - return false; + return EndpointI.this.datagram(); } public boolean secure() { - return true; + return EndpointI.this.secure(); } - }; - } - - // - // Return the endpoint type - // - public short - type() - { - return EndpointType.value; - } + }; - // - // Return the protocol name - // - public String - protocol() - { - return "ssl"; + fillEndpointInfo(info); + return info; } // // Return the timeout for the endpoint in milliseconds. 0 means // non-blocking, -1 means no timeout. // - public int - timeout() + public int timeout() { return _timeout; } @@ -296,8 +76,7 @@ final class EndpointI extends IceInternal.EndpointI // that timeouts are supported by the endpoint. Otherwise the same // endpoint is returned. // - public IceInternal.EndpointI - timeout(int timeout) + public IceInternal.EndpointI timeout(int timeout) { if(timeout == _timeout) { @@ -310,27 +89,10 @@ final class EndpointI extends IceInternal.EndpointI } // - // Return a new endpoint with a different connection id. - // - public IceInternal.EndpointI - connectionId(String connectionId) - { - if(connectionId.equals(_connectionId)) - { - return this; - } - else - { - return new EndpointI(_instance, _host, _port, _timeout, connectionId, _compress); - } - } - - // // Return true if the endpoints support bzip2 compress, or false // otherwise. // - public boolean - compress() + public boolean compress() { return _compress; } @@ -340,8 +102,7 @@ final class EndpointI extends IceInternal.EndpointI // provided that compression is supported by the // endpoint. Otherwise the same endpoint is returned. // - public IceInternal.EndpointI - compress(boolean compress) + public IceInternal.EndpointI compress(boolean compress) { if(compress == _compress) { @@ -356,8 +117,7 @@ final class EndpointI extends IceInternal.EndpointI // // Return true if the endpoint is datagram-based. // - public boolean - datagram() + public boolean datagram() { return false; } @@ -365,8 +125,7 @@ final class EndpointI extends IceInternal.EndpointI // // Return true if the endpoint is secure. // - public boolean - secure() + public boolean secure() { return true; } @@ -378,104 +137,54 @@ final class EndpointI extends IceInternal.EndpointI // "effective" endpoint, which might differ from this endpoint, // for example, if a dynamic port number is assigned. // - public IceInternal.Transceiver - transceiver(IceInternal.EndpointIHolder endpoint) + public IceInternal.Transceiver transceiver(IceInternal.EndpointIHolder endpoint) { endpoint.value = this; return null; } // - // Return connectors for this endpoint, or empty list if no connector - // is available. - // - public java.util.List<IceInternal.Connector> - connectors(Ice.EndpointSelectionType selType) - { - return _instance.endpointHostResolver().resolve(_host, _port, selType, this); - } - - public void - connectors_async(Ice.EndpointSelectionType selType, IceInternal.EndpointI_connectors callback) - { - _instance.endpointHostResolver().resolve(_host, _port, selType, this, callback); - } - - // // Return an acceptor for this endpoint, or null if no acceptors // is available. In case an acceptor is created, this operation // also returns a new "effective" endpoint, which might differ // from this endpoint, for example, if a dynamic port number is // assigned. // - public IceInternal.Acceptor - acceptor(IceInternal.EndpointIHolder endpoint, String adapterName) + public IceInternal.Acceptor acceptor(IceInternal.EndpointIHolder endpoint, String adapterName) { AcceptorI p = new AcceptorI(_instance, adapterName, _host, _port); endpoint.value = new EndpointI(_instance, _host, p.effectivePort(), _timeout, _connectionId, _compress); return p; } - // - // Expand endpoint out in to separate endpoints for each local - // host if listening on INADDR_ANY. - // - public java.util.List<IceInternal.EndpointI> - expand() + public String options() { - java.util.ArrayList<IceInternal.EndpointI> endps = new java.util.ArrayList<IceInternal.EndpointI>(); - java.util.ArrayList<String> hosts = - IceInternal.Network.getHostsForEndpointExpand(_host, _instance.protocolSupport(), false); - if(hosts == null || hosts.isEmpty()) - { - endps.add(this); - } - else - { - for(String host : hosts) - { - endps.add(new EndpointI(_instance, host, _port, _timeout, _connectionId, _compress)); - } - } - return endps; - } + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = super.options(); - // - // Check whether the endpoint is equivalent to a specific Connector. - // - public boolean - equivalent(IceInternal.EndpointI endpoint) - { - if(!(endpoint instanceof EndpointI)) + if(_timeout != -1) { - return false; + s += " -t " + _timeout; } - EndpointI sslEndpointI = (EndpointI)endpoint; - return sslEndpointI._host.equals(_host) && sslEndpointI._port == _port; - } - public java.util.List<IceInternal.Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses, IceInternal.NetworkProxy proxy) - { - java.util.List<IceInternal.Connector> connectors = new java.util.ArrayList<IceInternal.Connector>(); - for(java.net.InetSocketAddress p : addresses) + if(_compress) { - connectors.add(new ConnectorI(_instance, _host, p, proxy, _timeout, _connectionId)); + s += " -z"; } - return connectors; - } - public int - hashCode() - { - return _hashCode; + return s; } // // Compare endpoints for sorting purposes // - public int - compareTo(IceInternal.EndpointI obj) // From java.lang.Comparable + public int compareTo(IceInternal.EndpointI obj) // From java.lang.Comparable { if(!(obj instanceof EndpointI)) { @@ -487,23 +196,6 @@ final class EndpointI extends IceInternal.EndpointI { return 0; } - else - { - int r = super.compareTo(p); - if(r != 0) - { - return r; - } - } - - if(_port < p._port) - { - return -1; - } - else if(p._port < _port) - { - return 1; - } if(_timeout < p._timeout) { @@ -523,26 +215,94 @@ final class EndpointI extends IceInternal.EndpointI return 1; } - return _host.compareTo(p._host); + return super.compareTo(obj); + } + + protected void streamWriteImpl(IceInternal.BasicStream s) + { + super.streamWriteImpl(s); + s.writeInt(_timeout); + s.writeBool(_compress); } - private void - calcHashValue() + protected int hashInit(int h) { - int h = 5381; - h = IceInternal.HashUtil.hashAdd(h, EndpointType.value); - h = IceInternal.HashUtil.hashAdd(h, _host); - h = IceInternal.HashUtil.hashAdd(h, _port); + h = super.hashInit(h); h = IceInternal.HashUtil.hashAdd(h, _timeout); - h = IceInternal.HashUtil.hashAdd(h, _connectionId); h = IceInternal.HashUtil.hashAdd(h, _compress); - _hashCode = h; + return h; + } + + protected void fillEndpointInfo(Ice.IPEndpointInfo info) + { + super.fillEndpointInfo(info); + if(info instanceof IceSSL.EndpointInfo) + { + IceSSL.EndpointInfo sslInfo = (IceSSL.EndpointInfo)info; + sslInfo.timeout = _timeout; + sslInfo.compress = _compress; + } + } + + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + switch(option.charAt(1)) + { + case 't': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + try + { + _timeout = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + "' in endpoint " + + endpoint); + } + + return true; + } + + case 'z': + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + return true; + } + + default: + { + return false; + } + } + } + + protected IceInternal.Connector createConnector(java.net.InetSocketAddress addr, IceInternal.NetworkProxy proxy) + { + return new ConnectorI(_instance, _host, addr, proxy, _timeout, _connectionId); + } + + protected IceInternal.IPEndpointI createEndpoint(String host, int port, String connectionId) + { + return new EndpointI(_instance, host, port, _timeout, connectionId, _compress); } private Instance _instance; - private String _host; - private int _port; private int _timeout; private boolean _compress; - private int _hashCode; } diff --git a/java/src/IceSSL/Instance.java b/java/src/IceSSL/Instance.java index 741199480b5..944d6d95074 100644 --- a/java/src/IceSSL/Instance.java +++ b/java/src/IceSSL/Instance.java @@ -13,1196 +13,54 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; -class Instance +class Instance extends IceInternal.ProtocolInstance { - Instance(Ice.Communicator communicator) + Instance(SharedInstance sharedInstance, short type, String protocol) { - _logger = communicator.getLogger(); - _facade = IceInternal.Util.getProtocolPluginFacade(communicator); - _securityTraceLevel = communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); - _securityTraceCategory = "Security"; - _trustManager = new TrustManager(communicator); - - // - // Register the endpoint factory. We have to do this now, rather than - // in initialize, because the communicator may need to interpret - // proxies before the plug-in is fully initialized. - // - _facade.addEndpointFactory(new EndpointFactoryI(this)); - } - - void - initialize() - { - if(_initialized) - { - return; - } - - final String prefix = "IceSSL."; - Ice.Properties properties = communicator().getProperties(); - - // - // Parse the cipher list. - // - String ciphers = properties.getProperty(prefix + "Ciphers"); - if(ciphers.length() > 0) - { - parseCiphers(ciphers); - } - - // - // Select protocols. - // - String[] protocols = properties.getPropertyAsList(prefix + "Protocols"); - if(protocols.length != 0) - { - java.util.ArrayList<String> l = new java.util.ArrayList<String>(); - for(String prot : protocols) - { - String s = prot.toLowerCase(); - if(s.equals("ssl3") || s.equals("sslv3")) - { - l.add("SSLv3"); - } - else if(s.equals("tls") || s.equals("tls1") || s.equals("tlsv1") || s.equals("tls1_0") || - s.equals("tlsv1_0")) - { - l.add("TLSv1"); - } - else if(s.equals("tls1_1") || s.equals("tlsv1_1")) - { - l.add("TLSv1.1"); - } - else if(s.equals("tls1_2") || s.equals("tlsv1_2")) - { - l.add("TLSv1.2"); - } - else - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unrecognized protocol `" + prot + "'"; - throw e; - } - } - _protocols = new String[l.size()]; - l.toArray(_protocols); - } - - // - // CheckCertName determines whether we compare the name in a peer's - // certificate against its hostname. - // - _checkCertName = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0; - - // - // VerifyDepthMax establishes the maximum length of a peer's certificate - // chain, including the peer's certificate. A value of 0 means there is - // no maximum. - // - _verifyDepthMax = properties.getPropertyAsIntWithDefault(prefix + "VerifyDepthMax", 2); - - // - // VerifyPeer determines whether certificate validation failures abort a connection. - // - _verifyPeer = communicator().getProperties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2); - - // - // Check for a certificate verifier. - // - final String certVerifierClass = properties.getProperty(prefix + "CertVerifier"); - if(certVerifierClass.length() > 0) - { - if(_verifier != null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: certificate verifier already installed"; - throw e; - } - - Class<?> cls = null; - try - { - cls = _facade.findClass(certVerifierClass); - } - catch(Throwable ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to load certificate verifier class " + certVerifierClass, ex); - } - - try - { - _verifier = (CertificateVerifier)cls.newInstance(); - } - catch(Throwable ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to instantiate certificate verifier class " + certVerifierClass, ex); - } - } - - // - // Check for a password callback. - // - final String passwordCallbackClass = properties.getProperty(prefix + "PasswordCallback"); - if(passwordCallbackClass.length() > 0) - { - if(_passwordCallback != null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: password callback already installed"; - throw e; - } - - Class<?> cls = null; - try - { - cls = _facade.findClass(passwordCallbackClass); - } - catch(Throwable ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to load password callback class " + passwordCallbackClass, ex); - } - - try - { - _passwordCallback = (PasswordCallback)cls.newInstance(); - } - catch(Throwable ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to instantiate password callback class " + passwordCallbackClass, ex); - } - } - - // - // If the user doesn't supply an SSLContext, we need to create one based - // on property settings. - // - if(_context == null) - { - try - { - // - // Check for a default directory. We look in this directory for - // files mentioned in the configuration. - // - _defaultDir = properties.getProperty(prefix + "DefaultDir"); - - // - // We need a SecureRandom object. - // - // NOTE: The JDK recommends obtaining a SecureRandom object like this: - // - // java.security.SecureRandom rand = java.security.SecureRandom.getInstance("SHA1PRNG"); - // - // However, there is a bug (6202721) which causes it to always use /dev/random, - // which can lead to long delays at program startup. The workaround is to use - // the default constructor. - // - java.security.SecureRandom rand = new java.security.SecureRandom(); - - // - // Check for seed data for the random number generator. - // - final String seedFiles = properties.getProperty(prefix + "Random"); - if(seedFiles.length() > 0) - { - final String[] arr = seedFiles.split(java.io.File.pathSeparator); - for(String file : arr) - { - try - { - java.io.InputStream seedStream = openResource(file); - if(seedStream == null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: random seed file not found:\n" + file; - throw e; - } - - _seeds.add(seedStream); - } - catch(java.io.IOException ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to access random seed file:\n" + file, ex); - } - } - } - - if(!_seeds.isEmpty()) - { - byte[] seed = null; - int start = 0; - for(InputStream in : _seeds) - { - try - { - int num = in.available(); - if(seed == null) - { - seed = new byte[num]; - } - else - { - byte[] tmp = new byte[seed.length + num]; - System.arraycopy(seed, 0, tmp, 0, seed.length); - start = seed.length; - seed = tmp; - } - in.read(seed, start, num); - } - catch(java.io.IOException ex) - { - throw new Ice.PluginInitializationException("IceSSL: error while reading random seed", ex); - } - finally - { - try - { - in.close(); - } - catch(java.io.IOException e) - { - // Ignore. - } - } - } - rand.setSeed(seed); - } - _seeds.clear(); - - // - // We call nextInt() in order to force the object to perform any time-consuming - // initialization tasks now. - // - rand.nextInt(); - - // - // The keystore holds private keys and associated certificates. - // - String keystorePath = properties.getProperty(prefix + "Keystore"); - - // - // The password for the keys. - // - String password = properties.getProperty(prefix + "Password"); - - // - // The password for the keystore. - // - String keystorePassword = properties.getProperty(prefix + "KeystorePassword"); - - // - // The default keystore type is usually "JKS", but the legal values are determined - // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". - // - final String defaultType = java.security.KeyStore.getDefaultType(); - final String keystoreType = properties.getPropertyWithDefault(prefix + "KeystoreType", defaultType); - - // - // The alias of the key to use in authentication. - // - final String alias = properties.getProperty(prefix + "Alias"); - - // - // The truststore holds the certificates of trusted CAs. - // - String truststorePath = properties.getProperty(prefix + "Truststore"); - - // - // The password for the truststore. - // - String truststorePassword = properties.getProperty(prefix + "TruststorePassword"); - - // - // The default truststore type is usually "JKS", but the legal values are determined - // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". - // - final String truststoreType = - properties.getPropertyWithDefault(prefix + "TruststoreType", - java.security.KeyStore.getDefaultType()); - - // - // Collect the key managers. - // - javax.net.ssl.KeyManager[] keyManagers = null; - java.security.KeyStore keys = null; - if(_keystoreStream != null || keystorePath.length() > 0) - { - java.io.InputStream keystoreStream = null; - try - { - if(_keystoreStream != null) - { - keystoreStream = _keystoreStream; - } - else - { - keystoreStream = openResource(keystorePath); - if(keystoreStream == null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: keystore not found:\n" + keystorePath; - throw e; - } - } - - keys = java.security.KeyStore.getInstance(keystoreType); - char[] passwordChars = null; - if(keystorePassword.length() > 0) - { - passwordChars = keystorePassword.toCharArray(); - } - else if(_passwordCallback != null) - { - passwordChars = _passwordCallback.getKeystorePassword(); - } - else if(keystoreType.equals("BKS")) - { - // Bouncy Castle does not permit null passwords. - passwordChars = new char[0]; - } - - keys.load(keystoreStream, passwordChars); - - if(passwordChars != null) - { - java.util.Arrays.fill(passwordChars, '\0'); - } - keystorePassword = null; - } - catch(java.io.IOException ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to load keystore:\n" + keystorePath, ex); - } - finally - { - if(keystoreStream != null) - { - try - { - keystoreStream.close(); - } - catch(java.io.IOException e) - { - // Ignore. - } - } - } - - String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(); - javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm); - char[] passwordChars = new char[0]; // This password cannot be null. - if(password.length() > 0) - { - passwordChars = password.toCharArray(); - } - else if(_passwordCallback != null) - { - passwordChars = _passwordCallback.getPassword(alias); - } - kmf.init(keys, passwordChars); - if(passwordChars.length > 0) - { - java.util.Arrays.fill(passwordChars, '\0'); - } - password = null; - keyManagers = kmf.getKeyManagers(); - - // - // If the user selected a specific alias, we need to wrap the key managers - // in order to return the desired alias. - // - if(alias.length() > 0) - { - if(!keys.isKeyEntry(alias)) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'"; - throw e; - } - - for(int i = 0; i < keyManagers.length; ++i) - { - keyManagers[i] = new X509KeyManagerI((javax.net.ssl.X509KeyManager)keyManagers[i], alias); - } - } - } - - // - // Load the truststore. - // - java.security.KeyStore ts = null; - if(_truststoreStream != null || truststorePath.length() > 0) - { - // - // If the trust store and the key store are the same input - // stream or file, don't create another key store. - // - if((_truststoreStream != null && _truststoreStream == _keystoreStream) || - (truststorePath.length() > 0 && truststorePath.equals(keystorePath))) - { - assert keys != null; - ts = keys; - } - else - { - java.io.InputStream truststoreStream = null; - try - { - if(_truststoreStream != null) - { - truststoreStream = _truststoreStream; - } - else - { - truststoreStream = openResource(truststorePath); - if(truststoreStream == null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: truststore not found:\n" + truststorePath; - throw e; - } - } - - ts = java.security.KeyStore.getInstance(truststoreType); - - char[] passwordChars = null; - if(truststorePassword.length() > 0) - { - passwordChars = truststorePassword.toCharArray(); - } - else if(_passwordCallback != null) - { - passwordChars = _passwordCallback.getTruststorePassword(); - } - else if(truststoreType.equals("BKS")) - { - // Bouncy Castle does not permit null passwords. - passwordChars = new char[0]; - } - - ts.load(truststoreStream, passwordChars); - - if(passwordChars != null) - { - java.util.Arrays.fill(passwordChars, '\0'); - } - truststorePassword = null; - } - catch(java.io.IOException ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: unable to load truststore:\n" + truststorePath, ex); - } - finally - { - if(truststoreStream != null) - { - try - { - truststoreStream.close(); - } - catch(java.io.IOException e) - { - // Ignore. - } - } - } - } - } - else - { - ts = keys; - } - - // - // Collect the trust managers. - // - javax.net.ssl.TrustManager[] trustManagers = null; - { - String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm(); - javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm); - tmf.init(ts); - trustManagers = tmf.getTrustManagers(); - assert(trustManagers != null); - } - - // - // Wrap each trust manager. - // - for(int i = 0; i < trustManagers.length; ++i) - { - trustManagers[i] = new X509TrustManagerI(this, (javax.net.ssl.X509TrustManager)trustManagers[i]); - } - - // - // Initialize the SSL context. - // - _context = javax.net.ssl.SSLContext.getInstance("TLS"); - _context.init(keyManagers, trustManagers, rand); - } - catch(java.security.GeneralSecurityException ex) - { - throw new Ice.PluginInitializationException("IceSSL: unable to initialize context", ex); - } - } - - // - // Clear cached input streams. - // - _seeds.clear(); - _keystoreStream = null; - _truststoreStream = null; - - _initialized = true; - } - - void - context(javax.net.ssl.SSLContext context) - { - if(_initialized) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: plug-in is already initialized"; - throw ex; - } - - _context = context; - } - - javax.net.ssl.SSLContext - context() - { - return _context; - } - - void - setCertificateVerifier(CertificateVerifier verifier) - { - _verifier = verifier; - } - - CertificateVerifier - getCertificateVerifier() - { - return _verifier; - } - - void - setPasswordCallback(PasswordCallback callback) - { - _passwordCallback = callback; - } - - PasswordCallback - getPasswordCallback() - { - return _passwordCallback; - } - - void - setKeystoreStream(java.io.InputStream stream) - { - if(_initialized) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: plugin is already initialized"; - throw ex; - } - - _keystoreStream = stream; - } - - void - setTruststoreStream(java.io.InputStream stream) - { - if(_initialized) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: plugin is already initialized"; - throw ex; - } - - _truststoreStream = stream; - } - - void - addSeedStream(java.io.InputStream stream) - { - _seeds.add(stream); - } - - Ice.Communicator - communicator() - { - return _facade.getCommunicator(); - } - - IceInternal.EndpointHostResolver - endpointHostResolver() - { - return _facade.getEndpointHostResolver(); - } - - int - protocolSupport() - { - return _facade.getProtocolSupport(); - } - - boolean - preferIPv6() - { - return _facade.getPreferIPv6(); + super(sharedInstance.communicator(), type, protocol); + _sharedInstance = sharedInstance; } - Ice.EncodingVersion - defaultEncoding() + SharedInstance sharedInstance() { - return _facade.getDefaultEncoding(); + return _sharedInstance; } - String - defaultHost() + int securityTraceLevel() { - return _facade.getDefaultHost(); + return _sharedInstance.securityTraceLevel(); } - int - networkTraceLevel() + String securityTraceCategory() { - return _facade.getNetworkTraceLevel(); + return _sharedInstance.securityTraceCategory(); } - String - networkTraceCategory() + boolean initialized() { - return _facade.getNetworkTraceCategory(); + return _sharedInstance.initialized(); } - int - securityTraceLevel() + javax.net.ssl.SSLEngine createSSLEngine(boolean incoming, java.net.InetSocketAddress peerAddr) { - return _securityTraceLevel; + return _sharedInstance.createSSLEngine(incoming, peerAddr); } - String - securityTraceCategory() + void traceConnection(java.nio.channels.SocketChannel fd, javax.net.ssl.SSLEngine engine, boolean incoming) { - return _securityTraceCategory; + _sharedInstance.traceConnection(fd, engine, incoming); } - boolean - initialized() + void verifyPeer(NativeConnectionInfo info, java.nio.channels.SelectableChannel fd, String address) { - return _initialized; + _sharedInstance.verifyPeer(info, fd, address); } - javax.net.ssl.SSLEngine - createSSLEngine(boolean incoming, java.net.InetSocketAddress peerAddr) - { - javax.net.ssl.SSLEngine engine; - if(peerAddr != null) - { - engine = _context.createSSLEngine(peerAddr.getAddress().getHostAddress(), peerAddr.getPort()); - } - else - { - engine = _context.createSSLEngine(); - } - engine.setUseClientMode(!incoming); - - String[] cipherSuites = filterCiphers(engine.getSupportedCipherSuites(), engine.getEnabledCipherSuites()); - try - { - engine.setEnabledCipherSuites(cipherSuites); - } - catch(IllegalArgumentException ex) - { - throw new Ice.SecurityException("IceSSL: invalid ciphersuite", ex); - } - - if(_securityTraceLevel >= 1) - { - StringBuilder s = new StringBuilder(128); - s.append("enabling SSL ciphersuites:"); - for(String suite : cipherSuites) - { - s.append("\n "); - s.append(suite); - } - _logger.trace(_securityTraceCategory, s.toString()); - } - - if(_protocols != null) - { - try - { - engine.setEnabledProtocols(_protocols); - } - catch(IllegalArgumentException ex) - { - throw new Ice.SecurityException("IceSSL: invalid protocol", ex); - } - } - - if(incoming) - { - if(_verifyPeer == 0) - { - engine.setWantClientAuth(false); - engine.setNeedClientAuth(false); - } - else if(_verifyPeer == 1) - { - engine.setWantClientAuth(true); - } - else - { - engine.setNeedClientAuth(true); - } - } - - try - { - engine.beginHandshake(); - } - catch(javax.net.ssl.SSLException ex) - { - throw new Ice.SecurityException("IceSSL: handshake error", ex); - } - - return engine; - } - - String[] - filterCiphers(String[] supportedCiphers, String[] defaultCiphers) - { - java.util.LinkedList<String> result = new java.util.LinkedList<String>(); - if(_allCiphers) - { - for(String cipher : supportedCiphers) - { - result.add(cipher); - } - } - else if(!_noCiphers) - { - for(String cipher : defaultCiphers) - { - result.add(cipher); - } - } - - if(_ciphers != null) - { - for(CipherExpression ce : _ciphers) - { - if(ce.not) - { - java.util.Iterator<String> e = result.iterator(); - while(e.hasNext()) - { - String cipher = e.next(); - if(ce.cipher != null) - { - if(ce.cipher.equals(cipher)) - { - e.remove(); - } - } - else - { - assert(ce.re != null); - java.util.regex.Matcher m = ce.re.matcher(cipher); - if(m.find()) - { - e.remove(); - } - } - } - } - else - { - if(ce.cipher != null) - { - result.add(0, ce.cipher); - } - else - { - assert(ce.re != null); - for(String cipher : supportedCiphers) - { - java.util.regex.Matcher m = ce.re.matcher(cipher); - if(m.find()) - { - result.add(0, cipher); - } - } - } - } - } - } - - String[] arr = new String[result.size()]; - result.toArray(arr); - return arr; - } - - String[] - protocols() - { - return _protocols; - } - - void - traceConnection(java.nio.channels.SocketChannel fd, javax.net.ssl.SSLEngine engine, boolean incoming) - { - javax.net.ssl.SSLSession session = engine.getSession(); - String msg = "SSL summary for " + (incoming ? "incoming" : "outgoing") + " connection\n" + - "cipher = " + session.getCipherSuite() + "\n" + - "protocol = " + session.getProtocol() + "\n" + - IceInternal.Network.fdToString(fd); - _logger.trace(_securityTraceCategory, msg); - } - - void - verifyPeer(NativeConnectionInfo info, java.nio.channels.SelectableChannel fd, String address) - { - // - // For an outgoing connection, we compare the proxy address (if any) against - // fields in the server's certificate (if any). - // - if(info.nativeCerts != null && info.nativeCerts.length > 0 && address.length() > 0) - { - java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate)info.nativeCerts[0]; - - // - // Extract the IP addresses and the DNS names from the subject - // alternative names. - // - java.util.ArrayList<String> ipAddresses = new java.util.ArrayList<String>(); - java.util.ArrayList<String> dnsNames = new java.util.ArrayList<String>(); - try - { - java.util.Collection<java.util.List<?> > subjectAltNames = cert.getSubjectAlternativeNames(); - if(subjectAltNames != null) - { - for(java.util.List<?> l : subjectAltNames) - { - assert(!l.isEmpty()); - Integer n = (Integer)l.get(0); - if(n.intValue() == 7) - { - ipAddresses.add((String)l.get(1)); - } - else if(n.intValue() == 2) - { - dnsNames.add(((String)l.get(1)).toLowerCase()); - } - } - } - } - catch(java.security.cert.CertificateParsingException ex) - { - assert(false); - } - - // - // Compare the peer's address against the common name as well as - // the dnsName and ipAddress values in the subject alternative name. - // - boolean certNameOK = false; - String dn = ""; - String addrLower = address.toLowerCase(); - { - javax.security.auth.x500.X500Principal principal = cert.getSubjectX500Principal(); - dn = principal.getName(javax.security.auth.x500.X500Principal.CANONICAL); - // - // Canonical format is already in lower case. - // - String cn = "cn=" + addrLower; - int pos = dn.indexOf(cn); - if(pos >= 0) - { - // - // Ensure we match the entire common name. - // - certNameOK = (pos + cn.length() == dn.length()) || (dn.charAt(pos + cn.length()) == ','); - } - } - - // - // Compare the peer's address against the dnsName and ipAddress - // values in the subject alternative name. - // - if(!certNameOK) - { - certNameOK = ipAddresses.contains(addrLower); - } - if(!certNameOK) - { - certNameOK = dnsNames.contains(addrLower); - } - - // - // Log a message if the name comparison fails. If CheckCertName is defined, - // we also raise an exception to abort the connection. Don't log a message if - // CheckCertName is not defined and a verifier is present. - // - if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && _verifier == null))) - { - StringBuilder sb = new StringBuilder(128); - sb.append("IceSSL: "); - if(!_checkCertName) - { - sb.append("ignoring "); - } - sb.append("certificate validation failure:\npeer certificate does not have `"); - sb.append(address); - sb.append("' as its commonName or in its subjectAltName extension"); - if(dn.length() > 0) - { - sb.append("\nSubject DN: "); - sb.append(dn); - } - if(!dnsNames.isEmpty()) - { - sb.append("\nDNS names found in certificate: "); - for(int j = 0; j < dnsNames.size(); ++j) - { - if(j > 0) - { - sb.append(", "); - } - sb.append(dnsNames.get(j)); - } - } - if(!ipAddresses.isEmpty()) - { - sb.append("\nIP addresses found in certificate: "); - for(int j = 0; j < ipAddresses.size(); ++j) - { - if(j > 0) - { - sb.append(", "); - } - sb.append(ipAddresses.get(j)); - } - } - if(_securityTraceLevel >= 1) - { - _logger.trace(_securityTraceCategory, sb.toString()); - } - if(_checkCertName) - { - Ice.SecurityException ex = new Ice.SecurityException(); - ex.reason = sb.toString(); - throw ex; - } - } - } - - if(_verifyDepthMax > 0 && info.nativeCerts != null && info.nativeCerts.length > _verifyDepthMax) - { - String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected:\n" + - "length of peer's certificate chain (" + info.nativeCerts.length + ") exceeds maximum of " + - _verifyDepthMax + "\n" + - IceInternal.Network.fdToString(fd); - if(_securityTraceLevel >= 1) - { - _logger.trace(_securityTraceCategory, msg); - } - Ice.SecurityException ex = new Ice.SecurityException(); - ex.reason = msg; - throw ex; - } - - if(!_trustManager.verify(info)) - { - String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by trust manager\n" + - IceInternal.Network.fdToString(fd); - if(_securityTraceLevel >= 1) - { - _logger.trace(_securityTraceCategory, msg); - } - Ice.SecurityException ex = new Ice.SecurityException(); - ex.reason = msg; - throw ex; - } - - if(_verifier != null && !_verifier.verify(info)) - { - String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier\n" + - IceInternal.Network.fdToString(fd); - if(_securityTraceLevel >= 1) - { - _logger.trace(_securityTraceCategory, msg); - } - Ice.SecurityException ex = new Ice.SecurityException(); - ex.reason = msg; - throw ex; - } - } - - void - trustManagerFailure(boolean incoming, java.security.cert.CertificateException ex) + void trustManagerFailure(boolean incoming, java.security.cert.CertificateException ex) throws java.security.cert.CertificateException { - if(_verifyPeer == 0) - { - if(_securityTraceLevel >= 1) - { - String msg = "ignoring peer verification failure"; - if(_securityTraceLevel > 1) - { - java.io.StringWriter sw = new java.io.StringWriter(); - java.io.PrintWriter pw = new java.io.PrintWriter(sw); - ex.printStackTrace(pw); - pw.flush(); - msg += ":\n" + sw.toString(); - } - _logger.trace(_securityTraceCategory, msg); - } - } - else - { - throw ex; - } - } - - private void - parseCiphers(String ciphers) - { - java.util.ArrayList<CipherExpression> cipherList = new java.util.ArrayList<CipherExpression>(); - String[] expr = ciphers.split("[ \t]+"); - for(int i = 0; i < expr.length; ++i) - { - if(expr[i].equals("ALL")) - { - if(i != 0) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: `ALL' must be first in cipher list `" + ciphers + "'"; - throw ex; - } - _allCiphers = true; - } - else if(expr[i].equals("NONE")) - { - if(i != 0) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: `NONE' must be first in cipher list `" + ciphers + "'"; - throw ex; - } - _noCiphers = true; - } - else - { - CipherExpression ce = new CipherExpression(); - String exp = expr[i]; - if(exp.charAt(0) == '!') - { - ce.not = true; - if(exp.length() > 1) - { - exp = exp.substring(1); - } - else - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; - throw ex; - } - } - - if(exp.charAt(0) == '(') - { - if(!exp.endsWith(")")) - { - Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); - ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; - throw ex; - } - - try - { - ce.re = java.util.regex.Pattern.compile(exp.substring(1, exp.length() - 2)); - } - catch(java.util.regex.PatternSyntaxException ex) - { - throw new Ice.PluginInitializationException( - "IceSSL: invalid cipher expression `" + exp + "'", ex); - } - } - else - { - ce.cipher = exp; - } - - cipherList.add(ce); - } - } - _ciphers = new CipherExpression[cipherList.size()]; - cipherList.toArray(_ciphers); - } - - private java.io.InputStream - openResource(String path) - throws java.io.IOException - { - // - // This method wraps a call to IceInternal.Util.openResource. If the first call fails and - // IceSSL.DefaultDir is defined, prepend the default directory and try again. - // - java.io.InputStream stream = IceInternal.Util.openResource(getClass().getClassLoader(), path); - if(stream == null && _defaultDir.length() > 0) - { - stream = IceInternal.Util.openResource(getClass().getClassLoader(), - _defaultDir + java.io.File.separator + path); - } - - if(stream != null) - { - stream = new java.io.BufferedInputStream(stream); - } - - return stream; - } - - private static class CipherExpression - { - boolean not; - String cipher; - java.util.regex.Pattern re; + _sharedInstance.trustManagerFailure(incoming, ex); } - private Ice.Logger _logger; - private IceInternal.ProtocolPluginFacade _facade; - private int _securityTraceLevel; - private String _securityTraceCategory; - private boolean _initialized; - private javax.net.ssl.SSLContext _context; - private String _defaultDir; - private CipherExpression[] _ciphers; - private boolean _allCiphers; - private boolean _noCiphers; - private String[] _protocols; - private boolean _checkCertName; - private int _verifyDepthMax; - private int _verifyPeer; - private CertificateVerifier _verifier; - private PasswordCallback _passwordCallback; - private TrustManager _trustManager; - - private InputStream _keystoreStream; - private InputStream _truststoreStream; - private List<InputStream> _seeds = new ArrayList<InputStream>(); + private SharedInstance _sharedInstance; } diff --git a/java/src/IceSSL/PluginI.java b/java/src/IceSSL/PluginI.java index 9f19809aa54..ba714104582 100644 --- a/java/src/IceSSL/PluginI.java +++ b/java/src/IceSSL/PluginI.java @@ -11,76 +11,74 @@ package IceSSL; class PluginI implements Plugin { - public - PluginI(Ice.Communicator communicator) + public PluginI(Ice.Communicator communicator) { - _instance = new Instance(communicator); + IceInternal.ProtocolPluginFacade facade = IceInternal.Util.getProtocolPluginFacade(communicator); + + _sharedInstance = new SharedInstance(facade); + + // + // Register the endpoint factory. We have to do this now, rather than + // in initialize, because the communicator may need to interpret + // proxies before the plug-in is fully initialized. + // + facade.addEndpointFactory( + new EndpointFactoryI(new Instance(_sharedInstance, IceSSL.EndpointType.value, "ssl"))); } - public void - initialize() + public void initialize() { - _instance.initialize(); + _sharedInstance.initialize(); } - public void - destroy() + public void destroy() { } - public void - setContext(javax.net.ssl.SSLContext context) + public void setContext(javax.net.ssl.SSLContext context) { - _instance.context(context); + _sharedInstance.context(context); } - public javax.net.ssl.SSLContext - getContext() + public javax.net.ssl.SSLContext getContext() { - return _instance.context(); + return _sharedInstance.context(); } - public void - setCertificateVerifier(CertificateVerifier verifier) + public void setCertificateVerifier(CertificateVerifier verifier) { - _instance.setCertificateVerifier(verifier); + _sharedInstance.setCertificateVerifier(verifier); } - public CertificateVerifier - getCertificateVerifier() + public CertificateVerifier getCertificateVerifier() { - return _instance.getCertificateVerifier(); + return _sharedInstance.getCertificateVerifier(); } - public void - setPasswordCallback(PasswordCallback callback) + public void setPasswordCallback(PasswordCallback callback) { - _instance.setPasswordCallback(callback); + _sharedInstance.setPasswordCallback(callback); } - public PasswordCallback - getPasswordCallback() + public PasswordCallback getPasswordCallback() { - return _instance.getPasswordCallback(); + return _sharedInstance.getPasswordCallback(); } - public void - setKeystoreStream(java.io.InputStream stream) + public void setKeystoreStream(java.io.InputStream stream) { - _instance.setKeystoreStream(stream); + _sharedInstance.setKeystoreStream(stream); } - public void - setTruststoreStream(java.io.InputStream stream) + public void setTruststoreStream(java.io.InputStream stream) { - _instance.setTruststoreStream(stream); + _sharedInstance.setTruststoreStream(stream); } - public void - addSeedStream(java.io.InputStream stream) + public void addSeedStream(java.io.InputStream stream) { - _instance.addSeedStream(stream); + _sharedInstance.addSeedStream(stream); } - private Instance _instance; + private SharedInstance _sharedInstance; } diff --git a/java/src/IceSSL/SharedInstance.java b/java/src/IceSSL/SharedInstance.java new file mode 100644 index 00000000000..842dfe4b157 --- /dev/null +++ b/java/src/IceSSL/SharedInstance.java @@ -0,0 +1,1140 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +class SharedInstance +{ + SharedInstance(IceInternal.ProtocolPluginFacade facade) + { + _communicator = facade.getCommunicator(); + _logger = _communicator.getLogger(); + _facade = facade; + _securityTraceLevel = _communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); + _securityTraceCategory = "Security"; + _trustManager = new TrustManager(_communicator); + } + + void initialize() + { + if(_initialized) + { + return; + } + + final String prefix = "IceSSL."; + Ice.Properties properties = communicator().getProperties(); + + // + // Parse the cipher list. + // + String ciphers = properties.getProperty(prefix + "Ciphers"); + if(ciphers.length() > 0) + { + parseCiphers(ciphers); + } + + // + // Select protocols. + // + String[] protocols = properties.getPropertyAsList(prefix + "Protocols"); + if(protocols.length != 0) + { + java.util.ArrayList<String> l = new java.util.ArrayList<String>(); + for(String prot : protocols) + { + String s = prot.toLowerCase(); + if(s.equals("ssl3") || s.equals("sslv3")) + { + l.add("SSLv3"); + } + else if(s.equals("tls") || s.equals("tls1") || s.equals("tlsv1") || s.equals("tls1_0") || + s.equals("tlsv1_0")) + { + l.add("TLSv1"); + } + else if(s.equals("tls1_1") || s.equals("tlsv1_1")) + { + l.add("TLSv1.1"); + } + else if(s.equals("tls1_2") || s.equals("tlsv1_2")) + { + l.add("TLSv1.2"); + } + else + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unrecognized protocol `" + prot + "'"; + throw e; + } + } + _protocols = new String[l.size()]; + l.toArray(_protocols); + } + + // + // CheckCertName determines whether we compare the name in a peer's + // certificate against its hostname. + // + _checkCertName = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0; + + // + // VerifyDepthMax establishes the maximum length of a peer's certificate + // chain, including the peer's certificate. A value of 0 means there is + // no maximum. + // + _verifyDepthMax = properties.getPropertyAsIntWithDefault(prefix + "VerifyDepthMax", 2); + + // + // VerifyPeer determines whether certificate validation failures abort a connection. + // + _verifyPeer = properties.getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2); + + // + // Check for a certificate verifier. + // + final String certVerifierClass = properties.getProperty(prefix + "CertVerifier"); + if(certVerifierClass.length() > 0) + { + if(_verifier != null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: certificate verifier already installed"; + throw e; + } + + Class<?> cls = null; + try + { + cls = _facade.findClass(certVerifierClass); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load certificate verifier class " + certVerifierClass, ex); + } + + try + { + _verifier = (CertificateVerifier)cls.newInstance(); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to instantiate certificate verifier class " + certVerifierClass, ex); + } + } + + // + // Check for a password callback. + // + final String passwordCallbackClass = properties.getProperty(prefix + "PasswordCallback"); + if(passwordCallbackClass.length() > 0) + { + if(_passwordCallback != null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: password callback already installed"; + throw e; + } + + Class<?> cls = null; + try + { + cls = _facade.findClass(passwordCallbackClass); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load password callback class " + passwordCallbackClass, ex); + } + + try + { + _passwordCallback = (PasswordCallback)cls.newInstance(); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to instantiate password callback class " + passwordCallbackClass, ex); + } + } + + // + // If the user doesn't supply an SSLContext, we need to create one based + // on property settings. + // + if(_context == null) + { + try + { + // + // Check for a default directory. We look in this directory for + // files mentioned in the configuration. + // + _defaultDir = properties.getProperty(prefix + "DefaultDir"); + + // + // We need a SecureRandom object. + // + // NOTE: The JDK recommends obtaining a SecureRandom object like this: + // + // java.security.SecureRandom rand = java.security.SecureRandom.getInstance("SHA1PRNG"); + // + // However, there is a bug (6202721) which causes it to always use /dev/random, + // which can lead to long delays at program startup. The workaround is to use + // the default constructor. + // + java.security.SecureRandom rand = new java.security.SecureRandom(); + + // + // Check for seed data for the random number generator. + // + final String seedFiles = properties.getProperty(prefix + "Random"); + if(seedFiles.length() > 0) + { + final String[] arr = seedFiles.split(java.io.File.pathSeparator); + for(String file : arr) + { + try + { + java.io.InputStream seedStream = openResource(file); + if(seedStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: random seed file not found:\n" + file; + throw e; + } + + _seeds.add(seedStream); + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to access random seed file:\n" + file, ex); + } + } + } + + if(!_seeds.isEmpty()) + { + byte[] seed = null; + int start = 0; + for(InputStream in : _seeds) + { + try + { + int num = in.available(); + if(seed == null) + { + seed = new byte[num]; + } + else + { + byte[] tmp = new byte[seed.length + num]; + System.arraycopy(seed, 0, tmp, 0, seed.length); + start = seed.length; + seed = tmp; + } + in.read(seed, start, num); + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException("IceSSL: error while reading random seed", ex); + } + finally + { + try + { + in.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + rand.setSeed(seed); + } + _seeds.clear(); + + // + // We call nextInt() in order to force the object to perform any time-consuming + // initialization tasks now. + // + rand.nextInt(); + + // + // The keystore holds private keys and associated certificates. + // + String keystorePath = properties.getProperty(prefix + "Keystore"); + + // + // The password for the keys. + // + String password = properties.getProperty(prefix + "Password"); + + // + // The password for the keystore. + // + String keystorePassword = properties.getProperty(prefix + "KeystorePassword"); + + // + // The default keystore type is usually "JKS", but the legal values are determined + // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". + // + final String defaultType = java.security.KeyStore.getDefaultType(); + final String keystoreType = properties.getPropertyWithDefault(prefix + "KeystoreType", defaultType); + + // + // The alias of the key to use in authentication. + // + final String alias = properties.getProperty(prefix + "Alias"); + + // + // The truststore holds the certificates of trusted CAs. + // + String truststorePath = properties.getProperty(prefix + "Truststore"); + + // + // The password for the truststore. + // + String truststorePassword = properties.getProperty(prefix + "TruststorePassword"); + + // + // The default truststore type is usually "JKS", but the legal values are determined + // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". + // + final String truststoreType = + properties.getPropertyWithDefault(prefix + "TruststoreType", + java.security.KeyStore.getDefaultType()); + + // + // Collect the key managers. + // + javax.net.ssl.KeyManager[] keyManagers = null; + java.security.KeyStore keys = null; + if(_keystoreStream != null || keystorePath.length() > 0) + { + java.io.InputStream keystoreStream = null; + try + { + if(_keystoreStream != null) + { + keystoreStream = _keystoreStream; + } + else + { + keystoreStream = openResource(keystorePath); + if(keystoreStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: keystore not found:\n" + keystorePath; + throw e; + } + } + + keys = java.security.KeyStore.getInstance(keystoreType); + char[] passwordChars = null; + if(keystorePassword.length() > 0) + { + passwordChars = keystorePassword.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getKeystorePassword(); + } + else if(keystoreType.equals("BKS")) + { + // Bouncy Castle does not permit null passwords. + passwordChars = new char[0]; + } + + keys.load(keystoreStream, passwordChars); + + if(passwordChars != null) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + keystorePassword = null; + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load keystore:\n" + keystorePath, ex); + } + finally + { + if(keystoreStream != null) + { + try + { + keystoreStream.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + + String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(); + javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm); + char[] passwordChars = new char[0]; // This password cannot be null. + if(password.length() > 0) + { + passwordChars = password.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getPassword(alias); + } + kmf.init(keys, passwordChars); + if(passwordChars.length > 0) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + password = null; + keyManagers = kmf.getKeyManagers(); + + // + // If the user selected a specific alias, we need to wrap the key managers + // in order to return the desired alias. + // + if(alias.length() > 0) + { + if(!keys.isKeyEntry(alias)) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'"; + throw e; + } + + for(int i = 0; i < keyManagers.length; ++i) + { + keyManagers[i] = new X509KeyManagerI((javax.net.ssl.X509KeyManager)keyManagers[i], alias); + } + } + } + + // + // Load the truststore. + // + java.security.KeyStore ts = null; + if(_truststoreStream != null || truststorePath.length() > 0) + { + // + // If the trust store and the key store are the same input + // stream or file, don't create another key store. + // + if((_truststoreStream != null && _truststoreStream == _keystoreStream) || + (truststorePath.length() > 0 && truststorePath.equals(keystorePath))) + { + assert keys != null; + ts = keys; + } + else + { + java.io.InputStream truststoreStream = null; + try + { + if(_truststoreStream != null) + { + truststoreStream = _truststoreStream; + } + else + { + truststoreStream = openResource(truststorePath); + if(truststoreStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: truststore not found:\n" + truststorePath; + throw e; + } + } + + ts = java.security.KeyStore.getInstance(truststoreType); + + char[] passwordChars = null; + if(truststorePassword.length() > 0) + { + passwordChars = truststorePassword.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getTruststorePassword(); + } + else if(truststoreType.equals("BKS")) + { + // Bouncy Castle does not permit null passwords. + passwordChars = new char[0]; + } + + ts.load(truststoreStream, passwordChars); + + if(passwordChars != null) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + truststorePassword = null; + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load truststore:\n" + truststorePath, ex); + } + finally + { + if(truststoreStream != null) + { + try + { + truststoreStream.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + } + } + else + { + ts = keys; + } + + // + // Collect the trust managers. + // + javax.net.ssl.TrustManager[] trustManagers = null; + { + String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm(); + javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm); + tmf.init(ts); + trustManagers = tmf.getTrustManagers(); + assert(trustManagers != null); + } + + // + // Wrap each trust manager. + // + for(int i = 0; i < trustManagers.length; ++i) + { + trustManagers[i] = new X509TrustManagerI(this, (javax.net.ssl.X509TrustManager)trustManagers[i]); + } + + // + // Initialize the SSL context. + // + _context = javax.net.ssl.SSLContext.getInstance("TLS"); + _context.init(keyManagers, trustManagers, rand); + } + catch(java.security.GeneralSecurityException ex) + { + throw new Ice.PluginInitializationException("IceSSL: unable to initialize context", ex); + } + } + + // + // Clear cached input streams. + // + _seeds.clear(); + _keystoreStream = null; + _truststoreStream = null; + + _initialized = true; + } + + void context(javax.net.ssl.SSLContext context) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plug-in is already initialized"; + throw ex; + } + + assert(_context == null); + _context = context; + } + + javax.net.ssl.SSLContext context() + { + return _context; + } + + void setCertificateVerifier(CertificateVerifier verifier) + { + _verifier = verifier; + } + + CertificateVerifier getCertificateVerifier() + { + return _verifier; + } + + void setPasswordCallback(PasswordCallback callback) + { + _passwordCallback = callback; + } + + PasswordCallback getPasswordCallback() + { + return _passwordCallback; + } + + void setKeystoreStream(java.io.InputStream stream) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is already initialized"; + throw ex; + } + + _keystoreStream = stream; + } + + void setTruststoreStream(java.io.InputStream stream) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is already initialized"; + throw ex; + } + + _truststoreStream = stream; + } + + void addSeedStream(java.io.InputStream stream) + { + _seeds.add(stream); + } + + int securityTraceLevel() + { + return _securityTraceLevel; + } + + String securityTraceCategory() + { + return _securityTraceCategory; + } + + boolean initialized() + { + return _initialized; + } + + javax.net.ssl.SSLEngine createSSLEngine(boolean incoming, java.net.InetSocketAddress peerAddr) + { + javax.net.ssl.SSLEngine engine; + if(peerAddr != null) + { + engine = _context.createSSLEngine(peerAddr.getAddress().getHostAddress(), peerAddr.getPort()); + } + else + { + engine = _context.createSSLEngine(); + } + engine.setUseClientMode(!incoming); + + String[] cipherSuites = filterCiphers(engine.getSupportedCipherSuites(), engine.getEnabledCipherSuites()); + try + { + engine.setEnabledCipherSuites(cipherSuites); + } + catch(IllegalArgumentException ex) + { + throw new Ice.SecurityException("IceSSL: invalid ciphersuite", ex); + } + + if(_securityTraceLevel >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("enabling SSL ciphersuites:"); + for(String suite : cipherSuites) + { + s.append("\n "); + s.append(suite); + } + _logger.trace(_securityTraceCategory, s.toString()); + } + + if(_protocols != null) + { + try + { + engine.setEnabledProtocols(_protocols); + } + catch(IllegalArgumentException ex) + { + throw new Ice.SecurityException("IceSSL: invalid protocol", ex); + } + } + + if(incoming) + { + if(_verifyPeer == 0) + { + engine.setWantClientAuth(false); + engine.setNeedClientAuth(false); + } + else if(_verifyPeer == 1) + { + engine.setWantClientAuth(true); + } + else + { + engine.setNeedClientAuth(true); + } + } + + try + { + engine.beginHandshake(); + } + catch(javax.net.ssl.SSLException ex) + { + throw new Ice.SecurityException("IceSSL: handshake error", ex); + } + + return engine; + } + + String[] filterCiphers(String[] supportedCiphers, String[] defaultCiphers) + { + java.util.LinkedList<String> result = new java.util.LinkedList<String>(); + if(_allCiphers) + { + for(String cipher : supportedCiphers) + { + result.add(cipher); + } + } + else if(!_noCiphers) + { + for(String cipher : defaultCiphers) + { + result.add(cipher); + } + } + + if(_ciphers != null) + { + for(CipherExpression ce : _ciphers) + { + if(ce.not) + { + java.util.Iterator<String> e = result.iterator(); + while(e.hasNext()) + { + String cipher = e.next(); + if(ce.cipher != null) + { + if(ce.cipher.equals(cipher)) + { + e.remove(); + } + } + else + { + assert(ce.re != null); + java.util.regex.Matcher m = ce.re.matcher(cipher); + if(m.find()) + { + e.remove(); + } + } + } + } + else + { + if(ce.cipher != null) + { + result.add(0, ce.cipher); + } + else + { + assert(ce.re != null); + for(String cipher : supportedCiphers) + { + java.util.regex.Matcher m = ce.re.matcher(cipher); + if(m.find()) + { + result.add(0, cipher); + } + } + } + } + } + } + + String[] arr = new String[result.size()]; + result.toArray(arr); + return arr; + } + + String[] protocols() + { + return _protocols; + } + + void traceConnection(java.nio.channels.SocketChannel fd, javax.net.ssl.SSLEngine engine, boolean incoming) + { + javax.net.ssl.SSLSession session = engine.getSession(); + String msg = "SSL summary for " + (incoming ? "incoming" : "outgoing") + " connection\n" + + "cipher = " + session.getCipherSuite() + "\n" + + "protocol = " + session.getProtocol() + "\n" + + IceInternal.Network.fdToString(fd); + _logger.trace(_securityTraceCategory, msg); + } + + Ice.Communicator communicator() + { + return _communicator; + } + + void verifyPeer(NativeConnectionInfo info, java.nio.channels.SelectableChannel fd, String address) + { + // + // For an outgoing connection, we compare the proxy address (if any) against + // fields in the server's certificate (if any). + // + if(info.nativeCerts != null && info.nativeCerts.length > 0 && address.length() > 0) + { + java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate)info.nativeCerts[0]; + + // + // Extract the IP addresses and the DNS names from the subject + // alternative names. + // + java.util.ArrayList<String> ipAddresses = new java.util.ArrayList<String>(); + java.util.ArrayList<String> dnsNames = new java.util.ArrayList<String>(); + try + { + java.util.Collection<java.util.List<?> > subjectAltNames = cert.getSubjectAlternativeNames(); + if(subjectAltNames != null) + { + for(java.util.List<?> l : subjectAltNames) + { + assert(!l.isEmpty()); + Integer n = (Integer)l.get(0); + if(n.intValue() == 7) + { + ipAddresses.add((String)l.get(1)); + } + else if(n.intValue() == 2) + { + dnsNames.add(((String)l.get(1)).toLowerCase()); + } + } + } + } + catch(java.security.cert.CertificateParsingException ex) + { + assert(false); + } + + // + // Compare the peer's address against the common name as well as + // the dnsName and ipAddress values in the subject alternative name. + // + boolean certNameOK = false; + String dn = ""; + String addrLower = address.toLowerCase(); + { + javax.security.auth.x500.X500Principal principal = cert.getSubjectX500Principal(); + dn = principal.getName(javax.security.auth.x500.X500Principal.CANONICAL); + // + // Canonical format is already in lower case. + // + String cn = "cn=" + addrLower; + int pos = dn.indexOf(cn); + if(pos >= 0) + { + // + // Ensure we match the entire common name. + // + certNameOK = (pos + cn.length() == dn.length()) || (dn.charAt(pos + cn.length()) == ','); + } + } + + // + // Compare the peer's address against the dnsName and ipAddress + // values in the subject alternative name. + // + if(!certNameOK) + { + certNameOK = ipAddresses.contains(addrLower); + } + if(!certNameOK) + { + certNameOK = dnsNames.contains(addrLower); + } + + // + // Log a message if the name comparison fails. If CheckCertName is defined, + // we also raise an exception to abort the connection. Don't log a message if + // CheckCertName is not defined and a verifier is present. + // + if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && _verifier == null))) + { + StringBuilder sb = new StringBuilder(128); + sb.append("IceSSL: "); + if(!_checkCertName) + { + sb.append("ignoring "); + } + sb.append("certificate validation failure:\npeer certificate does not have `"); + sb.append(address); + sb.append("' as its commonName or in its subjectAltName extension"); + if(dn.length() > 0) + { + sb.append("\nSubject DN: "); + sb.append(dn); + } + if(!dnsNames.isEmpty()) + { + sb.append("\nDNS names found in certificate: "); + for(int j = 0; j < dnsNames.size(); ++j) + { + if(j > 0) + { + sb.append(", "); + } + sb.append(dnsNames.get(j)); + } + } + if(!ipAddresses.isEmpty()) + { + sb.append("\nIP addresses found in certificate: "); + for(int j = 0; j < ipAddresses.size(); ++j) + { + if(j > 0) + { + sb.append(", "); + } + sb.append(ipAddresses.get(j)); + } + } + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, sb.toString()); + } + if(_checkCertName) + { + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = sb.toString(); + throw ex; + } + } + } + + if(_verifyDepthMax > 0 && info.nativeCerts != null && info.nativeCerts.length > _verifyDepthMax) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected:\n" + + "length of peer's certificate chain (" + info.nativeCerts.length + ") exceeds maximum of " + + _verifyDepthMax + "\n" + + IceInternal.Network.fdToString(fd); + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + + if(!_trustManager.verify(info)) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by trust manager\n" + + IceInternal.Network.fdToString(fd); + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + + if(_verifier != null && !_verifier.verify(info)) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier\n" + + IceInternal.Network.fdToString(fd); + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + } + + void trustManagerFailure(boolean incoming, java.security.cert.CertificateException ex) + throws java.security.cert.CertificateException + { + if(_verifyPeer == 0) + { + if(_securityTraceLevel >= 1) + { + String msg = "ignoring peer verification failure"; + if(_securityTraceLevel > 1) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + msg += ":\n" + sw.toString(); + } + _logger.trace(_securityTraceCategory, msg); + } + } + else + { + throw ex; + } + } + + private void parseCiphers(String ciphers) + { + java.util.ArrayList<CipherExpression> cipherList = new java.util.ArrayList<CipherExpression>(); + String[] expr = ciphers.split("[ \t]+"); + for(int i = 0; i < expr.length; ++i) + { + if(expr[i].equals("ALL")) + { + if(i != 0) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: `ALL' must be first in cipher list `" + ciphers + "'"; + throw ex; + } + _allCiphers = true; + } + else if(expr[i].equals("NONE")) + { + if(i != 0) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: `NONE' must be first in cipher list `" + ciphers + "'"; + throw ex; + } + _noCiphers = true; + } + else + { + CipherExpression ce = new CipherExpression(); + String exp = expr[i]; + if(exp.charAt(0) == '!') + { + ce.not = true; + if(exp.length() > 1) + { + exp = exp.substring(1); + } + else + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; + throw ex; + } + } + + if(exp.charAt(0) == '(') + { + if(!exp.endsWith(")")) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; + throw ex; + } + + try + { + ce.re = java.util.regex.Pattern.compile(exp.substring(1, exp.length() - 2)); + } + catch(java.util.regex.PatternSyntaxException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: invalid cipher expression `" + exp + "'", ex); + } + } + else + { + ce.cipher = exp; + } + + cipherList.add(ce); + } + } + _ciphers = new CipherExpression[cipherList.size()]; + cipherList.toArray(_ciphers); + } + + private java.io.InputStream openResource(String path) + throws java.io.IOException + { + // + // This method wraps a call to IceInternal.Util.openResource. If the first call fails and + // IceSSL.DefaultDir is defined, prepend the default directory and try again. + // + java.io.InputStream stream = IceInternal.Util.openResource(getClass().getClassLoader(), path); + if(stream == null && _defaultDir.length() > 0) + { + stream = IceInternal.Util.openResource(getClass().getClassLoader(), + _defaultDir + java.io.File.separator + path); + } + + if(stream != null) + { + stream = new java.io.BufferedInputStream(stream); + } + + return stream; + } + + private static class CipherExpression + { + boolean not; + String cipher; + java.util.regex.Pattern re; + } + + private Ice.Communicator _communicator; + private Ice.Logger _logger; + private IceInternal.ProtocolPluginFacade _facade; + private int _securityTraceLevel; + private String _securityTraceCategory; + private boolean _initialized; + private javax.net.ssl.SSLContext _context; + private String _defaultDir; + private CipherExpression[] _ciphers; + private boolean _allCiphers; + private boolean _noCiphers; + private String[] _protocols; + private boolean _checkCertName; + private int _verifyDepthMax; + private int _verifyPeer; + private CertificateVerifier _verifier; + private PasswordCallback _passwordCallback; + private TrustManager _trustManager; + + private InputStream _keystoreStream; + private InputStream _truststoreStream; + private List<InputStream> _seeds = new ArrayList<InputStream>(); +} diff --git a/java/src/IceSSL/TransceiverI.java b/java/src/IceSSL/TransceiverI.java index 560b278dfdf..51c30138872 100644 --- a/java/src/IceSSL/TransceiverI.java +++ b/java/src/IceSSL/TransceiverI.java @@ -15,15 +15,13 @@ import javax.net.ssl.SSLEngineResult.*; final class TransceiverI implements IceInternal.Transceiver { - public java.nio.channels.SelectableChannel - fd() + public java.nio.channels.SelectableChannel fd() { assert(_fd != null); return _fd; } - public int - initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer) + public int initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer, Ice.BooleanHolder moreData) { try { @@ -32,7 +30,7 @@ final class TransceiverI implements IceInternal.Transceiver _state = StateConnectPending; return IceInternal.SocketOperation.Connect; } - else if(_state == StateConnectPending) + else if(_state <= StateConnectPending) { IceInternal.Network.doFinishConnect(_fd); _desc = IceInternal.Network.fdToString(_fd, _proxy, _addr); @@ -104,33 +102,36 @@ final class TransceiverI implements IceInternal.Transceiver _state = StateConnected; } - if(_state == StateConnected) - { - return handshakeNonBlocking(); - } + assert(_state == StateConnected); + + return handshakeNonBlocking(); } catch(Ice.LocalException ex) { - if(_instance.networkTraceLevel() >= 2) + if(_instance.traceLevel() >= 2) { StringBuilder s = new StringBuilder(128); - s.append("failed to establish ssl connection\n"); + s.append("failed to establish " + protocol() + " connection\n"); s.append(IceInternal.Network.fdToString(_fd, _proxy, _addr)); - _logger.trace(_instance.networkTraceCategory(), s.toString()); + _instance.logger().trace(_instance.traceCategory(), s.toString()); } throw ex; } + } - return IceInternal.SocketOperation.None; + public int closing(boolean initiator, Ice.LocalException ex) + { + // If we are initiating the connection closure, wait for the peer + // to close the TCP/IP connection. Otherwise, close immediately. + return initiator ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None; } - public void - close() + public void close() { - if(_state == StateHandshakeComplete && _instance.networkTraceLevel() >= 1) + if(_state == StateHandshakeComplete && _instance.traceLevel() >= 1) { - String s = "closing ssl connection\n" + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "closing " + protocol() + " connection\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } assert(_fd != null); @@ -151,7 +152,7 @@ final class TransceiverI implements IceInternal.Transceiver { // // Note: we can't block to send the close_notify message. In some cases, the - // close_notify message might therefore not be receieved by the peer. This is + // close_notify message might therefore not be received by the peer. This is // not a big issue since the Ice protocol isn't subject to truncation attacks. // flushNonBlocking(); @@ -186,7 +187,7 @@ final class TransceiverI implements IceInternal.Transceiver // We would probably need to wait for a response in shutdown() to avoid this. // For now, we'll ignore this exception. // - //_logger.error("IceSSL: error during close\n" + ex.getMessage()); + //_instance.logger().error("IceSSL: error during close\n" + ex.getMessage()); } } @@ -200,47 +201,33 @@ final class TransceiverI implements IceInternal.Transceiver } } - public boolean - write(IceInternal.Buffer buf) + public int write(IceInternal.Buffer buf) { if(_state == StateProxyConnectRequest) { // // We need to write the proxy message, but we have to use TCP and not SSL. // - return writeRaw(buf); - } - - // - // If the handshake isn't completed yet, we shouldn't be writing. - // - if(_state < StateHandshakeComplete) - { - throw new Ice.ConnectionLostException(); + return writeRaw(buf) ? IceInternal.SocketOperation.None : IceInternal.SocketOperation.Write; } // - // We don't want write to be called on android main thread as this will cause - // NetworkOnMainThreadException to be thrown. If that is the android main thread - // we return false and this method will be later called from the thread pool. + // We don't want write to be called on Android's main thread as this will cause + // NetworkOnMainThreadException to be thrown. If this is the Android main thread + // we return false and this method will be called later from the thread pool. // if(IceInternal.Util.isAndroidMainThread(Thread.currentThread())) { - return false; + return IceInternal.SocketOperation.Write; } int status = writeNonBlocking(buf.b); - if(status != IceInternal.SocketOperation.None) - { - assert(status == IceInternal.SocketOperation.Write); - return false; - } - return true; + assert(status == IceInternal.SocketOperation.None || status == IceInternal.SocketOperation.Write); + return status; } @SuppressWarnings("deprecation") - public boolean - read(IceInternal.Buffer buf, Ice.BooleanHolder moreData) + public int read(IceInternal.Buffer buf, Ice.BooleanHolder moreData) { moreData.value = false; @@ -249,21 +236,11 @@ final class TransceiverI implements IceInternal.Transceiver // // We need to read the proxy reply, but we have to use TCP and not SSL. // - return readRaw(buf); - } - - // - // If the handshake isn't completed yet, we shouldn't be reading (read can be - // called by the thread pool when the connection is registered/unregistered - // with the pool to be closed). - // - if(_state < StateHandshakeComplete) - { - throw new Ice.ConnectionLostException(); + return readRaw(buf) ? IceInternal.SocketOperation.None : IceInternal.SocketOperation.Read; } int rem = 0; - if(_instance.networkTraceLevel() >= 3) + if(_instance.traceLevel() >= 3) { rem = buf.b.remaining(); } @@ -274,10 +251,11 @@ final class TransceiverI implements IceInternal.Transceiver int pos = buf.b.position(); fill(buf.b); - if(_instance.networkTraceLevel() >= 3 && buf.b.position() > pos) + if(_instance.traceLevel() >= 3 && buf.b.position() > pos) { - String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via ssl\n" + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via " + protocol() + + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } // @@ -305,7 +283,7 @@ final class TransceiverI implements IceInternal.Transceiver if(status != IceInternal.SocketOperation.None) { assert(status == IceInternal.SocketOperation.Read); - return false; + return status; } continue; } @@ -322,10 +300,11 @@ final class TransceiverI implements IceInternal.Transceiver pos = buf.b.position(); fill(buf.b); - if(_instance.networkTraceLevel() >= 3 && buf.b.position() > pos) + if(_instance.traceLevel() >= 3 && buf.b.position() > pos) { - String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via ssl\n" + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via " + protocol() + + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } } @@ -338,29 +317,25 @@ final class TransceiverI implements IceInternal.Transceiver // Return a boolean to indicate whether more data is available. // moreData.value = _netInput.position() > 0; - return true; + return IceInternal.SocketOperation.None; } - public String - type() + public String protocol() { - return "ssl"; + return _instance.protocol(); } - public String - toString() + public String toString() { return _desc; } - public Ice.ConnectionInfo - getInfo() + public Ice.ConnectionInfo getInfo() { return getNativeConnectionInfo(); } - public void - checkSendSize(IceInternal.Buffer buf, int messageSizeMax) + public void checkSendSize(IceInternal.Buffer buf, int messageSizeMax) { if(buf.size() > messageSizeMax) { @@ -397,7 +372,6 @@ final class TransceiverI implements IceInternal.Transceiver _instance = instance; _engine = engine; _fd = fd; - _logger = instance.communicator().getLogger(); _maxPacketSize = 0; if(System.getProperty("os.name").startsWith("Windows")) { @@ -418,8 +392,7 @@ final class TransceiverI implements IceInternal.Transceiver _netOutput = ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize() * 2); } - protected void - finalize() + protected void finalize() throws Throwable { try @@ -435,8 +408,7 @@ final class TransceiverI implements IceInternal.Transceiver } } - private NativeConnectionInfo - getNativeConnectionInfo() + private NativeConnectionInfo getNativeConnectionInfo() { // // This can only be called on an open transceiver. @@ -454,7 +426,7 @@ final class TransceiverI implements IceInternal.Transceiver info.localAddress = socket.getLocalAddress().getHostAddress(); info.localPort = socket.getLocalPort(); } - + if(socket.getInetAddress() != null) { info.remoteAddress = socket.getInetAddress().getHostAddress(); @@ -489,8 +461,7 @@ final class TransceiverI implements IceInternal.Transceiver return info; } - private int - handshakeNonBlocking() + private int handshakeNonBlocking() { try { @@ -599,8 +570,7 @@ final class TransceiverI implements IceInternal.Transceiver return IceInternal.SocketOperation.None; } - private void - handshakeCompleted() + private void handshakeCompleted() { _state = StateHandshakeComplete; @@ -610,8 +580,7 @@ final class TransceiverI implements IceInternal.Transceiver // if(!_incoming) { - int verifyPeer = - _instance.communicator().getProperties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2); + int verifyPeer = _instance.properties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2); if(verifyPeer > 0) { try @@ -630,18 +599,18 @@ final class TransceiverI implements IceInternal.Transceiver // _instance.verifyPeer(getNativeConnectionInfo(), _fd, _host); - if(_instance.networkTraceLevel() >= 1) + if(_instance.traceLevel() >= 1) { String s; if(_incoming) { - s = "accepted ssl connection\n" + _desc; + s = "accepted " + protocol() + " connection\n" + _desc; } else { - s = "ssl connection established\n" + _desc; + s = protocol() + " connection established\n" + _desc; } - _logger.trace(_instance.networkTraceCategory(), s); + _instance.logger().trace(_instance.traceCategory(), s); } if(_instance.securityTraceLevel() >= 1) @@ -651,8 +620,7 @@ final class TransceiverI implements IceInternal.Transceiver } @SuppressWarnings("deprecation") - private int - writeNonBlocking(ByteBuffer buf) + private int writeNonBlocking(ByteBuffer buf) { // // This method has two purposes: encrypt the application's message buffer into our @@ -693,11 +661,11 @@ final class TransceiverI implements IceInternal.Transceiver // if(result.bytesConsumed() > 0) { - if(_instance.networkTraceLevel() >= 3) + if(_instance.traceLevel() >= 3) { - String s = "sent " + result.bytesConsumed() + " of " + rem + " bytes via ssl\n" + - toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "sent " + result.bytesConsumed() + " of " + rem + " bytes via " + + protocol() + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } } @@ -705,7 +673,7 @@ final class TransceiverI implements IceInternal.Transceiver // // Write the encrypted data to the socket. We continue writing until we've written // all of _netOutput, or until flushNonBlocking indicates that it cannot write - // (i.e., by returning NeedWrite). + // (i.e., by returning SocketOperation.Write). // if(_netOutput.position() > 0) { @@ -727,8 +695,7 @@ final class TransceiverI implements IceInternal.Transceiver return IceInternal.SocketOperation.None; } - private int - flushNonBlocking() + private int flushNonBlocking() { _netOutput.flip(); @@ -792,8 +759,7 @@ final class TransceiverI implements IceInternal.Transceiver return status; } - private int - readNonBlocking() + private int readNonBlocking() { while(true) { @@ -826,8 +792,7 @@ final class TransceiverI implements IceInternal.Transceiver return IceInternal.SocketOperation.None; } - private void - fill(ByteBuffer buf) + private void fill(ByteBuffer buf) { _appInput.flip(); if(_appInput.hasRemaining()) @@ -872,8 +837,7 @@ final class TransceiverI implements IceInternal.Transceiver } @SuppressWarnings("deprecation") - private boolean - writeRaw(IceInternal.Buffer buf) + private boolean writeRaw(IceInternal.Buffer buf) { // // We don't want write to be called on android main thread as this will cause @@ -904,10 +868,10 @@ final class TransceiverI implements IceInternal.Transceiver return false; } - if(_instance.networkTraceLevel() >= 3) + if(_instance.traceLevel() >= 3) { - String s = "sent " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "sent " + ret + " of " + packetSize + " bytes via " + protocol() + "\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } catch(java.io.InterruptedIOException ex) @@ -923,8 +887,7 @@ final class TransceiverI implements IceInternal.Transceiver } @SuppressWarnings("deprecation") - private boolean - readRaw(IceInternal.Buffer buf) + private boolean readRaw(IceInternal.Buffer buf) { int packetSize = buf.b.remaining(); @@ -947,10 +910,11 @@ final class TransceiverI implements IceInternal.Transceiver if(ret > 0) { - if(_instance.networkTraceLevel() >= 3) + if(_instance.traceLevel() >= 3) { - String s = "received " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); - _logger.trace(_instance.networkTraceCategory(), s); + String s = "received " + ret + " of " + packetSize + " bytes via " + protocol() + "\n" + + toString(); + _instance.logger().trace(_instance.traceCategory(), s); } } @@ -978,7 +942,6 @@ final class TransceiverI implements IceInternal.Transceiver private String _adapterName; private java.net.InetSocketAddress _addr; private int _state; - private Ice.Logger _logger; private String _desc; private int _maxPacketSize; diff --git a/java/src/IceSSL/X509TrustManagerI.java b/java/src/IceSSL/X509TrustManagerI.java index 39e5b7cd24f..9a1f22cb470 100644 --- a/java/src/IceSSL/X509TrustManagerI.java +++ b/java/src/IceSSL/X509TrustManagerI.java @@ -11,7 +11,7 @@ package IceSSL; final class X509TrustManagerI implements javax.net.ssl.X509TrustManager { - X509TrustManagerI(Instance instance, javax.net.ssl.X509TrustManager delegate) + X509TrustManagerI(SharedInstance instance, javax.net.ssl.X509TrustManager delegate) { _instance = instance; _delegate = delegate; @@ -67,6 +67,6 @@ final class X509TrustManagerI implements javax.net.ssl.X509TrustManager return _delegate.getAcceptedIssuers(); } - private Instance _instance; + private SharedInstance _instance; private javax.net.ssl.X509TrustManager _delegate; } |