ARTEMIS-1727 - Make sure transport is stopped on failed OpenWire

connection

To prevent a socket from hanging open by a bad client the broker should
make sure to stop the transport if a connection attempt fails by an
OpenWire client
This commit is contained in:
Christopher L. Shannon (cshannon) 2018-03-02 11:38:07 -05:00
parent 95b7438e7a
commit 29250466ae
2 changed files with 89 additions and 2 deletions

View File

@ -40,6 +40,7 @@ import org.apache.activemq.advisory.AdvisorySupport;
import org.apache.activemq.artemis.api.core.ActiveMQAddressExistsException; import org.apache.activemq.artemis.api.core.ActiveMQAddressExistsException;
import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException; import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException;
import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException; import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException;
import org.apache.activemq.artemis.api.core.ActiveMQRemoteDisconnectException; import org.apache.activemq.artemis.api.core.ActiveMQRemoteDisconnectException;
@ -299,11 +300,16 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se
} }
if (response instanceof ExceptionResponse) { if (response instanceof ExceptionResponse) {
Throwable cause = ((ExceptionResponse)response).getException();
if (!responseRequired) { if (!responseRequired) {
Throwable cause = ((ExceptionResponse) response).getException();
serviceException(cause); serviceException(cause);
response = null; response = null;
} }
// If there was an exception when processing ConnectionInfo we should
// stop the connection to prevent dangling sockets
if (command instanceof ConnectionInfo) {
delayedStop(2000, cause.getMessage(), cause);
}
} }
if (responseRequired) { if (responseRequired) {
@ -640,13 +646,29 @@ public class OpenWireConnection extends AbstractRemotingConnection implements Se
} }
} }
try { try {
protocolManager.removeConnection(this.getConnectionInfo(), me); if (this.getConnectionInfo() != null) {
protocolManager.removeConnection(this.getConnectionInfo(), me);
}
} catch (InvalidClientIDException e) { } catch (InvalidClientIDException e) {
ActiveMQServerLogger.LOGGER.warn("Couldn't close connection because invalid clientID", e); ActiveMQServerLogger.LOGGER.warn("Couldn't close connection because invalid clientID", e);
} }
shutdown(true); shutdown(true);
} }
private void delayedStop(final int waitTimeMillis, final String reason, Throwable cause) {
if (waitTimeMillis > 0) {
try {
protocolManager.getScheduledPool().schedule(() -> {
fail(new ActiveMQException(reason, cause, ActiveMQExceptionType.GENERIC_EXCEPTION), reason);
ActiveMQServerLogger.LOGGER.warn("Stopping " + transportConnection.getRemoteAddress() + "because " +
reason);
}, waitTimeMillis, TimeUnit.MILLISECONDS);
} catch (Throwable t) {
ActiveMQServerLogger.LOGGER.warn("Cannot stop connection. This exception will be ignored.", t);
}
}
}
public void setAdvisorySession(AMQSession amqSession) { public void setAdvisorySession(AMQSession amqSession) {
this.advisorySession = amqSession; this.advisorySession = amqSession;
} }

View File

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.tests.integration.openwire.amq;
import javax.jms.Connection;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.tests.integration.openwire.BasicOpenWireTest;
import org.apache.activemq.artemis.tests.util.Wait;
import org.junit.Test;
public class ConnectionErrorSocketCloseTest extends BasicOpenWireTest {
@Override
protected void createFactories() {
super.createFactories();
factory.setClientID("id");
}
//We want to make sure that the socket will be closed if there as an error on broker.addConnection
//even if the client doesn't close the connection to prevent dangling open sockets
@Test(timeout = 60000)
public void testDuplicateClientIdCloseConnection() throws Exception {
connection.start();
Wait.waitFor(() -> getActiveMQServer().getRemotingService().getConnections().size() == 1, 10000, 500);
try (Connection con = factory.createConnection()) {
// Try and create second connection the second should fail because of a
// duplicate clientId
try {
// Should fail because of previously started connection with same
// client Id
con.start();
fail("Should have exception");
} catch (Exception e) {
e.printStackTrace();
}
// after 2 seconds the second connection should be terminated by the
// broker because of the exception
assertTrue(Wait.waitFor(() -> getActiveMQServer().getRemotingService().getConnections().size() == 1, 10000, 500));
}
}
@SuppressWarnings("deprecation")
private ActiveMQServer getActiveMQServer() {
return jmsServer.getActiveMQServer();
}
}