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

Commit

Permalink
Implemented Option to choose default network interface
Browse files Browse the repository at this point in the history
Fixes #3884
  • Loading branch information
triller-telekom committed Aug 1, 2017
1 parent 545a6c3 commit 617471b
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 2 deletions.
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.smarthome.config.core.net.NetworkConfigOptionProvider">
<service>
<provide interface="org.eclipse.smarthome.config.core.ConfigOptionProvider"/>
</service>
<implementation class="org.eclipse.smarthome.config.core.net.NetworkConfigOptionProvider"/>
</scr:component>
@@ -0,0 +1,81 @@
/**
* Copyright (c) 2014-2017 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.config.core.net;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;

import org.eclipse.smarthome.config.core.ConfigOptionProvider;
import org.eclipse.smarthome.config.core.ParameterOption;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Provides a list of IPv4 addresses of the local machine and shows the user which interface belongs to which IP address
*
* @author Stefan Triller - initial contribution
*
*/
@Component
public class NetworkConfigOptionProvider implements ConfigOptionProvider {

static final URI CONFIG_URI = URI.create("system:network");
static final String PARAM_DEFAULT_INTERFACE = "defaultInterface";

private final Logger logger = LoggerFactory.getLogger(NetworkConfigOptionProvider.class);

@Override
public Collection<ParameterOption> getParameterOptions(URI uri, String param, Locale locale) {
if (!uri.equals(CONFIG_URI)) {
return null;
}

if (param.equals(PARAM_DEFAULT_INTERFACE)) {
return getInterfaces();
}
return null;
}

private List<ParameterOption> getInterfaces() {
ArrayList<ParameterOption> interfaceOptions = new ArrayList<>();
try {
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;
}

String ipv4Address = current_addr.getHostAddress();
ParameterOption po = new ParameterOption(ipv4Address, ipv4Address + " (" + current.getName() + ")");
interfaceOptions.add(po);
}
}
return interfaceOptions;
} catch (SocketException ex) {
logger.error("Could not retrieve network interface: {}", ex.getMessage(), ex);
return null;
}
}

}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="http://eclipse.org/smarthome/schemas/config-description/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/config-description/v1.0.0
http://eclipse.org/smarthome/schemas/config-description-1.0.0.xsd">

<config-description uri="system:network">
<parameter name="defaultInterface" type="text">
<label>Default Interface</label>
<description><![CDATA[
<p>The default network interface to be used.</p>
]]>
</description>
</parameter>
</config-description>

</config-description:config-descriptions>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" modified="modified" name="org.eclipse.smarthome.network">
<property name="service.config.description.uri" value="system:network"/>
<property name="service.config.label" value="Network Settings"/>
<property name="service.config.category" value="system"/>
<service>
<provide interface="org.eclipse.smarthome.core.net.NetworkInterfaceService"/>
</service>
<implementation class="org.eclipse.smarthome.core.net.NetworkInterfaceServiceImpl"/>
</scr:component>
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2014-2017 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;

/**
* Service that provides information about local network interfaces
*
* @author Stefan Triller - initial contribution
*
*/
public interface NetworkInterfaceService {

/**
* Obtain the local IPv4 address
*
* @return IPv4 address as string
*/
String getLocalIpv4HostAddress();

}
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2014-2017 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.util.Dictionary;
import java.util.Map;

import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;

/**
* Service that provides the current configured IPv4 address of the system
*
* @author Stefan Triller - initial contribution
*
*/
@Component(name = "org.eclipse.smarthome.network", property = { "service.config.description.uri=system:network",
"service.config.label=Network Settings", "service.config.category=system" })
public class NetworkInterfaceServiceImpl implements NetworkInterfaceService {

private static final String DEFAULT_INTERFACE = "defaultInterface";

private String defaultInterface;

@SuppressWarnings("unchecked")
protected void activate(ComponentContext componentContext) {
Dictionary<String, Object> props = componentContext.getProperties();
modified((Map<String, Object>) props);
}

@Modified
public synchronized void modified(Map<String, Object> config) {
String defaultInterfaceConfig = (String) config.get(DEFAULT_INTERFACE);
if (defaultInterfaceConfig == null) {
// if none is specified we return the default one for backward compatibility
defaultInterface = NetUtil.getLocalIpv4HostAddress();
} else {
defaultInterface = (String) config.get(DEFAULT_INTERFACE);
}
}

@Override
public String getLocalIpv4HostAddress() {
return defaultInterface;
}

}
21 changes: 21 additions & 0 deletions docs/documentation/development/bindings/thing-handler.md
Expand Up @@ -180,6 +180,27 @@ Furthermore bindings can specify a localized description of the thing status by
rate_limit=Device is blocked by remote service for {0} minutes. Maximum limit of {1} configuration changes per {2} has been exceeded. For further info please refer to device vendor.
```

## Offering a callback URL

Some things might require a `callback` URL which should be bould to a certain network interface. A user can configure his default network interface via Paper UI under `Configuration -> System -> Network Settings`. To obtain this configured address the `ThingHandlerFactory` needs a `service reference` to the `NetworkInterfaceService` in its `OSGI-INF/MyHandlerFactory.xml`:

```
<reference bind="setNetworkInterfaceService" cardinality="1..1" interface="org.eclipse.smarthome.core.net.NetworkInterfaceService" name="NetworkInterfaceService" policy="static" unbind="unsetNetworkInterfaceService"/>
```

Inside `MyHandlerFactory.java` two methods are required:

```java
protected void setNetworkInterfaceService(NetworkInterfaceService networkInterfaceService) {
this.networkInterfaceService = networkInterfaceService;
}
protected void unsetNetworkInterfaceService(NetworkInterfaceService networkInterfaceService) {
this.networkInterfaceService = null;
}
```

Now the `MyHandlerFactory` can obtain the configured IP address via `networkInterfaceService.getLocalIpv4HostAddress()`. This IP address can be used in callback URL offered to a device.

## Channel Links

Some bindings might want to start specific functionality for a channel only if an item is linked to the channel. The `ThingHandler` has two callback methods `channelLinked(ChannelUID channelUID)` and `channelUnlinked(ChannelUID channelUID)`, which are called for every link that is added or removed to/from a channel. So please be aware of the fact that both methods can be called multiple times.
Expand Down
Expand Up @@ -18,4 +18,5 @@
<provide interface="org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory"/>
</service>
<reference bind="setAudioHTTPServer" cardinality="1..1" interface="org.eclipse.smarthome.core.audio.AudioHTTPServer" name="AudioHTTPServer" policy="static" unbind="unsetAudioHTTPServer"/>
<reference bind="setNetworkInterfaceService" cardinality="1..1" interface="org.eclipse.smarthome.core.net.NetworkInterfaceService" name="NetworkInterfaceService" policy="static" unbind="unsetNetworkInterfaceService"/>
</scr:component>
Expand Up @@ -21,7 +21,7 @@
import org.eclipse.smarthome.core.audio.AudioHTTPServer;
import org.eclipse.smarthome.core.audio.AudioSink;
import org.eclipse.smarthome.core.net.HttpServiceUtil;
import org.eclipse.smarthome.core.net.NetUtil;
import org.eclipse.smarthome.core.net.NetworkInterfaceService;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.ThingUID;
Expand All @@ -46,6 +46,7 @@ public class SonosHandlerFactory extends BaseThingHandlerFactory {
private UpnpIOService upnpIOService;
private DiscoveryServiceRegistry discoveryServiceRegistry;
private AudioHTTPServer audioHTTPServer;
private NetworkInterfaceService networkInterfaceService;

private Map<String, ServiceRegistration<AudioSink>> audioSinkRegistrations = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -110,7 +111,7 @@ private String createCallbackUrl() {
if (callbackUrl != null) {
return callbackUrl;
} else {
final String ipAddress = NetUtil.getLocalIpv4HostAddress();
final String ipAddress = networkInterfaceService.getLocalIpv4HostAddress();
if (ipAddress == null) {
logger.warn("No network interface could be found.");
return null;
Expand Down Expand Up @@ -171,4 +172,12 @@ protected void unsetAudioHTTPServer(AudioHTTPServer audioHTTPServer) {
this.audioHTTPServer = null;
}

protected void setNetworkInterfaceService(NetworkInterfaceService networkInterfaceService) {
this.networkInterfaceService = networkInterfaceService;
}

protected void unsetNetworkInterfaceService(NetworkInterfaceService networkInterfaceService) {
this.networkInterfaceService = null;
}

}

0 comments on commit 617471b

Please sign in to comment.