I receive a ChannelClosedException when trying to connect to localhost service - kotlin

I have recently developed a small client server application for a customer. A windows executable adaptor provides a number of TCP sockets to interact with an external host, and my java(kotlin) client software is listening to those sockets and sends commands when necessary. Nothing fancy, and I tested the application thoroughly on my Windows10 developer system.
Now I tried to migrate the software to Ubuntu 22 as a host. The windows executable is running on wine emulation and I have checked with netstat that it listens to the expected ports, also I tested with telnet to access the primary port, and I can receive the feed. But when I try to access the ports from the java client, my code throws ChannelClosedException whenever my code tries to open the connection, and the retry logic (spring-retry) is repeating this 10 times before giving up:
Caused by: java.nio.channels.ClosedChannelException: null
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implConnect(UnixAsynchronousSocketChannelImpl.java:301) ~[na:na]
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.connect(AsynchronousSocketChannelImpl.java:200) ~[na:na]
Here some excerpt from the code I execute:
class RequestHandler(private val hostAddress: InetSocketAddress) :
Runnable{
private val client: AsynchronousSocketChannel = AsynchronousSocketChannel.open()
#Retryable(value=[ConnectException::class, ClosedChannelException::class], maxAttempts = 10)
fun init() {
connect()
executor.submit(this)
}
private fun connect() {
try {
client.connect(hostAddress).get()
client.setOption(StandardSocketOptions.TCP_NODELAY, true)
client.setOption(StandardSocketOptions.SO_KEEPALIVE, true)
} catch (e: RuntimeException) {
logger.error("Failed to connect to $hostAddress due to ${e.localizedMessage}")
}
}
}
Do you see anything here that requires special attention on a Linux host?

Related

Ratchet PHP server establishes connection, but Kotlin never receives acknowledgement

I have a ratchet server, that I try to access via Websocket. It is similar to the tutorial: logging when there is a new client or when it receives a message. The Ratchet server reports having successfully established a connection while the Kotlin client does not (the connection event in Kotlin is never fired). I am using the socket-io-java module v.2.0.1. The client shows a timeout after the specified timeout time, gets detached at the server and attaches again after a short while, just as it seems to think, the connection did not properly connect (because of a missing connection response?).
The successful connection confirmation gets reported to the client, if the client is a Websocket-Client in the JS-console of Chrome, but not to my Kotlin app. Even an Android emulator running on the same computer doesn´t get a response (So I think the problem is not wi-fi related).
The connection works fine with JS, completing the full handshake, but with an Android app it only reaches the server, but never the client again.
That´s my server code:
<?php
namespace agroSMS\Websockets;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class SocketConnection implements MessageComponentInterface
{
protected \SplObjectStorage $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
error_log("New client attached");
}
function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
error_log("Client detached");
}
function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
function onMessage(ConnectionInterface $from, $msg)
{
error_log("Received message: $msg");
// TODO: Implement onMessage() method.
}
}
And the script that I run in the terminal:
<?php
use Ratchet\Server\IoServer;
use agroSMS\Websockets\SocketConnection;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new SocketConnection()
)
)
);
$server->run();
What I run in the browser for tests (returns "Connection established" in Chrome, but for some reason not in the Browser "Brave"):
var conn = new WebSocket('ws://<my-ip>:80');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
What my Kotlin-code looks like:
try {
val uri = URI.create("ws://<my-ip>:80")
val options = IO.Options.builder()
.setTimeout(60000)
.setTransports(arrayOf(WebSocket.NAME))
.build()
socket = IO.socket(uri, options)
socket.connect()
.on(Socket.EVENT_CONNECT) {
Log.d(TAG, "[INFO] Connection established")
socket.send(jsonObject)
}
.once(Socket.EVENT_CONNECT_ERROR) {
val itString = gson.toJson(it)
Log.d(TAG, itString)
}
}catch(e : Exception) {
Log.e(TAG, e.toString())
}
After a minute the Kotlin code logs a "timeout"-error, detaches from the server, and attaches again.
When I stop the script on the server, it then gives an error: "connection reset, websocket error" (which makes sense, but why doesn´t he get the connection in the first time?)
I also tried to "just" change the protocol to "wss" in the url, in case it might be the problem, even though my server doesn´t even work with SSL, but this just gave me another error:
[{"cause":{"bytesTransferred":0,"detailMessage":"Read timed out","stackTrace":[],"suppressedExceptions":[]},"detailMessage":"websocket error","stackTrace":[],"suppressedExceptions":[]}]
And the connection isn´t even established at the server. So this try has been more like a down-grade.
I went to the github page of socket.io-java-client to find a solution to my problem there and it turned out, the whole problem was, that I misunderstood a very important concept:
That socket.io uses Websockets doesn´t mean it is compatible with Websockets.
So speaking in clear words:
If you use socket.io at client side, you also need to use it at the server side and vice versa. Since socket.io sends a lot of meta data with its packets, a pure Websocket-server will accept their connection establishment, but his acknowledgement coming back will not be accepted by the socket.io client.
You have to go for either full socket.io or full pure Websockets.

Refuse to connect with rabbitmq using docker toolbox

My friend has a problem with connection to rabbitmq via docker toolbox.
The whole team uses windows pro or edu, where we don't have any problems with docker. But one of my friend has windows home, so we needed to download docker toolbox. When we open rabbitmq management, it works well, but when we try to connect to rabbit, we get error message: "refuse to connect".
public void startRabbitMQ() {
ConnectionFactory factory = new ConnectionFactory();
setSpecificationFactory(factory);
try {
connection = factory.newConnection();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
try {
channel = Objects.requireNonNull(connection).createChannel();
} catch (IOException e) {
e.printStackTrace();
}
}
private void setSpecificationFactory(ConnectionFactory factory){
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
factory.setHost("localhost");
factory.setPort(5672);
}
We all use this code to connect, and, as I said, it works well. We think that it is a problem with the line:"factory.setHost([...])"
We all need only connect with localhost, but when we connect via docker toolbox we try many different options like:
localhost,
192.168.99.101,
127.0.0.1
With docker toolbox we need to use different IP, which is shared for us from kitematic, like on SS below, so we tried 192.168.99.101, but still it didn't work.
As I said, rabbitmq management works properly. We just used chrome and open "192.168.99.101:15672".
We tried
shut down antivirus and firewall
check, if port is used
virtualization is enabled
Docker toolbox kitematic

Paho Rabitmqq connection getting failed

Here is my paho client code
// Create a client instance
client = new Paho.MQTT.Client('127.0.0.1', 1883, "clientId");
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({onSuccess:onConnect});
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe("/World");
message = new Paho.MQTT.Message("Hello");
message.destinationName = "/World";
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
On Rabbitmq server everything is default seetings. When i run this code i get WebSocket connection to 'ws://127.0.0.1:1883/mqtt' failed: Connection closed before receiving a handshake response
What i am missing ?
From my personal experience with Paho MQTT JavaScript library and RabbitMQ broker on windows, here is a list of things that you need to do to be able to use MQTT from JS from within a browser:
Install rabbitmq_web_mqtt plugin (you may find latest binary here, copy it to "c:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.2\plugins\", and enable from command line using "rabbitmq-plugins enable rabbitmq_web_mqtt".
Of course, MQTT plugin also needs to be enabled on broker
For me, client was not working with version 3.6.1 of RabbitMQ, while it works fine with version 3.6.2 (Windows)
Port to be used for connections is 15675, NOT 1883!
Make sure to specify all 4 parameters when making instance of Paho.MQTT.Client. In case when you omit one, you get websocket connection error which may be quite misleading.
Finally, here is a code snippet which I tested and works perfectly (just makes connection):
client = new Paho.MQTT.Client("localhost", 15675, "/ws", "client-1");
//set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
//connect the client
client.connect({
onSuccess : onConnect
});
//called when the client connects
function onConnect() {
console.log("Connected");
}
//called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:" + responseObject.errorMessage);
}
}
//called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:" + message.payloadString);
}
It's not clear in the question but I assume you are running the code above in a web browser.
This will be making a MQTT connection over Websockets (as shown in the error). This is different from a native MQTT over TCP connection.
The default pure MQTT port if 1883, Websocket support is likely to be on a different port.
You will need to configure RabbitMQ to accept MQTT over Websockets as well as pure MQTT, this pull request for RabbitMQ seams to talk about adding this capability. It mentions that this capability was only added in version 3.6.x and that the documentaion is still outstanding (as of 9th Feb 2016)

Can't connect to a remote zookeeper from a Kafka producer

I've been playing with Apache Kafka for a few days, and here is my problem,
If I set up the local test described in the "quick start" section on the website, everything is fine, the kafka producer/ consumer, zookeeper server and kafka broker work perfectly.
Now if I run on a remote server (let's call it node2) :
- Zookeeper - port 2181
- Kafka Broker - port 9092
- kafka consumer
And then if I run from my local computer :
- kafka producer
Assuming that there is no firewall on node2.
The connection end up with a timeout.
Here is the error log :
/etc/java/jdk1.6.0_41/bin/java -Didea.launcher.port=7533 -Didea.launcher.bin.path=/home/kevin/Documents/idea-IU-123.169/bin -Dfile.encoding=UTF-8 -classpath /etc/java/jdk1.6.0_41/lib/dt.jar:/etc/java/jdk1.6.0_41/lib/tools.jar:/etc/java/jdk1.6.0_41/lib/jconsole.jar:/etc/java/jdk1.6.0_41/lib/htmlconverter.jar:/etc/java/jdk1.6.0_41/lib/sa-jdi.jar:/home/kevin/Desktop/kafka-0.7.2/examples/target/scala_2.8.0/classes:/home/kevin/Desktop/kafka-0.7.2/project/boot/scala-2.8.0/lib/scala-compiler.jar:/home/kevin/Desktop/kafka-0.7.2/project/boot/scala-2.8.0/lib/scala-library.jar:/home/kevin/Desktop/kafka-0.7.2/core/target/scala_2.8.0/classes:/home/kevin/Desktop/kafka-0.7.2/core/lib_managed/scala_2.8.0/compile/jopt-simple-3.2.jar:/home/kevin/Desktop/kafka-0.7.2/core/lib_managed/scala_2.8.0/compile/log4j-1.2.15.jar:/home/kevin/Desktop/kafka-0.7.2/core/lib_managed/scala_2.8.0/compile/zookeeper-3.3.4.jar:/home/kevin/Desktop/kafka-0.7.2/core/lib_managed/scala_2.8.0/compile/zkclient-0.1.jar:/home/kevin/Desktop/kafka-0.7.2/core/lib_managed/scala_2.8.0/compile/snappy-java-1.0.4.1.jar:/home/kevin/Desktop/kafka-0.7.2/examples/lib_managed/scala_2.8.0/compile/jopt-simple-3.2.jar:/home/kevin/Desktop/kafka-0.7.2/examples/lib_managed/scala_2.8.0/compile/log4j-1.2.15.jar:/home/kevin/Documents/idea-IU-123.169/lib/idea_rt.jar com.intellij.rt.execution.application.AppMain kafka.examples.KafkaConsumerProducerDemo
log4j:WARN No appenders could be found for logger (org.I0Itec.zkclient.ZkConnection).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "Thread-0" java.net.ConnectException: Connection timed out
at sun.nio.ch.Net.connect(Native Method)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:532)
at kafka.producer.SyncProducer.connect(SyncProducer.scala:173)
at kafka.producer.SyncProducer.getOrMakeConnection(SyncProducer.scala:196)
at kafka.producer.SyncProducer.send(SyncProducer.scala:92)
at kafka.producer.SyncProducer.send(SyncProducer.scala:125)
at kafka.producer.ProducerPool$$anonfun$send$1.apply$mcVI$sp(ProducerPool.scala:114)
at kafka.producer.ProducerPool$$anonfun$send$1.apply(ProducerPool.scala:100)
at kafka.producer.ProducerPool$$anonfun$send$1.apply(ProducerPool.scala:100)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:57)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:43)
at kafka.producer.ProducerPool.send(ProducerPool.scala:100)
at kafka.producer.Producer.zkSend(Producer.scala:137)
at kafka.producer.Producer.send(Producer.scala:99)
at kafka.javaapi.producer.Producer.send(Producer.scala:103)
at kafka.examples.Producer.run(Producer.java:53)
Process finished with exit code 0
And here is my Producer's code :
import java.util.Properties;
import kafka.javaapi.producer.ProducerData;
import kafka.producer.ProducerConfig;
public class Producer extends Thread{
private final kafka.javaapi.producer.Producer<String, String> producer;
private final String topic;
private final Properties props = new Properties();
public Producer(String topic)
{
props.put("zk.connect", "node2:2181");
props.put("connect.timeout.ms", "5000");
props.put("socket.timeout.ms", "30000");
props.put("serializer.class", "kafka.serializer.StringEncoder");
props.put("producer.type", "sync");
props.put("conpression.codec", "0");
producer = new kafka.javaapi.producer.Producer<String, String>(new ProducerConfig(props));
this.topic = topic;
}
public void run() {
String messageStr = new String("Message_test");
producer.send(new ProducerData<String, String>(topic, messageStr));
}
}
**So I also tested to switch
props.put("zk.connect", "node2:2181");
by
props.put("broker.list", "0:node2:9082");
And in that case I can connect successfully.**
See item #3 in http://kafka.apache.org/faq.html
The workaround is to explicitly set hostname property in server.properties of Kafka
You can verify this by using Zookeeper. If you are using kafka 0.7*, open ZkCli console and do get /brokers/ids/0 and you should get all the brokers metadata. Make sure the IP address/hostnames here matches the Zk connect string you are using in producer code -
props.put("zk.connect", "node2:2181");
In my case, I was using a producer running on my local machine connecting to a ubuntu VM (same box, different IP) and this workaround helped.

Connecting via named pipe from windows service (session#0) to desktop app (session #1)

Given:
- the application - desktop GUI (WPF) .NET app
- windows service watching for application (.NET also)
The windows service periodically "pings" application to get sure it's healthy (and if it's not winservice will restart it).
I was going to implement "pinging" via named pipes. To make things simpler I decided to do it with WCF. The application hosts a WCF-service (one operation Ping returning something). The windows service is a client for this WCF-service, invokes it periodically based on a timer.
That's all in Windows 7.
Windows service is running under LocalService (in session#0).
Desktop application is running under currently logged in user (in session#1).
The problem:
Windows service can't see WCF endpoint (with NetNamedPipeBinding) created in and being listened in desktop application. That means that on call via wcf proxy I get this exception: "The pipe endpoint 'net.pipe://localhost/HeartBeat' could not be found on your local machine"
I'm sure code is ok, because another desktop application (in session#1) can see the endpoint.
Obviously here I'm dealing with some security stuff for Win32 system object isolation.
But I believe there should be a way to workaround restrictions I've encountered with.
I can sacrifice WCF approach and go the raw NamedPipe way.
An easier solution might be to use a WCF duplex contract with the Windows service hosting the WCF service. The client App would call an operation on the service to register itself, when it starts up. The Ping would then be an operation invoked periodically by the service on the client's callback contract, to which the App would respond.
Service visibility works this way round, because the Windows service can run with SeCreateGlobalPrivilege, and so the shared memory object via which the pipe name is published by the service can be created in the Global kernel namespace, visible to other sessions. Interactive applications can't easily get that privilege in Windows7, so WCF services in such applications fall back to publishing the pipe in the Local kernel namespace, visible only within their own session.
Finally I've found a solution - using Named Pipes from System.IO.Pipes directly. It's seems that WCF's pipes support implementation doesn't use System.IO.Pipes.
Server:
using (var pipeServer = new NamedPipeServerStream("mypipe", PipeDirection.Out, 1))
{
try
{
while (true)
{
// #1 Connect:
try
{
pipeServer.WaitForConnection();
}
catch (ObjectDisposedException)
{
yield break;
}
if (ae.IsCanceled())
return;
// #2: Sending response:
var response = Encoding.ASCII.GetBytes(DateTime.Now.ToString());
try
{
pipeServer.Write(response, 0, response.Length);
}
catch (ObjectDisposedException)
{
return;
}
// #3: Disconnect:
pipeServer.Disconnect();
}
}
finally
{
if (pipeServer.IsConnected)
pipeServer.Disconnect();
}
}
Client:
using (var pipeClient = new NamedPipeClientStream(".", "mypipe", PipeDirection.In))
{
try
{
try
{
pipeClient.Connect(TIMEOUT);
}
catch(TimeoutException ex)
{
// nobody answers to us
continue;
}
using (var sr = new StreamReader(pipeClient))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
// got response
}
}
}
catch(Exception ex)
{
// pipe error
throw;
}
}