All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gnu.cajo.utils.Multicast Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
package gnu.cajo.utils;

import gnu.cajo.invoke.*;
import java.io.*;
import java.net.*;
import java.rmi.registry.*;
import java.rmi.MarshalledObject;

/*
 * Multicast Announcement Class
 * Copyright (C) 1999 John Catherino
 * The cajo project: https://cajo.dev.java.net
 *
 * For issues or suggestions mailto:[email protected]
 *
 * This file Multicast.java is part of the cajo library.
 *
 * The cajo library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation, at version 3 of the licence, or (at your
 * option) any later version.
 *
 * The cajo 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 Licence for more details.
 *
 * You should have received a copy of the GNU Lesser General Public Licence
 * along with this library. If not, see http://www.gnu.org/licenses/lgpl.html
 */

/**
 * This class can listen for UDP multicasts over the network, as well
 * as to send out UDP announcements.  The mechanism is rigged to send a
 * reference to a remote object as a zipped MarshalledObject (zedmob).  It also
 * allows a listening object to receive announced object referencess via a
 * callback mechanism. A single VM can use as many Multicast objects as it
 * wishes.
 * 

Note: this class requires that the network routers be configured * to pass IP multicast packets, at least for the multicast address used. If * not, the packets will will only exist within the subnet of origination. * * @version 1.0, 01-Nov-99 Initial release * @author John Catherino */ public final class Multicast implements Runnable { private Object callback; private Thread thread; /** * The network interface on which this multicast object is listening */ public final InetAddress host; /** * A reference to the address on which this object is operating. It is * referenced by the called listener, and is valid for the duration of the * object's existence. */ public final String address; /** * A reference to the port on which this object is operating. It is * referenced by the called listener, and is valid for the duration of the * object's existence. */ public final int port; /** * A reference to the address of the calling VM, when the object is * listening. It is referenced by the called listener, and should be * considered valid for the duration of the invocation only. */ public InetAddress iaddr; /** * A reference to a received remote object reference, when the object is * listening. It is referenced by the called listener, and should be * considered valid for the duration of the invocation only. */ public RemoteInvoke item; /** * The default constructor sets the internal fields to default values which * should be sufficient for most purposes. The multicast socket address * will be set to 244.0.23.162, which is officially registered with IANA * for cajo object reference announcements. The UDP port number on which * this object will announce and listen is set to 1198, which is is also * assigned by the IANA, for cajo object reference acquisition. The object * will listen on the same network interface being used for the server's RMI * communication. It sends and listens on the machine's default network * interface * @throws java.net.UnknownHostException If the default network interface * could not be resolved, not very likely. */ public Multicast() throws UnknownHostException { this(null, "224.0.23.162", 1198); } /** * This constructor allows creation of Multicast objects on any * appropriate multicast address, and port number. It uses the default * network interface. * being used for the server's RMI communication. * @param address The multicast socket domain name, or address, on which * this object will listen. It can be any address in the range 224.0.0.1 * through 239.255.255.255. * @param port The UDP port number on which this object will announce and * listen, its value can be 0 - 65535. It is completely independent of all * TCP port numbers. Application specific meaning could be assigned to port * numbers, to identify broadcast types. * @throws java.net.UnknownHostException If the specified host address * could not be resolved, or is invalid. */ public Multicast(String address, int port) throws UnknownHostException { this(null, address, port); } /** * The full constructor allows creation of Multicast objects on any * appropriate address, and port number. It uses the same network interface * being used for the server's RMI communication. * @param host The network interface on which to send or receive multicasts, * specified when a machine has more than one, otherwise use "0.0.0.0" to * send and receive on all of them * @param address The multicast socket domain name, or address, on which * this object will listen. It can be any address in the range 224.0.0.1 * through 239.255.255.255. * @param port The UDP port number on which this object will announce and * listen, its value can be 0 - 65535. It is completely independent of all * TCP port numbers. Application specific meaning could be assigned to port * numbers, to identify broadcast types. * @throws java.net.UnknownHostException If the specified host address * could not be resolved, or is invalid. */ public Multicast(String host, String address, int port) throws UnknownHostException { if (host == null) host = InetAddress.getLocalHost().getHostAddress(); this.host = InetAddress.getByName(host); this.address = address; this.port = port; } /** * This method is used to make UDP announcements on the network. The * provided object will first have its startThread method invoked with a * null argument, to signal it to start its main processing thread (if it * has one). Next it will have its setProxy method invoked remote reference * to itself, with which it can share with remote VMs, in an application * specific manner (again if it has one). * @param item The object reference to be sent in the announcement * packet, if it is not already remoted, it will be, automatically. * @param ttl The time-to-live of the broadcast packet. This roughly * specifies how many multicast enabled routers will pass this packet before * automatically discarding it. For example 16, should cover a medium sized * LAN. The maximum value is 255, which could theoretically cover the globe, * that is, in 1999. A value of 1 confines the packet to its immediate * subnet. * @throws IOException If a datagram socket could not be created, or the * packet could not be sent. */ public void announce(Object item, int ttl) throws IOException { InetAddress group = InetAddress.getByName(address); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (!(item instanceof Remote)) item = new Remote(item); try { Remote.invoke(item, "startThread", null); Remote.invoke(item, "setProxy", new MarshalledObject(item)); } catch(Exception x) {} ((Remote)item).zedmob(baos); byte packet[] = baos.toByteArray(); baos.close(); MulticastSocket ms = new MulticastSocket(); try { ms.setInterface(host); ms.setTimeToLive(ttl); ms.send(new DatagramPacket(packet, packet.length, group, port)); } finally { ms.close(); } } /** * This method is used to make UDP announcements on the network. The * provided object will first have its startThread method invoked with a * null argument, to signal it to start its main processing thread (if it * has one). If the proxy has a setItem method, it will be called with a * remote reference to the serving object. If the item implements a * setProxy method it will be called with a MarshalledObject containing * the proxy object. * @param item The object reference to be sent in the announcement * packet, if it is not already remoted, it will be, automatically. * @param ttl The time-to-live of the broadcast packet. This roughly * specifies how many multicast enabled routers will pass this packet before * automatically discarding it. For example 16, should cover a medium sized * LAN. The maximum value is 255, which could theoretically cover the globe, * that is, in 1999. A value of 1 confines the packet to its immediate * subnet. * @param proxy The proxy object to be sent to requesting clients. * @throws IOException If a datagram socket could not be created, or the * packet could not be sent. */ public void announce(Object item, int ttl, Object proxy) throws IOException { InetAddress group = InetAddress.getByName(address); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (!(item instanceof Remote)) item = new Remote(item); try { Remote.invoke(proxy, "setItem", item); } catch(Exception x) {} try { Remote.invoke(item, "startThread", null); Remote.invoke(item, "setProxy", new MarshalledObject(proxy)); } catch(Exception x) {} ((Remote)item).zedmob(baos); byte packet[] = baos.toByteArray(); baos.close(); MulticastSocket ms = new MulticastSocket(); try { ms.setInterface(host); ms.setTimeToLive(ttl); ms.send(new DatagramPacket(packet, packet.length, group, port)); } finally { ms.close(); } } /** * This method starts a thead to listen on the construction {@link #address * address} and {@link #port port}. The listening object will be called on * its public multicast method, with a reference to the calling Multicast * object. This is to allow the possibility for a single listener, to * monitor multiple multicast objects. If a listener is used to monitor * multiple multicast objects, it may be invoked reentrantly, otherwise it * cannot. Listening will continue until the callback object's multicast * method retruns a non-null value. If it does, this method would havt to * be called again to restart listening. * @param callback An object, presumably local to this VM, which is to * receive notifications about announcements. * @throws IllegalArgumentException If the object is actively listening, at * the time of the invocation. */ public void listen(Object callback) { if (thread == null) { this.callback = callback; thread = new Thread(this); thread.setDaemon(true); thread.start(); } else throw new IllegalArgumentException("Already listening"); } /** * The monitor thread, it listens for multicasts. It will sleep until * the arrival of a message. The packet will be reconstituted into a * remote object reference, from its zedmob encapsulation. The object * reference will be saved into the public item member variable, also the * calling VM's address will be extracted into the public address member * variable. The listener's multicast method will be called next with a * reference to this object. The multicast reference is used to access its * public member variables; the remote announcer's reference and IP address, * as well as the multicast address and port on which it was received. The * second two members are of interest in the case where the same object is * listening on multiple multicast objects. If the method returns null, the * multicast listening will continue, otherwise it will be stopped. Once * stopped it can be restarted by the application as necessary, by invoking * the {@link #listen listen} method again. */ public void run() { try { MulticastSocket ms = new MulticastSocket(port); ms.setInterface(host); ms.joinGroup(InetAddress.getByName(address)); DatagramPacket dp = new DatagramPacket(new byte[0xFF00], 0xFF00); while(!thread.isInterrupted()) try { ms.receive(dp); ByteArrayInputStream bais = new ByteArrayInputStream(dp.getData()); try { item = (RemoteInvoke)Remote.zedmob(bais); iaddr = dp.getAddress(); Object quit = Remote.invoke(callback, "multicast", this); item = null; if (quit != null) break; } catch(Exception x) { x.printStackTrace(); } finally { bais.close(); } } catch(Exception x) { x.printStackTrace(); } ms.close(); ms = null; thread = null; } catch(IOException x) { x.printStackTrace(); } } /** * The application method loads a zipped marshalled object (zedmob) to a * proxy from a URL, or a file, and allows it run in this virtual machine. * It will load an RMISecurityManager to protect the hosting * machine from potentially or accidentally dangerous proxies, if not * prohibited by the user at startup. It uses the {@link * gnu.cajo.invoke.Remote#getItem getitem} method of the {@link * gnu.cajo.invoke.Remote Remote} class to load the object. Following loading, * it will also create an rmiregistry, and bind a remote reference to it * under the name "main". This can allow remote clients to connect to, and * interact with, the object. It will announce its startup on a default * Multicast object, and then begin listening on it for further * announcements, which will be passed to the loaded proxy object. It can * be configured using the following arguments, all arguments subsequent to * the ones specified in the command line can be omitted:

    *
  • args[0] The optional URL where to get the object: file:// http:// * ftp:// ..., /path/name , path/name , or alternatively; * //[host][:port]/[name], where the object will be requested from a remote * rmiregistry and the returned reference cast to the Lookup interface and * invoked with a null reference, to return its proxy object. If no * arguments are provided, the URL will be assumed to be * //localhost:1099/main. *
  • args[1] The optional external client host name, if using NAT. *
  • args[2] The optional external client port number, if using NAT. *
  • args[3] The optional internal client host name, if multi home/NIC. *
  • args[4] The optional internal client port number, if using NAT. *
  • args[5] The optional URL where to get a proxy object: file:// * http:// ftp:// ..., //host:port/name (rmiregistry), /path/name * (serialized), or path/name (class). It will be passed into the loaded * object as the sole argument to a setItem method. *
*/ public static void main(String args[]) throws Exception { if (args.length == 0) args = new String[] { "///main" }; String clientHost = args.length > 1 ? args[1] : null; int clientPort = args.length > 2 ? Integer.parseInt(args[2]) : 0; String localHost = args.length > 3 ? args[3] : null; int localPort = args.length > 4 ? Integer.parseInt(args[4]) : 0; Remote.config(localHost, localPort, clientHost, clientPort); ItemServer.acceptProxies(); Remote item = new Remote(Remote.getItem(args[0])); if (args.length > 5) Remote.invoke(item, "setProxy", Remote.getItem(args[5])); Multicast m = new Multicast(); m.announce(ItemServer.bind(item, "main"), 16); m.listen(item); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy