/******************************************************************************* * Copyright (c) 1997, 2008 by ProSyst Software GmbH * http://www.prosyst.com * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * ProSyst Software GmbH - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.ip.dscagent; import java.io.IOException; import java.io.InterruptedIOException; import java.net.*; import java.util.Dictionary; import org.eclipse.equinox.internal.ip.ProvisioningInfoProvider; import org.eclipse.equinox.internal.ip.impl.Log; import org.eclipse.equinox.internal.ip.impl.ProvisioningAgent; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.provisioning.ProvisioningService; /** * Agent who make FW available for UDM multicast discovery. It joins * provisioning agent to a MulticastSocket and waits for ping replies. The * response contains data that describes gateway. HTTP port is determined using * next algorithm: <BR> * <OL> * <LI>If <I>"equinox.provisioning.gwhttp.port"</I> property is set it is used * for HTTP port value.</LI> * <LI>Else if there has <I>org.osgi.service.HttpService</I> is registered and * the default such service has registration property "openPort", value of this * property is assumed as port. </LI> * <LI>Else HTTP port is assumed to be "80" (the default HTTP port).</LI> * </OL> * * @author Avgustin Marinov * @author Pavlin Dobrev * @version 1.0 */ public class DiscoveryAgent implements Runnable { /** * This property can be used when HTTP service is not a prosyst's * implementation or HTTP is not always, which gives a port with * registration property "openPort", available. */ public static final String HTTP_PORT = "equinox.provisioning.gwhttp.port"; /** * This property can be used when HTTPS service is not a prosyst's * implementation, HTTPS is old prosyst's https implementation, or http is * not always, which gives a port with registration property * "secureOpenPort", or HTTPS is not always available. */ public static final String HTTPS_PORT = "equinox.provisioning.gwhttps.port"; /** * Packet Timeout */ public static final String TIMEOUT = "equinox.provisioning.packet.timeout"; /** * Separator used in string representing gateway. It separates different * parts of that string. */ public static final char SEPARATOR = '#'; /** * The String that corresponds to lack of sPID. */ public static final String NULL = new String(new byte[] {1}); /** Reference to provisioning agent. */ private ProvisioningAgent prvAgent; /** If discoverer service is active. */ private boolean active = true; // Net staff /** The multicast socket. */ private MulticastSocket mcsocket; /** The group. */ private InetAddress group; /** * Bundles context used for determining of HTTP port in ProSyst HTTPS * Service Implementation. */ private BundleContext bc; /** * Constructs instance of Discovery agent. * * @param address * address of multicast host. * @param port * port of multicast host. * @param bc * bundle context used to be accessed framework. * @param prvAgent * the provisioning agent * @throws UnknownHostException * when address cannot be resolved * @throws IOException * on I/O error, when accessing the given address */ public DiscoveryAgent(String address, int port, BundleContext bc, ProvisioningAgent prvAgent) throws UnknownHostException, IOException { group = InetAddress.getByName(address); mcsocket = new MulticastSocket(port); this.bc = bc; this.prvAgent = prvAgent; mcsocket.joinGroup(group); mcsocket.setSoTimeout(ProvisioningAgent.getInteger(TIMEOUT, 10000)); Log.debug("Discovery Agent has joined to multicast socket " + address + ":" + port + "."); } /** * Until close() method is invoked this method accepts packages broadcasted * to multicast host. */ public void run() { byte[] buffer = new byte[256]; DatagramPacket request = new DatagramPacket(buffer, buffer.length); Log.debug("Discovery Agent starting listening."); int errors = 0; while (active) { try { mcsocket.receive(request); /* It is ping send by the backend discoverer */ if ("equinox.provisioning.ping".equals(new String(request.getData(), 0, request.getLength()))) { byte[] data = getResponse(); if (data != null) { DatagramPacket response = new DatagramPacket(data, data.length, group, request.getPort()); /* response.setData(data); */ mcsocket.send(response); } } request.setLength(buffer.length); /* Restore packet length */ } catch (InterruptedIOException _) { } catch (IOException e) { if (errors++ > 5) { Log.debug("Seventh unexpected exception. Discoverer will be closed!", e); return; } } } } /** * Closes discoverer agent */ public void close() { try { active = false; mcsocket.leaveGroup(group); mcsocket.close(); } catch (Exception e) { Log.debug(e); } } /** * Encodes some valuable gateways parameters into string. The format is as * follows:<BR> * <I><spid>#<host>#<http port>#<ready>#<others * info></I><BR> * where:<BR> * <OL> * <LI><I>sPID</I> is service platform id</LI> * <LI><I>host</I> is service platform host</LI> * <LI><I>HTTP port</I> is service platform HTTP port</LI> * <LI><I>ready</I> is service platform is ready with deploying management * agent bundle</LI> * <LI><I>others info</I> is service platform others info in format: * <I>{<key0>=<value0>,<key1>=<value1>...}</I></LI> * </OL> * * @return string representation of gateway data as byte array. */ private byte[] getResponse() { String httpPort = ProvisioningAgent.bc.getProperty(HTTP_PORT); String httpsPort = ProvisioningAgent.bc.getProperty(HTTPS_PORT); // try to determine from service if (httpPort == null || httpsPort == null) { // Not using HttpService.class.getName(), because we don't need to // import // it. ServiceReference sref = bc.getServiceReference("org.osgi.service.http.HttpService"); // HTTP Service is available - explore it if (httpPort == null) httpPort = getPortProperty(sref, "openPort"); if (httpsPort == null) httpsPort = getPortProperty(sref, "secureOpenPort"); } Dictionary info = prvAgent.getInformation(); if (info == null) { return null; } StringBuffer buff = new StringBuffer(); String spid = (String) info.get(ProvisioningService.PROVISIONING_SPID); buff.append(spid == null || spid.length() == 0 ? NULL : spid); buff.append(SEPARATOR); String host = null; try { host = InetAddress.getLocalHost().getHostName(); } catch (Exception e) { host = "unknown"; } buff.append(host); buff.append(SEPARATOR); buff.append(httpPort); buff.append(SEPARATOR); buff.append(httpsPort); buff.append(SEPARATOR); buff.append(info.get(ProvisioningInfoProvider.MANAGER_URL) != null); buff.append(SEPARATOR); buff.append('{'); buff.append(ProvisioningService.PROVISIONING_REFERENCE); buff.append('='); buff.append(info.get(ProvisioningService.PROVISIONING_REFERENCE)); buff.append(','); buff.append(ProvisioningService.PROVISIONING_START_BUNDLE); buff.append('='); buff.append(info.get(ProvisioningService.PROVISIONING_START_BUNDLE)); buff.append('}'); buff.append(SEPARATOR); buff.append(getFlag()); Log.debug("Discoverer agent sends gw info : " + buff); return buff.toString().getBytes(); } public int getFlag() { int flag = 0; if (prvAgent.getHttpAllowed()) { try { new URL("http://").openConnection(); flag |= 0x01; } catch (Exception e) { } } try { new URL("rsh://").openConnection(); flag |= 0x02; } catch (Exception e) { } try { new URL("https://").openConnection(); flag |= 0x04; } catch (Exception e) { } return flag; } private static final String getPortProperty(ServiceReference ref, String property) { Object ret = ref != null ? ref.getProperty(property) : null; return ret == null ? "-1" : "" + ret; } }