/* * Minha.pt: middleware testing platform. * Copyright (c) 2011-2014, Universidade do Minho. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package pt.minha.models.fake.java.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.IllegalBlockingModeException; import pt.minha.models.fake.java.nio.channels.SocketChannel; import pt.minha.models.global.net.ClientTCPSocket; import pt.minha.models.local.lang.SimulationThread; public class Socket { private ClientTCPSocket tcp; private boolean closed; private InputStream in; private OutputStream out; private SocketChannel channel; public Socket() throws IOException { tcp = new ClientTCPSocket(SimulationThread.currentSimulationThread().getProcess().getNetwork()); } public Socket(InetAddress address, int port) throws IOException { this(); this.connect(new InetSocketAddress(address, port)); } public Socket(String address, int port) throws IOException { this(InetAddress.getByName(address), port); } public Socket(SocketChannel channel, ClientTCPSocket tcp) { this.tcp = tcp; this.channel = channel; if (channel == null) createStreams(); } public SocketChannel getChannel() { return channel; } private void checkBlocking() throws IOException { if (channel != null && !channel.isBlocking()) throw new IllegalBlockingModeException(); } private void createStreams() { in = new InputStream() { public int read(byte[] b, int off, int len) throws IOException { long cost = 0; SimulationThread.stopTime(0); try { checkBlocking(); while (!tcp.readers.isReady()) { tcp.readers.queue(SimulationThread.currentSimulationThread().getWakeup()); SimulationThread.currentSimulationThread().pause(false, false); } int res = tcp.read(b, off, len); cost = tcp.getNetwork().getConfig().getTCPOverhead(len); return res; } finally { if (cost<0) cost = 0; tcp.readAt(SimulationThread.currentSimulationThread().getTimeline().getTime()+cost); SimulationThread.startTime(cost); } } public int read() throws IOException { byte[] buf = new byte[1]; int res = read(buf, 0, 1); if (res<0) return res; else return ((int)buf[0])&0xff; } public void close() throws IOException { super.close(); Socket.this.close(); } }; out = new OutputStream() { public void write(byte[] b, int off, int len) throws IOException { long cost = 0; long time = SimulationThread.stopTime(0); try { checkBlocking(); int total = 0, res = 0; while(total+res < len) { while (!tcp.writers.isReady()) { if (res > 0) { total += res; res = 0; cost = tcp.getNetwork().getConfig().getTCPOverhead(total); tcp.uncork(); } tcp.writers.queue(SimulationThread.currentSimulationThread().getWakeup()); SimulationThread.currentSimulationThread().pause(false, false); } res += tcp.write(b, off+total+res, len-(total+res)); } total += res; tcp.uncork(); cost = tcp.getNetwork().getConfig().getTCPOverhead(total); } finally { tcp.writeAt(time); SimulationThread.startTime(cost); } } public void close() throws IOException { super.close(); Socket.this.close(); } public void write(int b) throws IOException { write(new byte[]{(byte)b}); } }; } public void bind(SocketAddress address) throws IOException { tcp.bind((InetSocketAddress)address); } public void connect(SocketAddress endpoint, int timeout) throws IOException { if (endpoint == null) throw new IllegalArgumentException("connect: The address can't be null"); if (timeout < 0) throw new IllegalArgumentException("connect: timeout can't be negative"); if (closed) throw new SocketException("Socket is closed"); if (!(endpoint instanceof InetSocketAddress)) throw new IllegalArgumentException("Unsupported address type"); //TODO: implement timeout logic connect(endpoint); } public void connect(SocketAddress endpoint) throws IOException { if (closed) throw new SocketException("socket closed"); try { SimulationThread.stopTime(0); checkBlocking(); tcp.connect((InetSocketAddress) endpoint); if (!tcp.connectors.isReady()) { tcp.connectors.queue(SimulationThread.currentSimulationThread().getWakeup()); SimulationThread.currentSimulationThread().pause(false, false); } if (!tcp.connectors.isReady()) throw new SocketException("connection refused"); createStreams(); } finally { SimulationThread.startTime(0); } } public OutputStream getOutputStream() throws IOException { if (closed) throw new SocketException("socket closed"); return out; } public InputStream getInputStream() throws IOException { if (closed) throw new SocketException("socket closed"); return in; } public void shutdownOutput() throws IOException { tcp.shutdownOutput(); } public void shutdownInput() throws IOException { tcp.shutdownInput(); } public void close() throws IOException { if (closed) return; this.closed = true; shutdownInput(); shutdownOutput(); if (channel!=null) channel.close(); } public boolean isClosed() { return closed; } public boolean isConnected() { return tcp.connectors.isReady(); } public SocketAddress getRemoteSocketAddress() { return tcp.getRemoteAddress(); } public InetAddress getInetAddress() { return tcp.getRemoteAddress().getAddress(); } public int getPort() { return tcp.getRemoteAddress().getPort(); } public SocketAddress getLocalSocketAddress() { return tcp.getLocalAddress(); } public InetAddress getLocalAddress() { return tcp.getLocalAddress().getAddress(); } public int getLocalPort() { return tcp.getLocalAddress().getPort(); } public int getReceiveBufferSize() throws SocketException { return 65535; } public void setReceiveBufferSize(int size) throws SocketException { // not implemented } public int getSendBufferSize() throws SocketException { return 65535; } public void setSendBufferSize(int size) throws SocketException { // not implemented } public void setSoTimeout(int timeout) { // TODO } public void setTcpNoDelay(boolean noDelay) { // TODO } public void setKeepAlive(boolean keepAlive) { // TODO } public void setSoLinger(boolean linger, int timeout) { // TODO } public void setReuseAddress(boolean reuseAddress) { // TODO } public String toString() { return "Socket[addr=" + this.getRemoteSocketAddress() + ",localaddr=" + this.getLocalSocketAddress()+"]"; } }