Closing socket in client crashes nodejs server - c

On C client I do:
socket()
connect() on port 6969
send()
//I have seen that I didn't call recv so nodejs try me to send data but My program was gone
and finally closesocket()
On nodejs server I receive the message so the connection is established:
const port = 6969;
var net = require('net');
var server = net.createServer(function(connection) {
console.log('client connected');
connection.on('close', function() {
console.log('conn closed');
});
connection.on('end', function() {
console.log('conn ended');// that is not called
});
connection.on("error", function(err) {
console.log("Caught flash policy server socket error: ");
console.log(err.stack);
});
connection.on('data', function(data) {
data = data.toString();
console.log('client sended the folowing string:' + data);
connection.write("Response");
console.log('Sended response to client');
});
});
server.listen(port, function() {
console.log('server is listening');
});
This is the result of my terminal:
server is listening
client connected
client sended the folowing string:err404
Sended response to client
Caught flash policy server socket error:
Error: read ECONNRESET
at exports._errnoException (util.js:1018:11)
at TCP.onread (net.js:568:26)
conn closed
So I have read Node js ECONNRESET already but I don't understand if this is normal why my nodejs server crash?
Edit: I found this snippet:
connection.on("error", function(err) {
console.log("Caught flash policy server socket error: ");
console.log(err.stack);
});
This code on client side will produce the same error:
#ifdef WIN32
Sleep(5000);
int iResult = shutdown(sock, SD_BOTH);
printf("shutdown is called\n");
Sleep(5000);
#elif defined (linux)
sleep(5);
int iResult = shutdown(sock, SHUT_RDWR);
printf("shutdown is called\n");
sleep(5);
#endif // WIN32
if (iResult == SOCKET_ERROR) {closesocket(sock);printf("SOCKET_ERROR");}
printf("iResult=%d",iResult);
Edit:
Now I catch either close event and end event: but the same error is still throwed.
Edit: I've Updated my code.
And I found where is the problem:NodeJs is trying to send me data but I've already called shutdown().

There 2 things to consider, one in your server and one in your client code.
Server code:
You have to use the end event instead of the close event, see
https://nodejs.org/api/net.html#net_event_end:
connection.on('end', function (){
console.log('client disconnected');
});
end event:
Emitted when the other end of the socket sends a FIN packet, thus ending the readable side of the socket.
close event:
Emitted once the socket is fully closed. The argument had_error is a boolean which says if the socket was closed due to a transmission error.
So that means, that the close event will occur after the end event.
Client code:
You have to call shutdown before closing the socket to prevent further reads or writes which then would cause an error because the socket is already down.
The Windows version of shutdown is described here at MSDN and the Linux variant here in a manpage.
Windows:
int ret = shutdown(sockfd, SD_BOTH); /* Shutdown both send and receive operations. */
Linux:
int ret = shutdown(sockfd, SHUT_RDWR); /* Disables further send and receive operations. */
Importance of flushing sent data:
The shutdown function does not guarantees that data that is already in the buffer does not get send. It is needed that all data get's flushed before the call to close occur. In this answer on SO is written down a nice way to do that rather than just sleep 20 ms or so.
In order to test if that is your problem you can use Sleep(2000) in Windows and sleep(2) in Linux to sleep 2 seconds between shutdown and close.
On this page is a nice comparison between close/closesocket and shutdown:
You're ready to close the connection on your socket descriptor. This is easy. You can just use the regular Unix file descriptor close() function:
close(sockfd);
This will prevent any more reads and writes to the socket. Anyone attempting to read or write the socket on the remote end will receive an error.
Just in case you want a little more control over how the socket closes, you can use the shutdown() function. It allows you to cut off communication in a certain direction, or both ways (just like close() does.) Synopsis:
int shutdown(int sockfd, int how);
[...]
shutdown() returns 0 on success, and -1 on error (with errno set accordingly.)

Related

Understanding USBIP bind function

I am trying to understand the USBIP tool code from Linux (https://github.com/torvalds/linux/tree/master/tools/usb/usbip).
USBIP has a command that attaches a remote USB from an IP to a client system. If you look at the code (https://github.com/torvalds/linux/blob/master/tools/usb/usbip/src/usbip_bind.c#L130) below, which binds the USB, if the function calls close(sockfd); and close the socket, then how the communication is done between client and server for USB data.
From Docs (https://docs.kernel.org/usb/usbip_protocol.html):
Once the client knows the list of exported USB devices it may decide
to use one of them. First the client opens a TCP/IP connection to the
server and sends an OP_REQ_IMPORT packet. The server replies with
OP_REP_IMPORT. If the import was successful the TCP/IP connection
remains open and will be used to transfer the URB traffic between the
client and the server.
It says connection remains open if import is successful, then what is the purpose of close(sockfd);. I can also see sockfd is sent inside query_import_device(sockfd, busid); but if it is closed how this is used?
static int attach_device(char *host, char *busid)
{
int sockfd;
int rc;
int rhport;
// creates a TCP connection to the specified host on the specified port.
sockfd = usbip_net_tcp_connect(host, usbip_port_string);
if (sockfd < 0) {
err("tcp connect");
return -1;
}
// sends a query to the connected host to import the device specified by "busid".
rhport = query_import_device(sockfd, busid);
if (rhport < 0)
return -1;
// closes the previously established TCP connection.
close(sockfd);
// records details of the connection, such as the host and port, the busid of the device, and the assigned rhport.
rc = record_connection(host, usbip_port_string, busid, rhport);
if (rc < 0) {
err("record connection");
return -1;
}
return 0;
}
If you look at the source code of usbip helper program, query_import_device(), it establishes the connection and then calls import_device() to finish it.
In turn, import_device() calls usbip_vhci_attach_device(), that calls usbip_vhci_attach_device2()... that eventually writes the sockfd and some extra data to the /sys/*/attach pseudo file for the given device.
To see what happens next we need to go to kernel mode. So, looking at the source code of the usbip, at function attach_store(). This function parses the sockfd back into an integer file descriptor and, most notably, does this:
struct socket *socket;
socket = sockfd_lookup(sockfd, &err);
This converts a file descriptor into a real kernel socket object. And it increases the reference count. Note how if any of the further checks fail, it calls sockfd_put(socket); to decrease that reference count.
But if the function succeeds, the socket is stored into the device. It is just as if an userland program had done a call to dup(): it doesn't matter if the original sockfd is closed, the kernel keeps the actual socket opened as long as it is needed.
You can see that the value of sockfd is also stored in the device, but it isn't actually used for anything other than reading back from /sys, so it doesn't matter if it is no longer a valid file descriptor.
So the close is actually necessary because the kernel dups the socket internally, that keeps the connection opened. And you do not want to keep an extra FD referencing the same socket, if you try to use that socket for anything that could mess up the device connection. The responsible thing to do is just to close it.

LWIP: Monitor and close a TCP connection with Netconn API

I am using Lwip 2.1.2 with FreeRtos v10.0.0 and the Netconn API.
I am trying to find a way to gracefully close a Netconn connection and try to reconnect in case of a communication issue.
Currently, to identify a communication issue, I try to do a
netconn_write()
and in case this method returns an error I try to
netconn_close()
and
netconn_delete()
the netconn connection.
To simulate a TCP connection I use Netcat in Linux (Running on my host PC) and my Embedded Device is connected with an Ethernet cable to my PC.
By the time I have a connection and receive data on the PC, I try to simulate a communication interruption by just killing the Netcat connection (Ctrl+c). However, I get the following errors:
netconn_close(netconn) returns error: -11 (ERR_CONN = Not connected)
netconn_delete(netconn) returns error: -5 (ERR_INPROGRESS = Operation in progress)
A simplified version of my code:
void FooMethod()
{
netconn* tcpListenNetconn;
netconn* connection;
tcpListenNetconn = netconn_new(NETCONN_TCP);
netconn_bind(tcpListenNetconn, IP4_ADDR_ANY, TCP_PORT);
netconn_listen(tcpListenNetconn);
netconn_accept(tcpListenNetconn, &connection);
uint8_t buffer = 0x65;
while(1)
{
err_t error = netconn_write(connection , &buffer , 1, NETCONN_COPY);
if (error != ERR_OK)
{
netconn_close(connection);
netconn_delete(connection);
break;
}
}
}
Update
I realized that if I kill netcat on the host machine, the TCP connection will be closed in the background, that's why I get the error messages from
netconn_close()
and
netconn_delete()
While I could ignore the closing errors, my next problem was when I was trying to re-connect I was getting an error from
netconn_bind(): -8 (ERR_USE, Address in use)
But this is because I try to reconnect to the same port. Apparently Netconn API doesn't provide options for reusing an IP Address or a Port, so the probably the Socket API has to be used.

C sockets: using shutdown() to stop server running in background

I have implemented end_server() method using some volatile flag should_server_end = true/false. I have used non-blocking connection sockets to enable checking this flag between consecutive recv() calls. It works fine. But I have read about using shutdown(sock, SHUT_RDWR) called from the main thread that can stop the server (and its connections) running in the background. I would like to try this approach in my app and implement some alternative methods instead of end_server() like shutdown_server().
I have tried something like this:
int pasv_sock = server_info_sock(server_info);
if(shutdown(pasv_sock, SHUT_RDWR) < 0) {
fprintf(stderr, "shutdown: failed! %s\n", strerror(errno));
return FAILURE;
}
But now I am getting error message:
shutdown: failed! Socket is not connected
which means shutdown() return this error code:
ENOTCONN
The specified socket is not connected.
1. Can I only use shutdown on active (connection) sockets and not on passive (server) socket. Should I just use close()?
Next I change shutdown() to close() on passive socket, and then nothing happens. No errors but as in the previous method with shutdown connection still works correctly and I can send() and recv() packets of data.
2. Does it mean that close()-ing passive socket only stops possibility of making new connections with the server (server will no longer accept connections?)
So I have changed the code to something like this:
static void shutdown_conn_sock_data_handler(void *data, size_t data_size) {
sock_fd_t *conn_sock = (sock_fd_t *) data;
printf("Connection sock: %d closing...!\n", *conn_sock);
if(shutdown(*conn_sock, SHUT_RDWR) < 0) {
fprintf(stderr, "shutdown: failed! %s\n", strerror(errno));
return;
}
}
server_info_set_force_shut_down(server_info, 1);
const linked_list_t *conn_socks = server_info_conn_socks(server_info);
linked_list_travers(conn_socks, shutdown_conn_sock_data_handler);
int pasv_sock = server_info_sock(server_info);
if(close(pasv_sock) < 0) {
fprintf(stderr, "close: failed! %s\n", strerror(errno));
return FAILURE;
}
return SUCCESS;
}
It works now but this need also some flag to give the hint information about the closed server, otherwise, it will be closed with some error message as trying to accept new connections on the already closed passive socket.
So before trying to accept a new connection I need to check like this:
while(1) {
if(server_info_should_shut_down(server_info)) {
return CLOSED;
}
if(server_info_force_shut_down(server_info)) {
return FORCE_CLOSED;
}
As you can see such a force close approach doesn't differ much from lazy shutdown when I just set volatile should_shut_down flag and wait for the server to detect this and close in a regular way. The only benefit is that I possibly no longer have to have:
non-blocking connection sockets in connection_handlers (this functions are supplied by client code using server api)
before each client code need to set:
fcntl(sock_fd, F_SETFL, O_NONBLOCK);
to enable server self-closing.
*client - means programmer using server API, not client side of TCP communication.
moreover there was need to place after each recv failing without new request data
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// call to recv() on non-blocking socket result with nothing to receive
continue;
}
and client-code needs to add in connection_handler in between each client-side request:
if(server_info_should_shut_down(server_info))
return CLOSED;
So implementing this shutdown_server() method instead of end_server()
I can hide implementation details inside server API and allow user of this API to provide simpler and cleaner connection handler. Just recv/send logic without need to inject some special code that enables the server to be closable!
3. Is it this new approach with shutdown() correct? Didn't I missed anything?
Can I only use shutdown on active (connection) sockets and not on passive (server) socket.
Yes.
Should I just use close()?
Yes.
Next I change shutdown() to close() on passive socket, and then nothing happens. No errors but as in the previous method with shutdown connection still works correctly and I can send() and recv() packets of data.
Correct. That's how it works.
Does it mean that close()-ing passive socket only stops possibility of making new connections with the server (server will no longer accept connections?)
Yes. It doesn't affect existing accepted sockets.
Is it this new approach with shutdown() correct? Didn't I missed anything?
You should not shutdown the sockets for output. That will cause errors at both ends: this end, because it may write to a shutdown socket, and the other end because it will receive a truncation.
All you need to to is shutdown each accepted socket for input (i.e. SHUT_RD). That will cause the next recv() on that socket to return zero,meaning the peer disconneceted, whereupon the existing code should already close the socket and exit the thread.

Crash when sending data without connection via Socket in Linux

I'm using C language to send data via socket in Linux by using command
send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
The procedure is:
Create socket
Connect to Server
while (condition): Send data
When I run this program in Linux environment, if it is connected, there is no problem. But in order to take care of failed connection when running, I check some cases and got results as below:
Case 1:
Create socket: No creation (comment out creating function)
Connection to Server: No connection (comment out connecting function)
Send data --> Failed (return -1) but no crash
Case 2:
Create socket: Successfully
Connection to Server: Failed or even No connection (comment out
connecting function)
Send data --> Crash
And then, i tried 3 different values of socket WITHOUT connection to server
Case 3:
ServerSocket = -1 --> Send data: Failed
ServerSocket = 0 --> Send data: Failed
ServerSocket = 4 --> Send data: Crash
In case of failed sending, it is correct but I don't understand why i got crash in other cases. I tried with Windows but no problem, is that a different between Linux and Windows? does it make sense? I want to open socket and connect to server only once time and after that sending data a thousand times, so if "the crash" makes sense in this case, how can I fix this problem in case of failed connection? Thanks for your time.
Here is the Case 2 (connect failed by stopping Server in order to test a case of failed connection):
ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP) ;
...
iResult = connect(ServerSocket,(struct sockaddrx *)&server , sizeof(server));
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
if(iResult<0)
{...}
Here is the Case 3:
//ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP) ;
...
//iResult = connect(ServerSocket,(struct sockaddrx *)&server , sizeof(server));
ServerSocket = 0;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
ServerSocket = -1;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
ServerSocket = 4;
iResult = send(ServerSocket, cSendBuff, strlen(cSendBuff), 0);
log();
if(iResult<0)
{...}
Your program does not crash!
It receives a SIGPIPE signal because the local end of the socket has been shut down. Read man 2 send, especially the EPIPE error case. (So, to be precise, your program is terminated due to an unhandled SIGPIPE signal.)
As the man 7 signal man page says, the default disposition for SIGPIPE is to terminate the process. To avoid the termination, either set a SIGPIPE signal handler, or use send(socket, buffer, length, MSG_NOSIGNAL).
Do not use Windows as your measuring stick. It is not a sane method. You have much better, actually reliable documentation available. The Linux man-pages project is one of the best sources for the C library documentation (section 3). Even though it is focused on Linux and GNU C library, every page has a Conforming to section which tells you when and where that functionality is available.
The above links refer to the up-to-date web pages, but you can also use man 2 send, man 7 signal on the command line to browse the same information. The web pages are more up to date than the distributions, but the project only includes standard man pages, not those installed by applications or extra libraries you might have.
Questions?
Case 2.3: This should fail, by which I mean it should return -1 with an accompanying value of errno. You don't state what you mean by 'fail' or 'crash,' so it is impossible to comment further.
Case 3:
These should all fail ditto unless FD 0 or 4 happens to be a socket.
I have no idea why you're even testing any of this. A 'failed connection' is a completely different thing from a socket that has never been connected in the first place. A 'failed connection' manifests itself as a -1 return from send(), recv(), and friends, with an accompanying value of errno other than EAGAIN/EWOULDBLOCK. You can't send to a TCP socket that isn't connected, and it shouldn't be possible for your code to even attempt it. If it is, your error handling code path is incorrect.

C file transfer question

I implemented a client-server program that allows to transfer files b/w them. The server is using select() to check changes of sockets.
Every test is good except this one:
- When server is sending a huge file to client (not yet finished), client hit "Ctrl-C" to kill the client program, then the server is killed too :(
The snippet:
fprintf(stderr,"Reading done, sending ...\n");
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
{
printf("Failed to send through socket %d \n", sockClient);
return -1;
}
fprintf(stderr,"Sending done\n");
When the client is killed, the server terminal displays:
user$./server
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
Sending done
Reading done, sending ...
user$
What's wrong with it?
Thanks for your answers!
You probably want to ignore SIGPIPE. Try adding something like this in your server startup:
#include <signal.h>
signal(SIGPIPE, SIG_IGN);
The send() call may be used only when the socket is in a connected state (so that the intended recipient is known). the return is the bytescount sent...
if(send(sockClient, sendBuf, chunk_length, 0) < 0)
so when disconnected, it skipped out...
MSG_NOSIGNAL is not portable and will not be available on Windows.

Resources