/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.net.ipv4.tcp; 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.net.SocketImpl; import java.net.SocketOptions; import java.nio.channels.UnresolvedAddressException; import org.apache.log4j.Logger; import org.jnode.net.ipv4.IPv4Address; /** * @author epr */ public class TCPSocketImpl extends SocketImpl { private static final boolean DEBUG = false; /** * The protocol I'm using */ private final TCPProtocol protocol; /** * The control block */ private TCPControlBlock controlBlock; /** * The output stream */ private TCPOutputStream os; /** * The input stream */ private TCPInputStream is; /** * My logger */ private static final Logger log = Logger.getLogger(TCPSocketImpl.class); /** * Initialize a new instance * * @param protocol */ public TCPSocketImpl(TCPProtocol protocol) { this.protocol = protocol; } /** * Accepts a connection on this socket. * * @param s The implementation object for the accepted connection. * @see java.net.SocketImpl#accept(java.net.SocketImpl) */ protected void accept(SocketImpl s) throws IOException { if (DEBUG) { log.debug("accept " + s); } if (controlBlock == null) { throw new IOException("Not listening"); } final TCPSocketImpl impl = (TCPSocketImpl) s; if (DEBUG) { log.debug("accept: blocking"); } impl.controlBlock = controlBlock.appAccept(); if (DEBUG) { log.debug("accept: got one"); } } protected int getLocalPort() { if (DEBUG) { log.debug("getLocalPort: controlBlock.getLocalPort()"); } return controlBlock.getLocalPort(); } /** * @see java.net.SocketImpl#available() */ protected final int available() throws IOException { return getInputStream().available(); } /** * @see java.net.SocketImpl#bind(java.net.InetAddress, int) */ protected void bind(InetAddress host, int port) throws IOException { if (controlBlock != null) { throw new IOException("Already bound"); } if (host.isAnyLocalAddress()) { host = InetAddress.getLocalHost(); } controlBlock = protocol.bind(new IPv4Address(host), port); } /** * @see java.net.SocketImpl#close() */ protected synchronized void close() throws IOException { if (is != null) { is.close(); } if (os != null) { os.close(); } if (controlBlock != null) { controlBlock.appClose(); controlBlock = null; } } /** * @see java.net.SocketImpl#connect(java.net.InetAddress, int) */ protected final void connect(InetAddress host, int port) throws IOException { connect(new InetSocketAddress(host, port), 0); } /** * @see java.net.SocketImpl#connect(java.net.SocketAddress, int) */ protected void connect(SocketAddress address, int timeout) throws IOException { if (!(address instanceof InetSocketAddress)) { throw new IOException("InetSocketAddress expected"); } final InetSocketAddress sa = (InetSocketAddress) address; if (sa.isUnresolved()) { throw new UnresolvedAddressException(); } if (controlBlock == null) { bind(InetAddress.getLocalHost(), 0); } controlBlock.appConnect(new IPv4Address(sa.getAddress()), sa.getPort()); } /** * @see java.net.SocketImpl#connect(java.lang.String, int) */ protected final void connect(String host, int port) throws IOException { connect(InetAddress.getByName(host), port); } /** * @see java.net.SocketImpl#create(boolean) */ protected void create(boolean stream) throws IOException { // Do nothing yet } /** * @see java.net.SocketImpl#getInputStream() */ protected InputStream getInputStream() throws IOException { if (controlBlock == null) { throw new IOException("Connect first"); } if (is == null) { is = new TCPInputStream(controlBlock, this); } return is; } /** * @see java.net.SocketOptions#getOption(int) */ public Object getOption(int option_id) throws SocketException { switch (option_id) { case SocketOptions.SO_BINDADDR: return controlBlock.getLocalAddress().toInetAddress(); case SocketOptions.SO_RCVBUF: return controlBlock.getReceiveBufferSize(); case SocketOptions.SO_SNDBUF: return controlBlock.getSendBufferSize(); case SocketOptions.SO_TIMEOUT: // todo implement it, 0 means disabled return 0; default: throw new SocketException("Option " + option_id + " is not recognised or not implemented"); } } /** * @see java.net.SocketImpl#getOutputStream() */ protected OutputStream getOutputStream() throws IOException { if (controlBlock == null) { throw new IOException("Connect first"); } if (os == null) { os = new TCPOutputStream(controlBlock, this); } return os; } /** * Starts listening for connections on a socket. The backlog parameter is * how many pending connections will queue up waiting to be serviced before * being accept'ed. If the queue of pending requests exceeds this number, * additional connections will be refused. * * @param backlog The length of the pending connection queue * @throws IOException If an error occurs * @see java.net.SocketImpl#listen(int) */ protected void listen(int backlog) throws IOException { if (controlBlock == null) { throw new IOException("Call bind first"); } controlBlock.appListen(); } /** * @see java.net.SocketImpl#sendUrgentData(int) */ protected void sendUrgentData(int data) throws IOException { // TODO Auto-generated method stub } /** * @see java.net.SocketOptions#setOption(int, java.lang.Object) */ public void setOption(int option_id, Object val) throws SocketException { // TODO Auto-generated method stub } /** * @see java.net.SocketImpl#shutdownInput() */ protected final void shutdownInput() throws IOException { getInputStream().close(); } /** * @see java.net.SocketImpl#shutdownOutput() */ protected final void shutdownOutput() throws IOException { getOutputStream().close(); } /** * @see java.net.SocketImpl#getInetAddress() */ protected InetAddress getInetAddress() { if (controlBlock != null) { return controlBlock.getForeignAddress().toInetAddress(); } else { return null; } } /** * @see java.net.SocketImpl#getPort() */ protected int getPort() { if (controlBlock != null) { return controlBlock.getForeignPort(); } else { return 0; } } }