package ibis.ipl.support; import ibis.io.Conversion; import ibis.io.IOProperties; import ibis.ipl.impl.IbisIdentifier; import ibis.smartsockets.virtual.VirtualServerSocket; import ibis.smartsockets.virtual.VirtualSocket; import ibis.smartsockets.virtual.VirtualSocketAddress; import ibis.smartsockets.virtual.VirtualSocketFactory; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Connection to the server and between clients using smartsockets. * * @author ndrost * */ public final class Connection { private static final Logger logger = LoggerFactory .getLogger(Connection.class); private final VirtualSocket socket; private final DataOutputStream out; private final DataInputStream in; private final CountInputStream counter; static final byte REPLY_ERROR = 2; static final byte REPLY_OK = 1; private static VirtualSocketAddress addressFromIdentifier( IbisIdentifier ibis, int virtualPort) throws IOException { VirtualSocketAddress registryAddress = VirtualSocketAddress.fromBytes( ibis.getRegistryData(), 0); if (registryAddress.port() == virtualPort) { return registryAddress; } // wrong port, create new address with correct port return new VirtualSocketAddress(registryAddress.machine(), virtualPort, registryAddress.hub(), registryAddress.cluster()); } public Connection(IbisIdentifier ibis, int timeout, boolean fillTimeout, VirtualSocketFactory factory, int virtualPort) throws IOException { this(addressFromIdentifier(ibis, virtualPort), timeout, fillTimeout, factory); } public Connection(VirtualSocketAddress address, int timeout, boolean fillTimeout, VirtualSocketFactory factory) throws IOException { logger.debug("connecting to " + address + ", timeout = " + timeout + " , filltimeout = " + fillTimeout); final HashMap<String, Object> lightConnection = new HashMap<String, Object>(); // lightConnection.put("connect.module.allow", // "ConnectModule(HubRouted)"); socket = factory.createClientSocket(address, timeout, fillTimeout, lightConnection); socket.setTcpNoDelay(true); out = new DataOutputStream(new BufferedOutputStream(socket .getOutputStream(), IOProperties.BUFFER_SIZE)); counter = new CountInputStream(new BufferedInputStream(socket .getInputStream(), IOProperties.BUFFER_SIZE)); in = new DataInputStream(counter); logger.debug("connection to " + address + " established"); } /** * Accept incoming connection on given serverSocket. */ public Connection(VirtualServerSocket serverSocket) throws IOException { logger.debug("waiting for incomming connection..."); socket = serverSocket.accept(); socket.setTcpNoDelay(true); counter = new CountInputStream(new BufferedInputStream(socket .getInputStream(), IOProperties.BUFFER_SIZE)); in = new DataInputStream(counter); out = new DataOutputStream(new BufferedOutputStream(socket .getOutputStream(), IOProperties.BUFFER_SIZE)); logger.debug("new connection from " + socket.getRemoteSocketAddress() + " accepted"); } public DataOutputStream out() { return out; } public DataInputStream in() { return in; } public Object readObject() throws IOException, ClassNotFoundException { int size = in.readInt(); if (size < 0) { throw new IOException("negative object size"); } byte[] bytes = new byte[size]; in.readFully(bytes); return Conversion.byte2object(bytes); } public void writeObject(Object object) throws IOException { byte[] bytes = Conversion.object2byte(object); out.writeInt(bytes.length); out.write(bytes); } public int written() { return out.size(); } public int read() { return counter.getCount(); } public void getAndCheckReply() throws IOException { // flush output, just in case... out.flush(); // get reply byte reply = in.readByte(); if (reply == Connection.REPLY_ERROR) { String message = in.readUTF(); close(); throw new RemoteException(message); } else if (reply != Connection.REPLY_OK) { close(); throw new IOException("Unknown reply (" + reply + ")"); } } public void sendOKReply() throws IOException { out.writeByte(Connection.REPLY_OK); out.flush(); } public void closeWithError(String message) { if (message == null) { message = ""; } try { out.writeByte(Connection.REPLY_ERROR); out.writeUTF(message); close(); } catch (IOException e) { // IGNORE } } public void close() { try { out.flush(); } catch (IOException e) { // IGNORE } try { out.close(); } catch (IOException e) { // IGNORE } try { in.close(); } catch (IOException e) { // IGNORE } try { socket.close(); } catch (IOException e) { // IGNORE } } }