blob: ce62aa41d02bbdbb08ca490f39e152b81628841b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately
* from Eclipse
* Google Inc - add support for accepting multiple connections
*******************************************************************************/
package org.eclipse.jdi.internal.connect;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdi.internal.VirtualMachineManagerImpl;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.ListeningConnector;
public class SocketListeningConnectorImpl extends ConnectorImpl implements ListeningConnector {
/** Port to which is attached. */
private int fPort;
/** Timeout before accept returns. */
private int fTimeout;
/**
* Creates new SocketAttachingConnectorImpl.
*/
public SocketListeningConnectorImpl(
VirtualMachineManagerImpl virtualMachineManager) {
super(virtualMachineManager);
// Create communication protocol specific transport.
SocketTransportImpl transport = new SocketTransportImpl();
setTransport(transport);
}
/**
* @return Returns the default arguments.
*/
@Override
public Map<String, Connector.Argument> defaultArguments() {
HashMap<String, Connector.Argument> arguments = new HashMap<String, Connector.Argument>(1);
// Port
IntegerArgumentImpl intArg = new IntegerArgumentImpl(
"port", ConnectMessages.SocketListeningConnectorImpl_Port_number_at_which_to_listen_for_VM_connections_1, ConnectMessages.SocketListeningConnectorImpl_Port_2, true, SocketTransportImpl.MIN_PORTNR, SocketTransportImpl.MAX_PORTNR); //$NON-NLS-1$
arguments.put(intArg.name(), intArg);
// Timeout
intArg = new IntegerArgumentImpl(
"timeout", ConnectMessages.SocketListeningConnectorImpl_Timeout_before_accept_returns_3, ConnectMessages.SocketListeningConnectorImpl_Timeout_4, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$
arguments.put(intArg.name(), intArg);
// FIXME: connectionLimit is not actually used in this class, but in the higher-level controller, SocketListenConnector.
// But IntegerArgumentImpl is package restricted so we must put it here.
intArg = new IntegerArgumentImpl("connectionLimit", ConnectMessages.SocketListeningConnectorImpl_Limit_incoming_connections, ConnectMessages.SocketListeningConnectorImpl_Limit, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$
intArg.setValue(1); // mimics previous behaviour, allowing a single connection
arguments.put(intArg.name(), intArg);
return arguments;
}
/**
* @return Returns a short identifier for the connector.
*/
@Override
public String name() {
return "com.sun.jdi.SocketListen"; //$NON-NLS-1$
}
/**
* @return Returns a human-readable description of this connector and its
* purpose.
*/
@Override
public String description() {
return ConnectMessages.SocketListeningConnectorImpl_Accepts_socket_connections_initiated_by_other_VMs_5;
}
/**
* Retrieves connection arguments.
*/
private void getConnectionArguments(Map<String, ? extends Connector.Argument> connectionArgs) throws IllegalConnectorArgumentsException {
String attribute = "port"; //$NON-NLS-1$
try {
// If listening port is not specified, use port 0
IntegerArgument argument = (IntegerArgument) connectionArgs
.get(attribute);
if (argument != null && argument.value() != null) {
fPort = argument.intValue();
} else {
fPort = 0;
}
// Note that timeout is not used in SUN's ListeningConnector, but is
// used by our
// LaunchingConnector.
attribute = "timeout"; //$NON-NLS-1$
argument = (IntegerArgument) connectionArgs.get(attribute);
if (argument != null && argument.value() != null) {
fTimeout = argument.intValue();
} else {
fTimeout = 0;
}
} catch (ClassCastException e) {
throw new IllegalConnectorArgumentsException(
ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6,
attribute);
} catch (NullPointerException e) {
throw new IllegalConnectorArgumentsException(
ConnectMessages.SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7,
attribute);
} catch (NumberFormatException e) {
throw new IllegalConnectorArgumentsException(
ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8,
attribute);
}
}
/**
* Listens for one or more connections initiated by target VMs.
*
* @return Returns the address at which the connector is listening for a
* connection.
*/
@Override
public String startListening(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException, IllegalConnectorArgumentsException {
getConnectionArguments(connectionArgs);
String result = null;
try {
result = ((SocketTransportImpl) fTransport).startListening(fPort);
} catch (IllegalArgumentException e) {
throw new IllegalConnectorArgumentsException(
ConnectMessages.SocketListeningConnectorImpl_ListeningConnector_Socket_Port,
"port"); //$NON-NLS-1$
}
return result;
}
/* (non-Javadoc)
* @see com.sun.jdi.connect.ListeningConnector#stopListening(java.util.Map)
*/
@Override
public void stopListening(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException {
((SocketTransportImpl) fTransport).stopListening();
}
/**
* Waits for a target VM to attach to this connector.
*
* @return Returns a connected Virtual Machine.
*/
@Override
public VirtualMachine accept(Map<String, ? extends Connector.Argument> connectionArgs) throws IOException, IllegalConnectorArgumentsException {
getConnectionArguments(connectionArgs);
SocketConnection connection = (SocketConnection) ((SocketTransportImpl) fTransport)
.accept(fTimeout, 0);
return establishedConnection(connection);
}
/**
* @return Returns whether this listening connector supports multiple
* connections for a single argument map.
*/
@Override
public boolean supportsMultipleConnections() {
return true;
}
/**
* @return Returns port number that is listened to.
*/
public int listeningPort() {
return fPort;
}
}