/* * $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.util; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocketImpl; import java.net.ExSocketOptions; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import org.jnode.bootlog.BootLogInstance; import org.jnode.driver.Device; import org.jnode.driver.DeviceNotFoundException; import org.jnode.driver.DeviceUtils; import org.jnode.net.SocketBuffer; import org.jnode.net.ethernet.EthernetConstants; import org.jnode.util.Queue; /** * @author epr */ public abstract class AbstractDatagramSocketImpl extends DatagramSocketImpl implements ExSocketOptions { /** The receive queue of SocketBuffer instances */ private final Queue<SocketBuffer> receiveQueue = new Queue<SocketBuffer>(); /** Have I been closed? */ private boolean closed; /** Time to live */ private int ttl = 0xFF; /** Type of service */ private int tos = 0; /** Timeout of network operations */ private int timeout = 0; /** Local address */ private InetAddress laddr; /** Send using broadcast addresses? */ private boolean broadcast = true; /** Device used for transmission (can be null) */ private Device device; /** * Create a new instance */ public AbstractDatagramSocketImpl() { this.closed = false; } /** * @see java.net.DatagramSocketImpl#bind(int, java.net.InetAddress) */ protected final synchronized void bind(int lport, InetAddress laddr) throws SocketException { this.localPort = lport; this.laddr = laddr; doBind(lport, laddr); } protected abstract void doBind(int lport, InetAddress laddr) throws SocketException; /** * @see java.net.DatagramSocketImpl#close() */ protected final synchronized void close() { if (!closed) { this.closed = true; doClose(); receiveQueue.close(); } } protected abstract void doClose(); /** * @see java.net.DatagramSocketImpl#create() */ protected void create() throws SocketException { // Nothing todo here } /** * @see java.net.SocketOptions#getOption(int) */ public final synchronized Object getOption(int option_id) throws SocketException { if (closed) { throw new SocketException("DatagramSocket closed"); } switch (option_id) { case IP_TOS: return tos; case SO_BINDADDR: return laddr; case SO_BROADCAST: return broadcast; case SO_RCVBUF: return EthernetConstants.ETH_FRAME_LEN; case SO_SNDBUF: return EthernetConstants.ETH_FRAME_LEN; case SO_TRANSMIT_IF: return (device == null) ? null : NetworkInterface.getByName(device.getId()); case SO_TIMEOUT: return timeout; default: return doGetOption(option_id); } } protected Object doGetOption(int option_id) throws SocketException { throw new SocketException("Unknown option " + option_id); } /** * @see java.net.SocketOptions#setOption(int, java.lang.Object) */ public final synchronized void setOption(int option_id, Object val) throws SocketException { if (closed) { throw new SocketException("DatagramSocket closed"); } try { switch (option_id) { case IP_TOS: tos = (Integer) val; break; case SO_BINDADDR: throw new SocketException("Get only option: SO_BINDADDR"); case SO_BROADCAST: broadcast = (Boolean) val; break; case SO_RCVBUF: /* ignore */ break; case SO_SNDBUF: /* ignore */ break; case SO_TRANSMIT_IF: if (val == null) { device = null; } else { final NetworkInterface netIf = (NetworkInterface) val; try { device = DeviceUtils.getDevice(netIf.getName()); } catch (DeviceNotFoundException ex) { throw new SocketException("Unknown networkinterface " + netIf.getName()); } } break; case SO_TIMEOUT: timeout = (Integer) val; break; case SO_REUSEADDR: // Ignored for now break; default: doSetOption(option_id, val); } } catch (ClassCastException ex) { throw (SocketException) new SocketException("Invalid option type").initCause(ex); } } protected void doSetOption(int option_id, Object val) throws SocketException { BootLogInstance.get().error("Unknown option " + option_id); } /** * @see java.net.DatagramSocketImpl#getTimeToLive() */ protected final int getTimeToLive() throws IOException { return ttl; } /** * @see java.net.DatagramSocketImpl#join(java.net.InetAddress) */ protected void join(InetAddress inetaddr) throws IOException { // TODO Auto-generated method stub } /** * @see java.net.DatagramSocketImpl#joinGroup(java.net.SocketAddress, * java.net.NetworkInterface) */ protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException { // TODO Auto-generated method stub } /** * @see java.net.DatagramSocketImpl#leave(java.net.InetAddress) */ protected void leave(InetAddress inetaddr) throws IOException { // TODO Auto-generated method stub } /** * @see java.net.DatagramSocketImpl#leaveGroup(java.net.SocketAddress, * java.net.NetworkInterface) */ protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException { // TODO Auto-generated method stub } /** * @see java.net.DatagramSocketImpl#peek(java.net.InetAddress) */ protected int peek(InetAddress i) throws IOException { // TODO Auto-generated method stub return 0; } /** * @see java.net.DatagramSocketImpl#peekData(java.net.DatagramPacket) */ protected int peekData(DatagramPacket p) throws IOException { throw new IOException("Not implemented"); } /** * @see java.net.DatagramSocketImpl#receive(java.net.DatagramPacket) */ protected final void receive(DatagramPacket p) throws IOException { if (closed) { throw new SocketException("DatagramSocket has been closed"); } final SocketBuffer skbuf = (SocketBuffer) receiveQueue.get(timeout); if (skbuf == null) { if (closed) { throw new SocketException("DatagramSocket has been closed"); } else { throw new SocketTimeoutException("Timeout in receive"); } } else { onReceive(p, skbuf); } } protected abstract void onReceive(DatagramPacket p, SocketBuffer skbuf) throws IOException; /** * Deliver a packet to this socket. This will put the packet in the * receive queue if this socket has not been closed. * @param skbuf */ public final boolean deliverReceived(SocketBuffer skbuf) { if (!closed) { receiveQueue.add(skbuf); return true; } else { return false; } } /** * @see java.net.DatagramSocketImpl#setTimeToLive(int) */ protected final void setTimeToLive(int ttl) { this.ttl = ttl; } /** * Gets the local port of this socket * @see java.net.DatagramSocketImpl#getLocalPort() */ public final int getLocalPort() { return super.getLocalPort(); } /** * Gets the local port of this socket */ public final InetAddress getLocalAddress() { return laddr; } /** * @see java.lang.Object#finalize() */ protected void finalize() throws Throwable { close(); super.finalize(); } /** * Gets the device used to send/receive packets. */ protected Device getDevice() { return device; } /** * Gets the timeout used in receive */ protected int getTimeout() { return timeout; } /** * Gets the Type of Service, used in send */ protected int getTos() { return tos; } }