Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
improve "get port" mechanism (#2331)
Browse files Browse the repository at this point in the history
* improve "get port" mechanism

It is not mandatory that the system property is used for setting the
service port. So we should also respect the service property.

The configuration admin is e.g. used by Pax Web.

See also: http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html
The service can both be configured using OSGi environment properties and
using Configuration Admin. ... If you use both methods, Configuration Admin
takes precedence.

Signed-off-by: Markus Rathgeb <maggu2810@gmail.com>
  • Loading branch information
maggu2810 authored and kaikreuzer committed Oct 25, 2016
1 parent 7033c63 commit f052a1a
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Import-Package: javax.servlet,
org.eclipse.smarthome.core.items,
org.eclipse.smarthome.core.items.events,
org.eclipse.smarthome.core.library.types,
org.eclipse.smarthome.core.net,
org.eclipse.smarthome.core.types,
org.eclipse.smarthome.io.console,
org.eclipse.smarthome.io.console.extensions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;
Expand All @@ -31,6 +29,8 @@
import org.eclipse.smarthome.core.audio.AudioHTTPServer;
import org.eclipse.smarthome.core.audio.AudioStream;
import org.eclipse.smarthome.core.audio.FixedLengthAudioStream;
import org.eclipse.smarthome.core.net.HttpServiceUtil;
import org.eclipse.smarthome.core.net.NetUtil;
import org.osgi.framework.BundleContext;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
Expand Down Expand Up @@ -195,13 +195,21 @@ public URL serve(FixedLengthAudioStream stream, int seconds) {

private URL getURL(String streamId) {
try {
String ipAddress = InetAddress.getLocalHost().getHostAddress(); // we use the primary interface; if a client
// knows it any better, he can himself
// change the url according to his needs.
String port = bundleContext.getProperty("org.osgi.service.http.port"); // we do not use SSL as it can cause
// certificate validation issues.
final String ipAddress = NetUtil.getLocalIpv4HostAddress();
if (ipAddress == null) {
logger.warn("No network interface could be found.");
return null;
}

// we do not use SSL as it can cause certificate validation issues.
final int port = HttpServiceUtil.getHttpServicePort(bundleContext);
if (port == -1) {
logger.warn("Cannot find port of the http service.");
return null;
}

return new URL("http://" + ipAddress + ":" + port + SERVLET_NAME + "/" + streamId);
} catch (UnknownHostException | MalformedURLException e) {
} catch (final MalformedURLException e) {
logger.error("Failed to construct audio stream URL: {}", e.getMessage(), e);
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Export-Package: org.eclipse.smarthome.core.binding,
org.eclipse.smarthome.core.items.events,
org.eclipse.smarthome.core.library.items,
org.eclipse.smarthome.core.library.types,
org.eclipse.smarthome.core.net,
org.eclipse.smarthome.core.scheduler,
org.eclipse.smarthome.core.service,
org.eclipse.smarthome.core.storage,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
* 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
*/
package org.eclipse.smarthome.core.net;

import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Some utility functions related to the http service
*
* @author Markus Rathgeb - Initial contribution and API
*/
public class HttpServiceUtil {

private HttpServiceUtil() {
}

/**
* Get the port that is used by the HTTP service.
*
* @param bc the bundle context used for lookup
* @return the port if used, -1 if no port could be found
*/
public static int getHttpServicePort(final BundleContext bc) {
return getHttpServicePortProperty(bc, "org.osgi.service.http.port");
}

public static int getHttpServicePortSecure(final BundleContext bc) {
return getHttpServicePortProperty(bc, "org.osgi.service.http.port.secure");
}

// Utility method that could be used for non-secure and secure port.
private static int getHttpServicePortProperty(final BundleContext bc, final String propertyName) {
Object value;
int port = -1;

// Try to find the port by using the service property (respect service ranking).
try {
int candidate = Integer.MIN_VALUE;
final ServiceReference[] refs = bc.getAllServiceReferences("org.osgi.service.http.HttpService", null);
for (final ServiceReference ref : refs) {
value = ref.getProperty(propertyName);
if (value == null) {
continue;
}
final int servicePort;
try {
servicePort = Integer.parseInt(value.toString());
} catch (final NumberFormatException ex) {
continue;
}
value = ref.getProperty(Constants.SERVICE_RANKING);
final int serviceRanking;
if (value == null || !(value instanceof Integer)) {
serviceRanking = 0;
} else {
serviceRanking = (Integer) value;
}
if (serviceRanking >= candidate) {
candidate = serviceRanking;
port = servicePort;
}
}
} catch (final InvalidSyntaxException ex) {
// This point of code should never be reached.
final Logger logger = LoggerFactory.getLogger(HttpServiceUtil.class);
logger.warn("This error should only be thrown if a filter could not be parsed. We don't use a filter...");
}
if (port > 0) {
return port;
}

// If the service does not provide the port, try to use the system property.
value = bc.getProperty(propertyName);
if (value != null) {
if (value instanceof String) {
try {
return Integer.parseInt(value.toString());
} catch (final NumberFormatException ex) {
// If the property could not be parsed, the HTTP servlet itself has to care and warn about.
}
} else if (value instanceof Integer) {
return (Integer) value;
}
}

return -1;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
* 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
*/
package org.eclipse.smarthome.core.net;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Some utility functions related to network interfaces etc.
*
* @author Markus Rathgeb - Initial contribution and API
*/
public class NetUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(NetUtil.class);

private NetUtil() {
}

/**
* Get the first candidate for a local IPv4 host address (non loopback, non localhost).
*/
public static String getLocalIpv4HostAddress() {
try {
String hostAddress = null;
final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
final NetworkInterface current = interfaces.nextElement();
if (!current.isUp() || current.isLoopback() || current.isVirtual()) {
continue;
}
final Enumeration<InetAddress> addresses = current.getInetAddresses();
while (addresses.hasMoreElements()) {
final InetAddress current_addr = addresses.nextElement();
if (current_addr.isLoopbackAddress() || (current_addr instanceof Inet6Address)) {
continue;
}
if (hostAddress != null) {
LOGGER.warn("Found multiple local interfaces - ignoring {}", current_addr.getHostAddress());
} else {
hostAddress = current_addr.getHostAddress();
}
}
}
return hostAddress;
} catch (SocketException ex) {
LOGGER.error("Could not retrieve network interface: " + ex.getMessage(), ex);
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Bundle-SymbolicName: org.eclipse.smarthome.io.rest.mdns
Bundle-Version: 0.9.0.qualifier
Bundle-Vendor: Eclipse.org/SmartHome
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.eclipse.smarthome.io.rest,
Import-Package: org.eclipse.smarthome.core.net,
org.eclipse.smarthome.io.rest,
org.eclipse.smarthome.io.transport.mdns,
org.osgi.framework,
org.slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Hashtable;
import java.util.Map;

import org.eclipse.smarthome.core.net.HttpServiceUtil;
import org.eclipse.smarthome.io.rest.RESTConstants;
import org.eclipse.smarthome.io.transport.mdns.MDNSService;
import org.eclipse.smarthome.io.transport.mdns.ServiceDescription;
Expand All @@ -20,6 +21,7 @@
* discover it.
*
* @author Kai Kreuzer - Initial contribution and API
* @author Markus Rathgeb - Use HTTP service utility functions
*/
public class MDNSAnnouncer {

Expand Down Expand Up @@ -47,13 +49,17 @@ public void activate(BundleContext bundleContext, Map<String, Object> properties
mdnsName = "smarthome";
}
try {
httpPort = Integer.parseInt(bundleContext.getProperty("org.osgi.service.http.port"));
mdnsService.registerService(getDefaultServiceDescription());
httpPort = HttpServiceUtil.getHttpServicePort(bundleContext);
if (httpPort != -1) {
mdnsService.registerService(getDefaultServiceDescription());
}
} catch (NumberFormatException e) {
}
try {
httpSSLPort = Integer.parseInt(bundleContext.getProperty("org.osgi.service.http.port.secure"));
mdnsService.registerService(getSSLServiceDescription());
httpSSLPort = HttpServiceUtil.getHttpServicePortSecure(bundleContext);
if (httpSSLPort != -1) {
mdnsService.registerService(getSSLServiceDescription());
}
} catch (NumberFormatException e) {
}
}
Expand Down

0 comments on commit f052a1a

Please sign in to comment.