Eventmachine HTTP - How to get notified if connection is lost? - eventmachine

I have this EM http code:
require 'eventmachine'
require 'em-http'
require 'json'
http = EM::HttpRequest.new("api_url", :keepalive => true, :connect_timeout => 0, :inactivity_timeout => 0)
EventMachine.run do
s = http.get({'accept' => 'application/json'})
s.stream do |data|
puts data
end
s.errback do
puts "FATAL EM STOPPED: #{response.error}"
EM.stop
end
end
I want to get notified if the connection is lost. I just tried to disable my WIFI and nothing is triggered. After I enable my WIFI the connection is established again and the messages are printed again. I want this behavior I just want to catch that the connection is lost, so that I can raise a error message.

Related

How to return error response to calling channel when TCP destination gives 'Connection refused'

I have this pattern:
channel ESANTE_MPI_CREATE_PATIENT_LISTENER (with a MLLP listener) calls channel ESANTE_MPI_CREATE_PATIENT that calls a TCP destination.
If connection cannot be done in the TCP destination inside ESANTE_MPI_CREATE_PATIENT then this channel reports an error for this destination:(ERROR: ConnectException: Connection refused (Connection refused))
The response transformer does not seem to be called (which is normal as there is no response).
I wonder how I can report the error back to the calling channel ESANTE_MPI_CREATE_PATIENT_LISTENER ?
PS: When tcp destination responds, then I use the response transformer to parse the received frame and create a response message (json error/ok) for the calling channel. Everything works fine here.
My question ends up with: How to trap a Connection refused in a TCP destination to create a response message.
I finally managed this by using the postprocessor script in ESANTE_MPI_CREATE_PATIENT to get the response of the connector and then force a message.
// fake error message prepared for connection refused.
// we put this as the response of the channel destination in order to force a understandable error message.
const sErrorMsg = {
status: "error",
error: "connection refused to eSanté MPI"
};
const TCP_CONNECTOR_ESANTE_MPI_RANK = 2; // WARNING: be sure to take the correct connector ID as displayed into destination.
const TCP_CONNECTOR_ESANTE_MPI_DNAME = 'd' + TCP_CONNECTOR_ESANTE_MPI_RANK; // WARNING: be sure to take the correct connector ID as displayed into destination.
/*
var cms = message.getConnectorMessages(); // returns message but as Immutable
responses. not what we want: we use responseMap instead.
var key = TCP_CONNECTOR_ESANTE_MPI_RANK;
logger.debug(" Response Data=" + cms.get(key).getResponseData());
logger.debug(" Response Data0=" + cms.get(key).getResponseError());
logger.debug(" Response Data1=" + cms.get(key).getResponseData().getError());
logger.debug(" Response Data2=" + cms.get(key).getResponseData().getMessage());
logger.debug(" Response Data3=" + cms.get(key).getResponseData().getStatusMessage());
logger.debug(" Response Data4=" + cms.get(key).getResponseData().getStatus());
*/
var responseMPI = responseMap.get(TCP_CONNECTOR_ESANTE_MPI_DNAME); // return a mutable reponse :-)
if (responseMPI.getStatus()=='ERROR' &&
responseMPI.getStatusMessage().startsWith('ConnectException: Connection refused')) {
// build a error message for this dedicated case
logger.error("connection refused detected");
responseMPI.setMessage(JSON.stringify(sErrorMsg)); // force the message to be responsed.
}
return;

Asyncio - RELIABLY Always Close Straggling TCP Connections

I have a program which connects to a bunch of hosts and checks if they are "socket reflectors". Basically, it is scanning a bunch of ips and doing this:
Connect, check - if there is data, is that data the same as what I am sending? Yes, return true, no return false. No data, return false.
For some reason, asyncio is not reliably closing TCP connections after they time out. I attribute this to the fact that a lot of these hosts I am connecting to are god knows what, and maybe just buggy servers. Be that as it may, there must be a way to make this force timeout? When I run this, it hangs after a while. Out of 12,978 hosts, about 12,768 of them complete. Then I end up with a bunch of open ESTABLISHED connections! Why does this happen?
I need it close the connection if nothing happens during the given timeout period.
async def tcp_echo_client(message, host_port, loop, connection_timeout=10):
"""
Asyncio TCP echo client
:param message: data to send
:param host_port: host and port to connect to
:param loop: asyncio loop
"""
host_port_ = host_port.split(':')
try:
host = host_port_[0]
port = host_port_[1]
except IndexError:
pass
else:
fut = asyncio.open_connection(host, port, loop=loop)
try:
reader, writer = await asyncio.wait_for(fut, timeout=connection_timeout)
except asyncio.TimeoutError:
print('[t] Connection Timeout')
return 1
except Exception:
return 1
else:
if args.verbosity >= 1:
print('[~] Send: %r' % message)
writer.write(message.encode())
writer.drain()
data = await reader.read(1024)
await asyncio.sleep(1)
if data:
if args.verbosity >= 1:
print(f'[~] Host: {host} Received: %r' % data.decode())
if data.decode() == message:
honeypots.append(host_port)
writer.close()
return 0
else:
filtered_list.append(host_port)
print(f'[~] Received: {data.decode()}')
writer.close()
return 1
else:
filtered_list.append(host_port)
writer.close()
if args.verbosity > 1:
print(f'[~] No data received for {host}')
return 1
What am I doing wrong?

How can I check the connection of Mongoid

Does Mongoid has any method like ActiveRecord::Base.connected??
I want to check if the connection that's accessible.
We wanted to implement a health check for our running Mongoid client that tells us whether the established connection is still alive. This is what we came up with:
Mongoid.default_client.database_names.present?
Basically it takes your current client and tries to query the databases on its connected server. If this server is down, you will run into a timeout, which you can catch.
My solution:
def check_mongoid_connection
mongoid_config = File.read("#{Rails.root}/config/mongoid.yml")
config = YAML.load(mongoid_config)[Rails.env].symbolize_keys
host, db_name, user_name, password = config[:host], config[:database], config[:username], config[:password]
port = config[:port] || Mongo::Connection::DEFAULT_PORT
db_connection = Mongo::Connection.new(host, port).db(db_name)
db_connection.authenticate(user_name, password) unless (user_name.nil? || password.nil?)
db_connection.collection_names
return { status: :ok }
rescue Exception => e
return { status: :error, data: { message: e.to_s } }
end
snrlx's answer is great.
I use following in my puma config file, FYI:
before_fork do
begin
# load configuration
Mongoid.load!(File.expand_path('../../mongoid.yml', __dir__), :development)
fail('Default client db check failed, is db connective?') unless Mongoid.default_client.database_names.present?
rescue => exception
# raise runtime error
fail("connect to database failed: #{exception.message}")
end
end
One thing to remind is the default server_selection_timeout is 30 seconds, which is too long for db status check at least in development, you can modify this in your mongoid.yml.

how to check if connection is established when use libev with non-block socket

I have some code use libev on how to deal with connection timeout as below (please refer to http://lists.schmorp.de/pipermail/libev/2011q2/001365.html):
sd = create_socket()
set_socket_nonblock(sd)
connect("127.0.0.1", port) // connect to an invalid port
ev_io_init(&w_io, connect_cb, sd, EV_WRITE)
ev_io_start(...)
ev_timer_init(&w_timer, timeout_cb, 5.0, 0)
ev_timer_start(...)
and in someplace perform ev_run. The connect_cb is called and in this callback function I checked the revents with EV_ERROR, the result is no error. This is strange because I provide an invalid port number which is not listening in local machine. Anyway, I try to send a message in the connect_cb function, got an error 111, which means that connection refused. I'm confused! How to check if the connection is established correctly when use non-block socket?
getsockopt is possible way to get if the connection has some error happen:
int err;
socklen_t len = sizeof(err);
getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len);
if (err) {
// error happen
} else {
connection is OK
}

fulljid is empty after connection to BOSH service with XMPHP

I am trying to pre-bind an XMPP session via XMPHP and pass the rid/sid/jid to a strophe client to attach to the session.
connection code here:
$conn = new CIRCUIT_BOSH('server.com', 7070, $username, $pass, $resource, 'server.com', $printlog=true, $loglevel=XMPPHP_Log::LEVEL_VERBOSE);
$conn->autoSubscribe();
try{
$conn->connect('http://xmpp.server.com/http-bind', 1, true);
$log->lwrite('Connected!');
}catch(XMPPHP_Exception $e){
die($e->getMessage());
}
I am getting the rid and sid but the fulljid in the $conn object stays empty and I cant see a session started on my openfire admin console.
If I create the jid manually by using the given resource and passing jid/rid/sid to strophe to use in attach, I get the ATTACHED status and I see calls from the client to the BOSH ip but I still dont see a session and I cant use the connection.
Strophe Client Code:
Called on document ready:
var sid = $.cookie('sid');
var rid = $.cookie('rid');
var jid = $.cookie('jid');
$(document).trigger('attach', {
sid: sid,
rid: rid,
jid: jid,
});
$(document).bind('attach', function (ev, data) {
var conn = new Strophe.Connection(
"http://xmpp.server.com/http-bind");
conn.attach(data.jid, data.sid, data.rid, function (status) {
if (status === Strophe.Status.CONNECTED) {
$(document).trigger('connected');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
} else if (status === Strophe.Status.ATTACHED){
$(document).trigger('attached');
}
});
Object.connection = conn;
});
I think the problem starts on the XMPPHP side which is not creating the session properly.
'attached' is triggered but never 'connected', is status 'connected' supposed to be sent?
What am I missing?
Ok, solved, I saw that XMPPHP lib didn't create a session at all on the openfire server, so I wrote a simple test for the XMPP class which was good and created the session, and for the XMPP_BOSH class that didn't manage create one. Then I saw the issue report here: http://code.google.com/p/xmpphp/issues/detail?id=47 comment no.9 worked, it fixed the issue by copying the processUntil() function from the XMLStream.php to BOSH.php, still can't figure out why this is working. Then I found I had an overlapping bug also with some of the passwords set for users on the openfire server. These passwords contained these ! # % ^ characters, for some reason the XMPP_BOSH is sending the password corrupted or changed so I got Auth Failed exception. Changing the password fixed the issue and I can now attach to the session XMPPHP created with the Strophe.js library.