Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement TCPServerCommProvider 2 #245

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.api.comm;

import org.sensorhub.api.module.IModule;
import org.sensorhub.impl.comm.ConnectionEventArgs;

import java.util.function.Consumer;

/**
* Interface for all server communication providers giving access to input and output streams
* via a connection event handler.
*
* @param <ConfigType> Comm module config type
* @author Michael Elmore
* @since November 2023
*/
public interface IServerCommProvider<ConfigType extends CommProviderConfig<?>> extends IModule<ConfigType> {
/**
* Adds a connection event handler to this comm provider.
* The handler will be called when a connection is established.
* Only one handler can be registered at a time.
* Calling this method again will replace the previous handler.
*
* @param eventHandler The event handler to add
*/
void onConnection(Consumer<ConnectionEventArgs> eventHandler);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.comm;

import java.io.InputStream;
import java.io.OutputStream;

/**
* Event arguments for a connection event
*
* @author Michael Elmore
* @since September 2023
*/
public class ConnectionEventArgs {
private final InputStream inputStream;
private final OutputStream outputStream;

/**
* @param inputStream The input stream for the connection
* @param outputStream The output stream for the connection
*/
public ConnectionEventArgs(InputStream inputStream, OutputStream outputStream) {
this.inputStream = inputStream;
this.outputStream = outputStream;
}

/**
* @return The input stream for the connection
*/
public InputStream getInputStream() {
return inputStream;
}

/**
* @return The output stream for the connection
*/
public OutputStream getOutputStream() {
return outputStream;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.comm;

import org.sensorhub.api.module.IModule;
import org.sensorhub.api.module.IModuleProvider;
import org.sensorhub.api.module.ModuleConfig;
import org.sensorhub.impl.module.JarModuleProvider;

/**
* Communication provider for TCP/IP server connections.
*
* @author Michael Elmore
* @since September 2023
*/
public class TCPServerCommModuleDescriptor extends JarModuleProvider implements IModuleProvider {
@Override
public String getModuleName() {
return "TCP Server Comm Driver";
}

@Override
public String getModuleDescription() {
return "Simple TCP/IP server communication provider using JDK TCP stack. Allows multiple client sensors to connect.";
}

@Override
public Class<? extends IModule<?>> getModuleClass() {
return TCPServerCommProvider.class;
}

@Override
public Class<? extends ModuleConfig> getModuleConfigClass() {
return TCPServerCommProviderConfig.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.comm;

import org.sensorhub.api.comm.IServerCommProvider;
import org.sensorhub.api.common.SensorHubException;
import org.sensorhub.impl.module.AbstractModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;

/**
* Communication provider for TCP/IP server connections.
*
* @author Michael Elmore
* @since September 2023
*/
public class TCPServerCommProvider extends AbstractModule<TCPServerCommProviderConfig> implements IServerCommProvider<TCPServerCommProviderConfig> {
static final Logger log = LoggerFactory.getLogger(TCPServerCommProvider.class.getSimpleName());
private final Set<Consumer<ConnectionEventArgs>> eventHandlers = new HashSet<>();

ServerSocket serverSocket;
Thread serverThread;

@Override
protected void doStart() throws SensorHubException {
var config = this.config.protocol;

//Start a thread to listen on the configured port
serverThread = new Thread(() -> {
try {
if (config.enableTLS) {
var sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
try (var sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(config.localPort)) {
while (true) {
var socket = sslServerSocket.accept();
broadcast(socket.getInputStream(), socket.getOutputStream());
}
}
} else {
serverSocket = new ServerSocket(config.localPort);
while (true) {
var socket = serverSocket.accept();
broadcast(socket.getInputStream(), socket.getOutputStream());
}
}
} catch (Exception e) {
log.error(String.format("TCPServerCommProvider error: %s", e.getMessage()), e);
}
});
serverThread.start();
}

@Override
protected void doStop() throws SensorHubException {
try {
if (serverSocket != null) {
serverSocket.close();
}
if (serverThread != null) {
serverThread.interrupt();
}
} catch (IOException e) {
throw new SensorHubException("Error stopping TCPServerCommProvider: " + e.getMessage(), e);
}
}

/**
* Register code to be called when a connection is established.
* <p>
* Usage: commProvider.onConnection(args -> { ... })
* <p>
* Or: commProvider.onConnection(this::handleConnection)
*
* @param eventHandler code to be called when a connection is established
*/
@Override
public void onConnection(Consumer<ConnectionEventArgs> eventHandler) {
eventHandlers.add(eventHandler);
}

/**
* Broadcast a connection to all registered event handlers.
*
* @param input input stream
* @param output output stream
*/
private void broadcast(InputStream input, OutputStream output) {
var args = new ConnectionEventArgs(input, output);
eventHandlers.forEach(eventHandler -> eventHandler.accept(args));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.comm;

import org.sensorhub.api.comm.CommProviderConfig;
import org.sensorhub.api.config.DisplayInfo;

/**
* Configuration class for TCP/IP server connections
*
* @author Michael Elmore
* @since September 2023
*/
public class TCPServerCommProviderConfig extends CommProviderConfig<TCPServerConfig> {
@DisplayInfo(label = "Connection Options")
public RobustIPConnectionConfig connection = new RobustIPConnectionConfig();

public TCPServerCommProviderConfig() {
this.moduleClass = TCPCommProvider.class.getCanonicalName();
this.protocol = new TCPServerConfig();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/***************************** BEGIN LICENSE BLOCK ***************************
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.

Copyright (C) 2023 Botts Innovative Research Inc. All Rights Reserved.
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.impl.comm;

import org.sensorhub.api.comm.ICommConfig;
import org.sensorhub.api.config.DisplayInfo;
import org.sensorhub.api.config.DisplayInfo.FieldType;
import org.sensorhub.api.config.DisplayInfo.FieldType.Type;
import org.sensorhub.api.config.DisplayInfo.Required;
import org.sensorhub.api.config.DisplayInfo.ValueRange;


/**
* Driver configuration options for the TCP/IP server network protocol
*
* @author Michael Elmore
* @since September 2023
*/
public class TCPServerConfig implements ICommConfig {
@DisplayInfo(desc = "Port number to listen on")
@ValueRange(max = 65535)
@Required
public int localPort;

@DisplayInfo(label = "User Name", desc = "Remote user name")
public String user;

@DisplayInfo(label = "Password", desc = "Remote password")
@FieldType(Type.PASSWORD)
public String password;

@DisplayInfo(desc = "Secure communications with SSL/TLS")
public boolean enableTLS;
}
Loading