/* * $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.service; import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import org.jnode.driver.ApiNotFoundException; import org.jnode.driver.Device; import org.jnode.driver.net.NetDeviceAPI; import org.jnode.driver.net.NetworkException; import org.jnode.net.LayerAlreadyRegisteredException; import org.jnode.net.NetworkLayer; import org.jnode.net.NetworkLayerManager; import org.jnode.net.NoSuchProtocolException; import org.jnode.net.SocketBuffer; import org.jnode.plugin.ConfigurationElement; import org.jnode.plugin.Extension; import org.jnode.plugin.ExtensionPoint; import org.jnode.plugin.ExtensionPointListener; import org.jnode.util.NumberUtils; import org.jnode.util.Queue; import org.jnode.util.QueueProcessor; /** * @author epr */ public class DefaultNetworkLayerManager implements NetworkLayerManager, QueueProcessor<SocketBuffer>, ExtensionPointListener { /** My logger */ private static final Logger log = Logger.getLogger(DefaultNetworkLayerManager.class); /** Registered packet types */ private final HashMap<Integer, NetworkLayer> layers = new HashMap<Integer, NetworkLayer>(); /** Queue of received packets */ private final Queue<SocketBuffer> packetQueue = new Queue<SocketBuffer>(); /** The networkLayers extension-point */ private final ExtensionPoint networkLayersEP; /** * Initialize a new instance * * @param networkLayersEP */ public DefaultNetworkLayerManager(ExtensionPoint networkLayersEP) { this.networkLayersEP = networkLayersEP; networkLayersEP.addListener(this); refreshNetworkLayers(); } /** * Register a packet type. * * @param pt */ protected synchronized void registerNetworkLayer(NetworkLayer pt) throws LayerAlreadyRegisteredException { layers.put(pt.getProtocolID(), pt); } /** * Unregister a packet type. If the packettype has not been registered, this * method returns without an error. * * @param pt */ public synchronized void unregisterNetworkLayer(NetworkLayer pt) { layers.remove(pt); } /** * Get all register packet types. * * @return A collection of PacketType instances */ public synchronized Collection<NetworkLayer> getNetworkLayers() { return new ArrayList<NetworkLayer>(layers.values()); } /** * Gets the packet type for a given protocol ID * * @param protocolID * @throws NoSuchProtocolException */ public NetworkLayer getNetworkLayer(int protocolID) throws NoSuchProtocolException { final NetworkLayer pt = (NetworkLayer) layers.get(Integer.valueOf(protocolID)); if (pt == null) { throw new NoSuchProtocolException("protocolID " + protocolID); } return pt; } /** * Process a packet that has been received. The receive method of all those * packettypes that have a matching type and allow the device(of the packet) * is called. The packet is cloned if more then 1 packettypes want to * receive the packet. * * @param skbuf */ public void receive(SocketBuffer skbuf) { packetQueue.add(skbuf); } /** * Process the received packet * * @param skbuf */ public synchronized void process(SocketBuffer skbuf) { try { final int protoID = skbuf.getProtocolID(); final Device dev = skbuf.getDevice(); if (dev == null) { throw new NetworkException("Device not set on SocketBuffer"); } final NetDeviceAPI deviceAPI; try { deviceAPI = dev.getAPI(NetDeviceAPI.class); } catch (ApiNotFoundException ex) { throw new NetworkException("Device in SocketBuffer is not a network device"); } // Find all the packettype that want to process the given packet try { final NetworkLayer pt = getNetworkLayer(protoID); if (pt.isAllowedForDevice(dev)) { pt.receive(skbuf, deviceAPI); } } catch (NoSuchProtocolException ex) { log.debug("No network layer handler for protocol 0x" + NumberUtils.hex(protoID, 4)); } } catch (SocketException ex) { log.error("Cannot process packet", ex); } } /** * Gets the packet queue */ protected final Queue<SocketBuffer> getQueue() { return packetQueue; } /** * Reload the network layer list from the extension-point */ protected void refreshNetworkLayers() { if (networkLayersEP != null) { layers.clear(); final Extension[] extensions = networkLayersEP.getExtensions(); for (final Extension ext : extensions) { final ConfigurationElement[] elements = ext.getConfigurationElements(); for (ConfigurationElement element : elements) { configureLayer(layers, element); } } } log.debug("Found " + layers.size() + " network layers"); } private void configureLayer(Map<Integer, NetworkLayer> layers, ConfigurationElement element) { final String className = element.getAttribute("class"); if (className != null) { try { final Class<?> cls = Thread.currentThread().getContextClassLoader().loadClass(className); final NetworkLayer layer = (NetworkLayer) cls.newInstance(); layers.put(layer.getProtocolID(), layer); } catch (ClassNotFoundException ex) { log.error("Cannot find networklayer class " + className); } catch (IllegalAccessException ex) { log.error("Cannot access networklayer class " + className); } catch (InstantiationException ex) { log.error("Cannot instantiate networklayer class " + className); } catch (ClassCastException ex) { log.error("Networklayer class " + className + " does not implement the NetworkLayer interface"); } } } /** * @see org.jnode.plugin.ExtensionPointListener#extensionAdded(org.jnode.plugin.ExtensionPoint, * org.jnode.plugin.Extension) */ public void extensionAdded(ExtensionPoint point, Extension extension) { refreshNetworkLayers(); } /** * @see org.jnode.plugin.ExtensionPointListener#extensionRemoved(org.jnode.plugin.ExtensionPoint, * org.jnode.plugin.Extension) */ public void extensionRemoved(ExtensionPoint point, Extension extension) { refreshNetworkLayers(); } }