/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.jini.discovery; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import net.jini.core.lookup.ServiceID; /** * Encapsulate the details of unmarshaling an incoming multicast * request packet. * * @author Sun Microsystems, Inc. * * @see OutgoingMulticastRequest */ public class IncomingMulticastRequest { /** * The address to which any responses should go. */ protected InetAddress addr; /** * The port to which any responses should connect. */ protected int port; /** * The ServiceIDs from which the requestor has already heard. * This set may not be complete. */ protected ServiceID[] serviceIDs; /** * The groups in which the requestor is interested. This set may * not be complete. */ protected String[] groups; /** * The current version of the multicast request protocol. */ protected final int protoVersion = 1; /** * Construct a new object, initialized from the contents of the * given multicast request packet. * * @param dgram the packet to unmarshal * @exception IOException a problem occurred while unmarshaling * the packet */ public IncomingMulticastRequest(DatagramPacket dgram) throws IOException { ByteArrayInputStream bs = new ByteArrayInputStream(dgram.getData()); DataInputStream ds = new DataInputStream(bs); int proto = ds.readInt(); if (proto != protoVersion) throw new IOException("unsupported protocol version: " + proto); port = ds.readInt(); // Valid port ranges are 1 through 65535 for IPv4. if (port <= 0 || port >= 65536) throw new IOException("port number out of range: " + port); int sidCount = ds.readInt(); // We know that a ServiceID marshals to 8 bytes, so ensure // that the count can plausibly fit into this packet. if (sidCount < 0 || sidCount > bs.available() / 8) throw new IOException("service ID count invalid: " + sidCount); serviceIDs = new ServiceID[sidCount]; for (int i = 0; i < serviceIDs.length; i++) { serviceIDs[i] = new ServiceID(ds); } int grpCount = ds.readInt(); // We know that the minimal length of a string written with // DataOutput.writeUTF is two bytes (for the empty string), so // we make some attempt to see if the count can plausibly fit // into this packet. if (grpCount < 0 || grpCount > bs.available() / 2) throw new IOException("group count invalid: " + grpCount); groups = new String[grpCount]; for (int i = 0; i < groups.length; i++) { groups[i] = ds.readUTF(); } addr = dgram.getAddress(); } /** * Return the address of the host to contact in order to start * unicast discovery. * * @return the address of the host to contact in order to start * unicast discovery */ public InetAddress getAddress() { return addr; } /** * Return the number of the port to connect to on the remote host * in order to start unicast discovery. * * @return the number of the port to connect to on the remote host * in order to start unicast discovery */ public int getPort() { return port; } /** * Return the set of groups in which the requestor is interested. * This set may not be complete, but other incoming packets should * contain the rest of the set. * * @return the set of groups in which the requestor is interested. */ public String[] getGroups() { return groups; } /** * Return a set of ServiceIDs from which the requestor has already * heard. This set may not be complete. * * @return a set of service IDs from which the requestor has already * heard */ public ServiceID[] getServiceIDs() { return serviceIDs; } public int hashCode() { byte[] foo = addr.getAddress(); int code = (foo[0] << 3) ^ (foo[1] << 7) ^ (foo[2] << 5) ^ (foo[3] << 1) ^ ~port; for (int i = 0; i < groups.length; i++) { code ^= groups[i].hashCode() << i; } for (int i = 0; i < serviceIDs.length; i++) { code ^= serviceIDs[i].hashCode() << i; } return code; } /** * Two requests are equal if they have the same address, port, * groups, and service IDs. */ public boolean equals(Object o) { // We assume here that multiple requests from the same machine // will have the same source IP address. This is not // necessarily true. if (o instanceof IncomingMulticastRequest) { IncomingMulticastRequest oo = (IncomingMulticastRequest) o; if (oo.addr.equals(addr) && oo.port == port && oo.groups.length == groups.length && oo.serviceIDs.length == serviceIDs.length) { for (int i = 0; i < groups.length; i++) { if (!groups[i].equals(oo.groups[i])) return false; } for (int i = 0; i < serviceIDs.length; i++) { if (!serviceIDs[i].equals(oo.serviceIDs[i])) return false; } return true; } } return false; } }