Setting timeout on a socket using arduino-esp32 framework - arduino-esp8266

I'm trying to set a connection timeout on a secure wifi connection on arduino-esp32 framework. My code is:
const uint32_t RESPONSE_TIMEOUT = 30;
WiFiClientSecure client;
client.setTimeout(RESPONSE_TIMEOUT);
if (!client.connect(currentHost.c_str(), port)) {
ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str());
display(3, " E", "connection lost");
goto failure;
}
This openes the wifi connection successful, but it logs this error:
[E][WiFiClient.cpp:236] setSocketOption(): 1006 : 9
0x1006 is defined as
SO_RCVTIMEO 0x1006 /* receive timeout */
and error 9 is defined as
EBADF 9 /* Bad file number */
I am stuck here. What means bad file number here, and why is it not possible to set the socket stream timeout this way? Can anyone help me?

You can't have setTimeOut before the client.connect. You must establish the connection first.

Related

Get system error 115(operation in progress) on blocked socket connect()

In general, system error 115 occurs on a non blocking socket connect(), and the connection needs to be further checked through the select() interface.
But I didn't use fcntl() to set socket to O_NONBLOCK, just set a send timeout as shown below:
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
So, In my scenario, is the cause of the 115 error in connect() the same as that of a non block socket? And how do I know how long the connect interface is blocked when I get a 115 error?
Code example:
socklen_t len = sizeof(timeout);
ret = setsockopt(real_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
if (-1 == ret)
{
LOG(" error setsockopt");
return SOCKET_FAIL;
}
ret = connect(fd, (struct sockaddr *) &dest, sizeof(dest));
if (0 != ret)
{
LOG("error connect = %s", strerror(errno));
return ret;
}
Result:
Sometimes get system error "Operation now in progress".
The error number is 115, which is also defined as EINPROGRESS.
Thank you for your ideas. I found the answer in the man socket(7). EINPROGRESS errors can also occur in blocked sockets.
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an
error. The argument is a struct timeval. If an input or output
function blocks for this period of time, and data has been sent
or received, the return value of that function will be the
amount of data transferred; if no data has been transferred and
the timeout has been reached, then -1 is returned with errno set
to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just
as if the socket was specified to be nonblocking. If the time‐
out is set to zero (the default), then the operation will never
timeout. Timeouts only have effect for system calls that per‐
form socket I/O (e.g., read(2), recvmsg(2), send(2),
sendmsg(2)); timeouts have no effect for select(2), poll(2),
epoll_wait(2), and so on.

using TCP Keep-Alives in server to get rid of idle client

I have a server to collect Tcp data from different clients to a certain port. I have a scenario that whenever the client creates tcp connection and remain idle for more than let's say 30 min then I need to close the connection.
I have learned about TCP keep alive to track that the peer is dead or not and Mostly I found examples used in client side. Similarly can I used in the server side to poll the connection whether it is active or not?
Further In linux sysctl.conf , there is a configuration file to edit the values. This seems that the whole tcp connection is destroyed after certain inactivity. I am in need such that certain connection form the device are destroyed after certain time inactivity but not the whole tcp port connection closed.
I am using ubuntu to create the server to collect tcp connection. Can I use TCP Keep-Alives in server code to find the inactive client and close the particular client? or is there any other way in server side to implement such feature?
and while going through the web it is mentioned that
(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)
this getsockopt is for the main tcp connection and setting here seems the setting is for whole connection to the server.
However what I need is for the specific client. I have the event server code as
here client_fd is accepted and now I need to close this client_fd if next data through this client is not received within certain time.
void event_server(EV_P_ struct ev_io *w, int revents) {
int flags;
struct sockaddr_in6 addr;
socklen_t len = sizeof(addr);
int client_fd;
// since ev_io is the first member,
// watcher `w` has the address of the
// start of the _sock_ev_serv struct
struct _sock_ev_serv* server = (struct _sock_ev_serv*) w;
server->socket_len = len;
for (;;) {
if ((client_fd = accept(server->fd, (struct sockaddr*) &addr, &len)) < 0) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
zlog_info(_c, "Error accepting connection from client \n");
//perror("accept");
}
break;
}
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr.sin6_addr, ip, INET6_ADDRSTRLEN);
char *dev_ip = get_ip(ip);
server->device_ip = dev_ip;
zlog_debug(_c,"The obtained ip is %s and dev_ip is %s", ip, dev_ip);
/** check for the cidr address for config_ip **/
char *config_ip;
config_ip = get_config_ip(dev_ip, _client_map);
zlog_debug(_c,"The _config ip for dev_ip:%s is :%s", dev_ip, config_ip);
if (config_ip == NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
json_t *dev_config;
dev_config = get_json_object_from_json(_client_map, config_ip);
if (dev_config==NULL) {
zlog_debug(_c,"Connection attempted from unreigistered IP: %s", dev_ip);
zlog_info(_c, "Connection attempted from unregistered IP : %s", dev_ip);
AFREE(server->device_ip);
continue;
}
if ((flags = fcntl(client_fd, F_GETFL, 0)) < 0 || fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
zlog_error(_c, "fcntl(2)");
}
struct _sock_ev_client* client = malloc(sizeof(struct _sock_ev_client));
client->device_ip = dev_ip;
client->server = server;
client->fd = client_fd;
// ev_io *watcher = (ev_io*)calloc(1, sizeof(ev_io));
ev_io_init(&client->io, event_client, client_fd, EV_READ);
ev_io_start(EV_DEFAULT, &client->io);
}
}
TCP keep alives are not to detect idle clients but to detect dead connections, i.e. if a client crashed without closing the connection or if the line is dead etc. But if the client is only idle but not dead the connection is still open. Any attempts to send an empty packet (which keep-alive packets are) to the client will result in an ACK from the client and thus keep alive will not report a dead connection.
To detect idle clients instead use either timeouts for read (SO_RCVTIMEO) or use a timeout with select, poll or similar functions.
I have implemented below mechanism to detect idle status on Socket IO activity.
My Socket is wrapped in some class like UserConnection. This class has one more attribute lastActivtyTime. Whenever I get a read on write on this Socket, I will update this attribute.
I have one more background Reaper thread, which will iterate through all UserConnection objects and check for lastActivtyTime. If current time - lastActivtyTime is greater than configured threshold parameter like 15 seconds, I will close the idle connection.
In your case, when you are iterating through all UserConnections, you can check client_id and your threshold of 30 minutes inactivity to close idle connection.

Node.js connectListener still called on socket error

I'm having a weird issue with a TCP client - I use socket.connect() to connect to the server instance. However, since the server is not running, I receive an error of ECONNREFUSED (so far so good).
I handle it using on('error') and set a timeout to try and reconnect in 10 seconds. This should continue to fail as long as the server is down. which is the case.
However, as soon as the server is running, it looks like all of the previous sockets are still active, so now I have several client sockets connected to the server.
I tried to call the destroy at the beginning of the on('error') handler function.
Any ideas how to deal with that?
Thanks!
EDIT: Code snippet:
var mySocket;
var self = this;
...
var onError = function (error) {
mySocket.destroy(); // this does not change anything...
console.log(error);
// Wait 10 seconds and try to reconnect
setTimeout(function () {
console.log("reconnecting...");
self.once('InitDone', function () {
// do something
console.log("init is done")
});
self.init();
}, 10000);
}
Inside init function:
...
console.log("trying to connect");
mySocket = tls.connect(options, function () {
console.log("connected!");
self.emit('InitDone');
});
mySocket.setEncoding('utf8');
mySocket.on('error', onError);
...
The result of this is something like the following:
trying to connect
ECONNREFUSED
reconnecting...
trying to connect
ECONNREFUSED
reconnecting...
trying to connect
ECONNREFUSED
reconnecting...
--> Starting the server here
trying to connect
connected
init is done
connected
init is done
connected
init is done
connected
init is done
However I would expect only one connection since the previous sockets failed to connect. Hope this clarifies the question.
Thanks!

Node socket.io server crash when starts

I have a socket.io server and a client runing correctly. Each time that the server is down, the client try to connect again each 5 seconds. When the server is up again they connect without problems.
But the problem comes when I wait long time before up the server again, when the server is up, it crashes showing :
info - socket.io started
debug - client authorized
info - handshake authorized DqN4t2YVP7NiqQi8zer9
debug - setting request GET /socket.io/1/websocket/DqN4t2YVP7NiqQi8zer9
debug - set heartbeat interval for client DqN4t2YVP7NiqQi8zer9
debug - client authorized for
debug - websocket writing 1::
buffer.js:287
pool = new SlowBuffer(Buffer.poolSize);
^
RangeError: Maximum call stack size exceeded
Client reconnection (Executed each 5 seconds while is not connected):
function socket_connect() {
if (!socket) {
socket = io.connect('http://192.168.1.25:8088', { 'reconnect':false, 'connect timeout': 5000 });
} else {
socket.socket.connect();
}
socket.on("connect", function () {
clearInterval(connect_interval);
connect_interval = 0;
socket.emit('player', { refresh_data:true });
});
}
On server side, only with the socket instance, it crashes:
var io = require('socket.io').listen(8088);
I think that the problem is:
When the server goes up, it recive all the connections emited by the client each 5 seconds, (15 hours disconnected * 60 m * 60 s / 5 seconds reconnection) and it crashes.
What can i do to close the connections that the server try to do?
PS:If i reload the client, and after up the server, it works
The main idea for socket.io.js is to reuse an existing connection.
You should only connect it once and then exchange messages by using socket.emit()
I am not sure why you are creating a new connection between your client and server for every 5 seconds. There is a limit on the number of connections the server can create, but that should be more than enough. If you put it in a loop then eventually the server will run out of sockets.
io.connect has to be executed once on the client, then may be you can socket.emit() every 5 seconds. Remove the { 'reconnect':false, 'connect timeout': 5000 } and you will be fine.
I founded the problem...
Each time that the function socket_connect() is called, a "socket.on("connect" ..." function is created. So when the server turns up, a new connection is created, but the event "socket.on("connect" is fired multiple times...
The solution was:
function socket_connect() {
if (!socket) {
socket = io.connect('http://192.168.1.25:8088', { 'reconnect':false, 'connect timeout': 5000 });
} else {
socket.socket.connect();
}
}
socket.on("connect", function () {
clearInterval(connect_interval);
connect_interval = 0;
socket.emit('player', { refresh_data:true });
});

How do you kill a redis client when there is no connection?

I have a valid server configuration in which redis can't be accessed, but the server can function correctly (I simply strip away features when redis can't be found).
However, I can't manage the connection errors well. I'd like to know when a connection error fails and shutdown the client in that case.
I've found that the connection retry will never stop. And quit() is actually swallowed - "Queueing quit for next server connection." - when called.
Is there a way to kill the client in the case where no connection can be established?
var redis = require("redis"),
client = redis.createClient();
client.on("error", function(err) {
logme.error("Bonk. The worker framework cannot connect to redis, which might be ok on a dev server!");
logme.error("Resque error : "+err);
client.quit();
});
client.on("idle", function(err) {
logme.error("Redis queue is idle. Shutting down...");
});
client.on("end", function(err) {
logme.error("Redis is shutting down. This might be ok if you chose not to run it in your dev environment");
});
client.on("ready", function(err) {
logme.info("Redis up! Now connecting the worker queue client...");
});
ERROR - Resque error : Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED
ERROR - Redis is shutting down. This might be ok if you chose not to run it in your dev environment
ERROR - Resque error : Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED
ERROR - Resque error : Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED
ERROR - Resque error : Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED
ERROR - Resque error : Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED
One thing that is interesting is the fact that the 'end' event gets emitted. Why?
For v3.1.2 of the library
The right way to have control on the client's reconnect behaviour is to use a retry_strategy.
Upon disconnection the redisClient will try to reconnect as per the default behaviour. The default behaviour can be overridden by providing a retry_strategy while creating the client.
Example usage of some fine grained control from the documentation.
var client = redis.createClient({
retry_strategy: function (options) {
if (options.error && options.error.code === 'ECONNREFUSED') {
// End reconnecting on a specific error and flush all commands with
// a individual error
return new Error('The server refused the connection');
}
if (options.total_retry_time > 1000 * 60 * 60) {
// End reconnecting after a specific timeout and flush all commands
// with a individual error
return new Error('Retry time exhausted');
}
if (options.attempt > 10) {
// End reconnecting with built in error
return undefined;
}
// reconnect after
return Math.min(options.attempt * 100, 3000);
}
});
Ref: https://www.npmjs.com/package/redis/v/3.1.2
For the purpose of killing the client when the connection is lost, we could use the following retry_strategy.
var client = redis.createClient({
retry_strategy: function (options) {
return undefined;
}
});
Update June 2022 (Redis v4.1.0)
The original answer was for an earlier version of Redis client. Since v4 things have changed in the client configuration. Specifically, the retry_strategy is now called reconnectStrategy and is nested under the socket configuration option for createClient.
You might want to just forcibly end the connection to redis on error with client.end() rather than using client.quit() which waits for the completion of all outstanding requests and then sends the QUIT command which as you know requires a working connection with redis to complete.

Resources