package ibis.ipl.impl.smartsockets; import ibis.ipl.ConnectionFailedException; import ibis.ipl.ConnectionsFailedException; import ibis.ipl.IbisIdentifier; import ibis.ipl.NoSuchPropertyException; import ibis.ipl.PortType; import ibis.ipl.ReceivePortIdentifier; import ibis.ipl.SendPort; import ibis.ipl.SendPortIdentifier; import ibis.ipl.WriteMessage; import ibis.smartsockets.hub.servicelink.ServiceLink; import ibis.smartsockets.util.MalformedAddressException; import ibis.smartsockets.virtual.VirtualSocketAddress; import java.io.IOException; import java.io.PrintStream; import java.net.UnknownHostException; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Map.Entry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SmartSocketsUltraLightSendPort implements SendPort { // FIXME: This value is arbitrarily chosen... private static final int DEFAULT_BUFFER_SIZE = 64*1024; protected static final Logger logger = LoggerFactory.getLogger("ibis.ipl.impl.smartsockets.SendPort"); private final PortType type; private final String name; // private final Properties properties; private final SmartSocketsIbis ibis; private final SendPortIdentifier sid; private boolean closed = false; private final SmartSocketsUltraLightWriteMessage message; private final byte [] buffer; private boolean messageInUse = false; private final Set<ReceivePortIdentifier> connections = new HashSet<ReceivePortIdentifier>(); private final byte [][] messageToHub; SmartSocketsUltraLightSendPort(SmartSocketsIbis ibis, PortType type, String name, Properties props) throws IOException { this.ibis = ibis; this.type = type; this.name = name; // this.properties = props; sid = new ibis.ipl.impl.SendPortIdentifier(name, ibis.ident); buffer = new byte[DEFAULT_BUFFER_SIZE]; message = new SmartSocketsUltraLightWriteMessage(this, buffer); messageToHub = new byte[2][]; messageToHub[0] = ibis.ident.toBytes(); } public synchronized void close() throws IOException { closed = true; notifyAll(); } public synchronized void connect(ReceivePortIdentifier receiver) throws ConnectionFailedException { connections.add(receiver); } public void connect(ReceivePortIdentifier receiver, long timeoutMillis, boolean fillTimeout) throws ConnectionFailedException { connect(receiver); } public ReceivePortIdentifier connect(IbisIdentifier ibisIdentifier, String receivePortName) throws ConnectionFailedException { ReceivePortIdentifier id = new ibis.ipl.impl.ReceivePortIdentifier(receivePortName, (ibis.ipl.impl.IbisIdentifier) ibisIdentifier); connect(id); return id; } public ReceivePortIdentifier connect(IbisIdentifier ibisIdentifier, String receivePortName, long timeoutMillis, boolean fillTimeout) throws ConnectionFailedException { return connect(ibisIdentifier, receivePortName); } public void connect(ReceivePortIdentifier[] receivePortIdentifiers) throws ConnectionsFailedException { LinkedList<ConnectionFailedException> tmp = null; LinkedList<ReceivePortIdentifier> success = new LinkedList<ReceivePortIdentifier>(); for (ReceivePortIdentifier id : receivePortIdentifiers) { try { connect(id); success.add(id); } catch (ConnectionFailedException e) { if (tmp == null) { tmp = new LinkedList<ConnectionFailedException>(); } tmp.add(e); } } if (tmp != null && tmp.size() > 0) { ConnectionsFailedException c = new ConnectionsFailedException("Failed to connect"); for (ConnectionFailedException ex : tmp) { c.add(ex); } c.setObtainedConnections(success.toArray(new ReceivePortIdentifier[success.size()])); throw c; } } public void connect(ReceivePortIdentifier[] receivePortIdentifiers, long timeoutMillis, boolean fillTimeout) throws ConnectionsFailedException { connect(receivePortIdentifiers); } public ReceivePortIdentifier[] connect(Map<IbisIdentifier, String> ports) throws ConnectionsFailedException { ReceivePortIdentifier [] tmp = new ReceivePortIdentifier[ports.size()]; int index = 0; for (Entry<IbisIdentifier, String> e : ports.entrySet()) { tmp[index++] = new ibis.ipl.impl.ReceivePortIdentifier(e.getValue(), (ibis.ipl.impl.IbisIdentifier) e.getKey()); } connect(tmp); return tmp; } public ReceivePortIdentifier[] connect(Map<IbisIdentifier, String> ports, long timeoutMillis, boolean fillTimeout) throws ConnectionsFailedException { return connect(ports); } public ReceivePortIdentifier[] connectedTo() { return connections.toArray(new ReceivePortIdentifier[0]); } public synchronized void disconnect(ReceivePortIdentifier receiver) throws IOException { if (!connections.remove(receiver)) { throw new IOException("Not connected to " + receiver); } } public void disconnect(IbisIdentifier ibisIdentifier, String receivePortName) throws IOException { disconnect(new ibis.ipl.impl.ReceivePortIdentifier(receivePortName, (ibis.ipl.impl.IbisIdentifier) ibisIdentifier)); } public PortType getPortType() { return type; } public SendPortIdentifier identifier() { return sid; } public ReceivePortIdentifier[] lostConnections() { return new ReceivePortIdentifier[0]; } public String name() { return name; } public synchronized WriteMessage newMessage() throws IOException { while (!closed && messageInUse) { try { wait(); } catch (InterruptedException e) { // ignore } } if (closed) { throw new IOException("Sendport is closed"); } messageInUse = false; return message; } public String getManagementProperty(String key) throws NoSuchPropertyException { // TODO Auto-generated method stub return null; } public Map<String, String> managementProperties() { // TODO Auto-generated method stub return null; } public void printManagementProperties(PrintStream stream) { // TODO Auto-generated method stub } public void setManagementProperties(Map<String, String> properties) throws NoSuchPropertyException { // TODO Auto-generated method stub } public void setManagementProperty(String key, String value) throws NoSuchPropertyException { // TODO Auto-generated method stub } private void send(byte [] data, int len) throws UnknownHostException, MalformedAddressException { ServiceLink link = ibis.getServiceLink(); if (link == null) { if (logger.isDebugEnabled()) { logger.debug("No servicelink available"); } return; } // messageToHub[1] = Arrays.copyOfRange(buffer, 0, len); // This is Java 6 speak. Modified to equivalent code that // is acceptable to Java 1.5. --Ceriel messageToHub[1] = new byte[len]; System.arraycopy(buffer, 0, messageToHub[1], 0, Math.min(len, buffer.length)); for (ReceivePortIdentifier id : connections) { ibis.ipl.impl.IbisIdentifier dst = (ibis.ipl.impl.IbisIdentifier) id.ibisIdentifier(); VirtualSocketAddress a = VirtualSocketAddress.fromBytes(dst.getImplementationData(), 0); if (logger.isDebugEnabled()) { logger.debug("Sending message to " + a); } link.send(a.machine(), a.hub(), id.name(), 0xDEADBEEF, messageToHub); } } public synchronized void finishedMessage() throws IOException { int len = (int) message.bytesWritten(); byte [] m = buffer; try { send(m, len); } catch (Exception e) { logger.debug("Failed to send message to " + connections, e); } message.reset(); messageInUse = false; notifyAll(); } /* private void send(ReceivePortIdentifier id, byte [] data) throws UnknownHostException, MalformedAddressException { ServiceLink link = ibis.getServiceLink(); if (link != null) { ibis.ipl.impl.IbisIdentifier dst = (ibis.ipl.impl.IbisIdentifier) id.ibisIdentifier(); VirtualSocketAddress a = VirtualSocketAddress.fromBytes(dst.getImplementationData(), 0); byte [][] message = new byte[2][]; message[0] = ibis.ident.toBytes(); message[1] = data; if (logger.isDebugEnabled()) { logger.debug("Sending message to " + a); } link.send(a.machine(), a.hub(), id.name(), 0xDEADBEEF, message); } else { if (logger.isDebugEnabled()) { logger.debug("No servicelink available"); } } } public synchronized void finishedMessage() throws IOException { int len = (int) message.bytesWritten(); byte [] m = buffer; if (len < buffer.length) { m = Arrays.copyOfRange(buffer, 0, len); } for (ReceivePortIdentifier id : connections) { try { send(id, m); } catch (Exception e) { logger.debug("Failed to send message to " + id, e); } } message.reset(); messageInUse = false; notifyAll(); } */ public synchronized void finishedMessage(IOException exception) throws IOException { message.reset(); messageInUse = false; notifyAll(); } }