1 /******************************************************************************* 2 * Copyright (c) 1997, 2008 by ProSyst Software GmbH 3 * http://www.prosyst.com 4 * 5 * This program and the accompanying materials 6 * are made available under the terms of the Eclipse Public License 2.0 7 * which accompanies this distribution, and is available at 8 * https://www.eclipse.org/legal/epl-2.0/ 9 * 10 * SPDX-License-Identifier: EPL-2.0 11 * 12 * Contributors: 13 * ProSyst Software GmbH - initial API and implementation 14 *******************************************************************************/ 15 package org.eclipse.equinox.internal.ip.dscagent; 16 17 import java.io.IOException; 18 import java.io.InterruptedIOException; 19 import java.net.*; 20 import java.util.Dictionary; 21 import org.eclipse.equinox.internal.ip.ProvisioningInfoProvider; 22 import org.eclipse.equinox.internal.ip.impl.Log; 23 import org.eclipse.equinox.internal.ip.impl.ProvisioningAgent; 24 import org.osgi.framework.BundleContext; 25 import org.osgi.framework.ServiceReference; 26 import org.osgi.service.provisioning.ProvisioningService; 27 28 /** 29 * Agent who make FW available for UDM multicast discovery. It joins 30 * provisioning agent to a MulticastSocket and waits for ping replies. The 31 * response contains data that describes gateway. HTTP port is determined using 32 * next algorithm: <BR> 33 * <OL> 34 * <LI>If <I>"equinox.provisioning.gwhttp.port"</I> property is set it is used 35 * for HTTP port value.</LI> 36 * <LI>Else if there has <I>org.osgi.service.HttpService</I> is registered and 37 * the default such service has registration property "openPort", value of this 38 * property is assumed as port. </LI> 39 * <LI>Else HTTP port is assumed to be "80" (the default HTTP port).</LI> 40 * </OL> 41 * 42 * @author Avgustin Marinov 43 * @author Pavlin Dobrev 44 * @version 1.0 45 */ 46 47 public class DiscoveryAgent implements Runnable { 48 49 /** 50 * This property can be used when HTTP service is not a prosyst's 51 * implementation or HTTP is not always, which gives a port with 52 * registration property "openPort", available. 53 */ 54 public static final String HTTP_PORT = "equinox.provisioning.gwhttp.port"; 55 56 /** 57 * This property can be used when HTTPS service is not a prosyst's 58 * implementation, HTTPS is old prosyst's https implementation, or http is 59 * not always, which gives a port with registration property 60 * "secureOpenPort", or HTTPS is not always available. 61 */ 62 public static final String HTTPS_PORT = "equinox.provisioning.gwhttps.port"; 63 64 /** 65 * Packet Timeout 66 */ 67 public static final String TIMEOUT = "equinox.provisioning.packet.timeout"; 68 69 /** 70 * Separator used in string representing gateway. It separates different 71 * parts of that string. 72 */ 73 public static final char SEPARATOR = '#'; 74 75 /** 76 * The String that corresponds to lack of sPID. 77 */ 78 public static final String NULL = new String(new byte[] {1}); 79 80 /** Reference to provisioning agent. */ 81 private ProvisioningAgent prvAgent; 82 83 /** If discoverer service is active. */ 84 private boolean active = true; 85 86 // Net staff 87 /** The multicast socket. */ 88 private MulticastSocket mcsocket; 89 /** The group. */ 90 private InetAddress group; 91 92 /** 93 * Bundles context used for determining of HTTP port in ProSyst HTTPS 94 * Service Implementation. 95 */ 96 private BundleContext bc; 97 98 /** 99 * Constructs instance of Discovery agent. 100 * 101 * @param address 102 * address of multicast host. 103 * @param port 104 * port of multicast host. 105 * @param bc 106 * bundle context used to be accessed framework. 107 * @param prvAgent 108 * the provisioning agent 109 * @throws UnknownHostException 110 * when address cannot be resolved 111 * @throws IOException 112 * on I/O error, when accessing the given address 113 */ DiscoveryAgent(String address, int port, BundleContext bc, ProvisioningAgent prvAgent)114 public DiscoveryAgent(String address, int port, BundleContext bc, ProvisioningAgent prvAgent) throws UnknownHostException, IOException { 115 group = InetAddress.getByName(address); 116 mcsocket = new MulticastSocket(port); 117 this.bc = bc; 118 this.prvAgent = prvAgent; 119 mcsocket.joinGroup(group); 120 mcsocket.setSoTimeout(ProvisioningAgent.getInteger(TIMEOUT, 10000)); 121 Log.debug("Discovery Agent has joined to multicast socket " + address + ":" + port + "."); 122 } 123 124 /** 125 * Until close() method is invoked this method accepts packages broadcasted 126 * to multicast host. 127 */ run()128 public void run() { 129 byte[] buffer = new byte[256]; 130 DatagramPacket request = new DatagramPacket(buffer, buffer.length); 131 Log.debug("Discovery Agent starting listening."); 132 int errors = 0; 133 while (active) { 134 try { 135 mcsocket.receive(request); 136 /* It is ping send by the backend discoverer */ 137 if ("equinox.provisioning.ping".equals(new String(request.getData(), 0, request.getLength()))) { 138 byte[] data = getResponse(); 139 if (data != null) { 140 DatagramPacket response = new DatagramPacket(data, data.length, group, request.getPort()); 141 /* response.setData(data); */ 142 mcsocket.send(response); 143 } 144 } 145 request.setLength(buffer.length); /* Restore packet length */ 146 } catch (InterruptedIOException _) { 147 } catch (IOException e) { 148 if (errors++ > 5) { 149 Log.debug("Seventh unexpected exception. Discoverer will be closed!", e); 150 return; 151 } 152 } 153 } 154 } 155 156 /** 157 * Closes discoverer agent 158 */ close()159 public void close() { 160 try { 161 active = false; 162 mcsocket.leaveGroup(group); 163 mcsocket.close(); 164 } catch (Exception e) { 165 Log.debug(e); 166 } 167 } 168 169 /** 170 * Encodes some valuable gateways parameters into string. The format is as 171 * follows:<BR> 172 * <I><spid>#<host>#<http port>#<ready>#<others 173 * info></I><BR> 174 * where:<BR> 175 * <OL> 176 * <LI><I>sPID</I> is service platform id</LI> 177 * <LI><I>host</I> is service platform host</LI> 178 * <LI><I>HTTP port</I> is service platform HTTP port</LI> 179 * <LI><I>ready</I> is service platform is ready with deploying management 180 * agent bundle</LI> 181 * <LI><I>others info</I> is service platform others info in format: 182 * <I>{<key0>=<value0>,<key1>=<value1>...}</I></LI> 183 * </OL> 184 * 185 * @return string representation of gateway data as byte array. 186 */ getResponse()187 private byte[] getResponse() { 188 String httpPort = ProvisioningAgent.bc.getProperty(HTTP_PORT); 189 String httpsPort = ProvisioningAgent.bc.getProperty(HTTPS_PORT); 190 191 // try to determine from service 192 if (httpPort == null || httpsPort == null) { 193 // Not using HttpService.class.getName(), because we don't need to 194 // import 195 // it. 196 ServiceReference sref = bc.getServiceReference("org.osgi.service.http.HttpService"); 197 // HTTP Service is available - explore it 198 if (httpPort == null) 199 httpPort = getPortProperty(sref, "openPort"); 200 if (httpsPort == null) 201 httpsPort = getPortProperty(sref, "secureOpenPort"); 202 } 203 204 Dictionary info = prvAgent.getInformation(); 205 if (info == null) { 206 return null; 207 } 208 209 StringBuffer buff = new StringBuffer(); 210 String spid = (String) info.get(ProvisioningService.PROVISIONING_SPID); 211 buff.append(spid == null || spid.length() == 0 ? NULL : spid); 212 buff.append(SEPARATOR); 213 String host = null; 214 try { 215 host = InetAddress.getLocalHost().getHostName(); 216 } catch (Exception e) { 217 host = "unknown"; 218 } 219 buff.append(host); 220 buff.append(SEPARATOR); 221 buff.append(httpPort); 222 buff.append(SEPARATOR); 223 buff.append(httpsPort); 224 buff.append(SEPARATOR); 225 buff.append(info.get(ProvisioningInfoProvider.MANAGER_URL) != null); 226 buff.append(SEPARATOR); 227 buff.append('{'); 228 buff.append(ProvisioningService.PROVISIONING_REFERENCE); 229 buff.append('='); 230 buff.append(info.get(ProvisioningService.PROVISIONING_REFERENCE)); 231 buff.append(','); 232 buff.append(ProvisioningService.PROVISIONING_START_BUNDLE); 233 buff.append('='); 234 buff.append(info.get(ProvisioningService.PROVISIONING_START_BUNDLE)); 235 buff.append('}'); 236 buff.append(SEPARATOR); 237 buff.append(getFlag()); 238 Log.debug("Discoverer agent sends gw info : " + buff); 239 return buff.toString().getBytes(); 240 } 241 getFlag()242 public int getFlag() { 243 int flag = 0; 244 if (prvAgent.getHttpAllowed()) { 245 try { 246 new URL("http://").openConnection(); 247 flag |= 0x01; 248 } catch (Exception e) { 249 } 250 } 251 252 try { 253 new URL("rsh://").openConnection(); 254 flag |= 0x02; 255 } catch (Exception e) { 256 } 257 258 try { 259 new URL("https://").openConnection(); 260 flag |= 0x04; 261 } catch (Exception e) { 262 } 263 264 return flag; 265 } 266 getPortProperty(ServiceReference ref, String property)267 private static final String getPortProperty(ServiceReference ref, String property) { 268 Object ret = ref != null ? ref.getProperty(property) : null; 269 return ret == null ? "-1" : "" + ret; 270 } 271 272 } 273