socket, detect connection is lost - c++

I'm connecting a server process and a client process with a TCP connection, and I have to detect
that physical connection between the two machines is down. I'm trying to do this using the keepalive,
decreasing the default system wide values to:
TCP_KEEPIDLE=5
TCP_KEEPCNT = 5
TCP_KEEPINTVL = 1
When the connection goes down ( I disconnect the cable ) only the server in 10 seconds detect that the connection has been lost, the client just hangs on the send.
This is the client code:
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/tcp.h>
int main(int argc, char** argv) {
char myVector[1600];
int mySocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (mySocket < 0 ) {
std::cout << "error creating the socket" << strerror(errno) << std::endl;
::exit(-1);
}
struct sockaddr_in sin;
memset( (char *)&sin, 0, sizeof( sin ) );
sin.sin_addr.s_addr = inet_addr("192.168.21.27");
sin.sin_port = htons(7788);
sin.sin_family = AF_INET;
if ( connect( mySocket, (struct sockaddr *)&sin, sizeof( sin )) < 0 ) {
std::cout << "Error on connection: " << strerror(errno) << std::endl;
::exit(-1);
}
int optval = 1;
socklen_t optlen = sizeof(optval);
/*Enabling keep alive*/
if(setsockopt(mySocket, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
std::cout << "Error setting SO_KEEPALIVE: " << strerror(errno) << std::endl;
}
optval = 5;
optlen = sizeof(optval);
if(setsockopt(mySocket, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) {
std::cout << "Error setting TCP_KEEPIDLE: " << strerror(errno) << std::endl;
}
optval = 5;
optlen = sizeof(optval);
if(setsockopt(mySocket, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0) {
std::cout << "Error setting TCP_KEEPCNT: " << strerror(errno) << std::endl;
}
optval = 1;
optlen = sizeof(optval);
if(setsockopt(mySocket, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) {
std::cout << "Error setting TCP_KEEPINTVL: " << strerror(errno) << std::endl;
}
for (;;) {
ssize_t myRet= ::send(mySocket,
myVector,
sizeof(myVector),
0);
if (myRet < 0) {
std::cout << "Error: " << strerror(errno) << std::endl;
break;
}
std::cout << myRet << "."; std::cout.flush();
sleep(1);
}
}
I'm sure I'm missing something, but what ?

TCP Keepalive isn't intended for this use.
If you want to detect outages at the application layer, do what protocols like SSH, IMAP and IRC do - implement an echo/ping type message at the application layer. Send them on a regular basis, and if you don't get a timely reply, the connection can be assumed to be down.

We wondered about that question in our company a while ago : "how to detect that connection went down?".
To adress this issue reliably, we had to implement a "heart-beat" system, ie the client regularly check (each second in our case) that the server is still there, by doing a pseudo-ping.
If you don't want to do that, you can wait that the OS actually detects that connection went down, but don't expect it to be reliable...

So,
after further investigaion, even if "TCP Keepalive" is not intended for this use, I have discovered that keep alive probes are started to being sent on a "idle connection". The question is now: "when a connection is considered in idle state?".
A connection is considered idle when there is no data "being transmitted" so if one of the
two peers are blocked on a send(...) there are actually some data being transmitted and the connection is not considered idle. I guess the only option I have now is to do a ping/pong using sends/recv with timeout, declaring a connection "lost" when those timers expires.

Gaetano, IMO, TCP keep-alives can be used to detect dead connections. In your example, the client might actually be hanging in the send waiting for the TCP retries to exhaust themselves. Depending on the back-off algorithm and TCP stack state machine, this can last several minutes without any keep-alive probes, and thus no way to exhaust keepcnt.
I assume that the server is mostly read-blocked, in which case, its keep-alives would be sent out every keepidle/slowhz seconds (slowhz is often 2 instead of 1), and it will detect the connection loss fairly quickly.
If you capture a packet trace with tcpdump, you'll see exactly what's happening on the wire.

You should replace SOL_TCP with IPPROTO_TCP.
For more information follow these links
TCP-Keepalive-HOWTO
Socket keepalive not working

Related

multi usage of udp port on c++ / use port multi time on c++ server

i wanna ask about how can i use port for 2 application
for example i have a program like teamspeak server use port 9987 (Default)
and i have a code with c++ to listen to this udp ports and see the packets value
but the problem is when i start teamspeak server i can't start c++ code get error 10048
this is my code
#include <iostream>
#include <WS2tcpip.h>
// Include the Winsock library (lib) file
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
// Start WinSock
int wsOk = WSAStartup(version, &data);
if (wsOk != 0)
{
// Not ok! Get out quickly
cout << "Can't start Winsock! " << wsOk;
return;
}
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY; // Us any IP address available on the machine
serverHint.sin_family = AF_INET; // Address format is IPv4
serverHint.sin_port = htons(9987); // Convert from little to big endian
int reuse = 1;
setsockopt(in, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
setsockopt(in, SOL_SOCKET, 15, (const char*)&reuse, sizeof(reuse));
// Try and bind the socket to the IP and port
if (bind(in, (sockaddr*)&serverHint, sizeof(serverHint)) == SOCKET_ERROR)
{
cout << "Can't bind socket! " << WSAGetLastError() << endl;
return;
}
sockaddr_in client; // Use to hold the client information (port / ip address)
int clientLength = sizeof(client); // The size of the client information
char buf[1024];
while (true)
{
ZeroMemory(&client, clientLength); // Clear the client structure
ZeroMemory(buf, 1024); // Clear the receive buffer
int bytesIn = recvfrom(in, buf, 1024, 0, (sockaddr*)&client, &clientLength);
if (bytesIn == SOCKET_ERROR)
{
cout << "Error receiving from client " << WSAGetLastError() << endl;
continue;
}
char clientIp[256]; // Create enough space to convert the address byte array
ZeroMemory(clientIp, 256); // to string of characters
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);
cout << "Message recv from " << clientIp << " : " << buf << endl;
}
closesocket(in);
WSACleanup();
}
i get this code from youtube channel and have some edit on it and i tired from search
my edit in the code is add SO_REUSEADDR and add SO_REUSEPORT and its value is 15
any one can help ?
2 separate applications cannot listen to the same port on the same address either for TCP or UDP, OS needs to know which application to deliver an UDP packet (or which app would accept connection in case of TCP). Exception is multicast UDP, but that is a different story. If you want to intercept packets that are delivered to existing application that is completely different task and significantly more complicated. You may use existing application like Wireshark or write your own app - details on writing app for traffic interception for windows can be found here Making a program that intercepts network traffic in Windows

Trying to connect() multiple times in TCP

I'm writing a client/server application where the client and server should send data to each other via a TCP socket. The client should connect to the server and if the connection fails, it should wait a few seconds and then try again to connect to it (up to a certain number of tries).
This is the code I currently have:
const int i_TRIES = 5;
time_t t_timeout = 3000;
int i_port = 5678;
int i_socket;
string s_IP = "127.0.0.1";
for(int i = 0; i < i_TRIES; i++)
{
if((i_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "[Client]: Socket creation failed." << endl;
exit(EXIT_FAILURE);
}
memset(&server_address, '0', sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(i_port);
if(inet_pton(AF_INET, s_IP.c_str(), &server_address.sin_addr) <= 0)
{
cout << "[Client]: Invalid IP address." << endl;
exit(EXIT_FAILURE);
}
if(connect(i_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
if(i < i_TRIES - 2)
{
cout << "[Client]: Connection to server failed. Trying again in " << t_timeout << " ms." << endl;
close(i_socket);
sleep(t_timeout);
}
else
{
cout << "[Client]: Could not connect to server, exiting." << endl;
exit(EXIT_FAILURE);
}
}
else
{
cout << "[Client]: Successfully connected to server." << endl;
break;
}
}
// do stuff with socket
The issue I'm having is that the first call to connect() works as expected, it fails if there's no server and then the loop repeats, however, the second time connect() blocks forever (or at least for much longer than I want it to). Initially, my loop was just around the connect() if block (code below), and this also caused the same problem. After that I included the whole socket setup (the code above) in the loop, but that also didn't help. I also tried closing the socket after a failed connection, but this didn't help either.
Initial for loop:
// other stuff from above here
for(int i = 0; i < i_TRIES; i++)
{
if(connect(i_socket, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
if(i < i_TRIES - 2)
{
cout << "[Client]: Connection to server failed. Trying again in " << t_timeout << " ms." << endl;
sleep(t_timeout);
}
else
{
cout << "[Client]: Could not connect to server, exiting." << endl;
exit(EXIT_FAILURE);
}
}
else
{
cout << "[Client]: Successfully connected to server." << endl;
break;
}
}
// do stuff with socket
Can I force connect() to return after a certain amount of time has passed? Or is there a way to get the connect() function to try multiple times on it's own? Or is there something I need to do to the socket to reset everything before I can try again? I hope this isn't a dumb question, I couldn't find any information about how to connect multiple times.
Thanks in advance!
Can I force connect() to return after a certain amount of time has passed?
No. You must put the socket into non-blocking mode and then use select() or (e)poll() to provide timeout logic while you wait for the socket to connect. If the connection fails, or takes too long to connect, close the socket, create a new one, and try again.
Or is there a way to get the connect() function to try multiple times on it's own?
No. It can perform only 1 connection attempt per call.
Or is there something I need to do to the socket to reset everything before I can try again?
There is no guarantee that you can even call connect() multiple times on the same socket. On some platforms, you must destroy the socket and create a new socket before you call connect() again. You should get in the habit of doing that for all platforms.
Put the socket into non-blocking mode and use select() to implement the timeout. Select for writeability on the socket. Note that you can decrease the platform connect timeout by this means, but not increase it.
The sleep() is pointless, just literally a waste of time.

c++ : TCP Server "bind" function failed (errno 98) if I do not wait enough time between two consecutive app launch [duplicate]

This question already has answers here:
What are the use cases of SO_REUSEADDR?
(2 answers)
Closed 7 years ago.
discovering TCP socket, I made a very simple test based on my understanding of the subject and some tuto found on the net
Server :
void Server(void)
{
int localSocket;
int distantSocket;
sockaddr_in serverInfo;
sockaddr_in clientInfo;
int sizeOfSocketInfo = sizeof(struct sockaddr_in);
/* Open Socket */
std::cout << "open socket" << std::endl;
localSocket = socket(AF_INET, SOCK_STREAM, 0);
if (localSocket == -1)
{
std::cout << "open failed, error - " << (int)errno << std::endl;
exit(errno);
}
/* Configure server */
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_family = AF_INET;
serverInfo.sin_port = htons(61001);
/* Bind Socket */
std::cout << "bind socket" << std::endl;
if (bind (localSocket, (sockaddr *) &serverInfo, sizeof(serverInfo)) == -1)
{
std::cout << "bind failed, error - " << (int)errno << std::endl;
exit(errno);
}
/* Wait for client */
std::cout << "Wait for client ..." << std::endl;
listen(localSocket, 1);
distantSocket = accept(localSocket, (sockaddr *)&clientInfo, (socklen_t*)&sizeOfSocketInfo);
std::cout << "client connected - " << inet_ntoa(clientInfo.sin_addr) << std::endl;
/* Close Socket */
close (localSocket);
close (distantSocket);
std::cout << "socket closed" << std::endl;
}
and client :
void Client(void)
{
int localSocket;
sockaddr_in clientInfo;
/* Open Socket */
std::cout << "open socket" << std::endl;
localSocket = socket(AF_INET, SOCK_STREAM, 0);
if (localSocket == -1)
{
std::cout << "open failed, error - " << (int)errno << std::endl;
exit(errno);
}
clientInfo.sin_family = AF_INET;
clientInfo.sin_port = htons(61001);
clientInfo.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Open Socket */
std::cout << "connect to server" << std::endl;
if (connect(localSocket, (sockaddr*)&clientInfo, sizeof(clientInfo)) < (int)0)
{
std::cout << "connect failed, error - " << (int)errno << std::endl;
exit(errno);
}
std::cout << "connected !" << std::endl;
close(localSocket);
}
When I launch the server in one terminal and the client in another one, it seems to be ok :
server side :
> ./tcpTest -s
open socket
bind socket
Wait for client ...
client connected - 127.0.0.1
socket closed
>
and client side :
> ./tcpTest -c
open socket
connect to server
connected !
>
But, if, just after this first try, I launch the server again ...
> ./tcpTest -s
open socket
bind socket
bind failed, error - 98
>
And I have to wait a "certain time", I don't know exactly how long, one minute maybe, to have the server working again.
I can't figure out what's happening, looking to open socket with sockstat does not show anything strange (I only see mozilla socket).
I found this guy having the same problem but in Ruby
basic Ruby TCP server demo fails on startup: `bind': Address already in use, Errno::EADDRINUSE
If this is really the same problem, how can I apply the same solution in C++ ? Or do you have any idea ?
Thank you
You may need to use both SO_REUSEADDR and SO_REUSEPORT. You can further go through the documentation of Socket: Socket Docs
const int trueFlag = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &trueFlag, sizeof(int)) < 0)
error("Failure");
You can use reuse Port in similar way. Hope this helps
Try setsockopt(SO_REUSEADDR), this should help.

Clients unable to connect after server shutdown and restart

I have a problem with my C++ networking code(a test server that receives strings and displays it). Occasionally, when I turn off my server(Ctrl C) and then restart it, clients fail to connect to it. If I wait for around a minute and try connecting with a client again, it works perfect. Doing a ps -A | grep my_server I don't find the process running. However, if I'd try to connect in about 2 minutes it would work just fine.
I find this rather strange.
I'm used to a slightly similar problem in Python, where I have trouble connecting to a port after pressing Ctrl+C. In that case, the process might still be running and I'd have to manually kill the process and try connecting again(and it would work just fine then).
Is there any code that you'd like me to paste in particular? I'm accepting the connections as follows :-
NetworkManager* start_listening(char* host, int port) {
keep_running = true;
signal(SIGINT, signal_handler);
int listenfd, connfd, n;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
pid_t pid;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
#ifdef DEBUG
std::cout << "[+] Starting to listen at port " << port << std::endl;
#endif
#ifdef DEBUG
std::cout << "[+] Binding to port" << std::endl;
#endif
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
#ifdef DEBUG
std::cout << "[+] Starting to listen" << std::endl;
#endif
listen(listenfd, 1024);
clilen = sizeof(cliaddr);
while ( keep_running ) {
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
#ifdef DEBUG
if ( connfd == -1 ) {
std::cout << "Yikes got an error with errno = " << errno << std::endl;
}
sockaddr_in* pV4Addr = (struct sockaddr_in*)&cliaddr;
int ipAddr = pV4Addr->sin_addr.s_addr;
char str[20];
inet_ntop(AF_INET, &ipAddr, str, 20);
std::cout << "[+] Incoming connection from " << str << std::endl;
std::cout << "[+] Using socket " << connfd << std::endl;
#endif
if ( (pid=fork()) == 0 ) {
close(listenfd);
NetworkManager *nm = new NetworkManager(connfd);
return nm;
} else {
close(connfd);
}
}
if (!keep_running) {
// #TODO kill all children
#ifdef DEBUG
std::cout << "[+] Killing server" << std::endl;
#endif
exit(0);
}
return 0;
}
The problem is that you're not checking your return values. For example, to bind. Which could be failing. For example, because you aren't using REUSEADDR to allow binding to a port which was recently in use. There's a timeout on these things, and that was a dead giveaway when you mentioned that it works again after two minutes. But really, check your return values--this is C after all!

Winsock connect() hanging on one network, but not another

I am having trouble using the connect() function. My code was completely working before, but now I have moved to a different physical network and my blocking call to connect() no longer works, and just seems to hang indefinitely. Receiving broadcasts over UDP still works fine. Going back to the old network it works fine again. I cant for the life of me figure out why it works on one network and not the other. I have checked firewall settings and they are correct. What could be going on?
I have a pre-defined port being used and I am getting the address from the broadcast. I use recievefrom to receive the broadcast and set the outgoing ip address from it
ret = recvfrom (bcast, bcast_read,sizeof(j4cDAC_broadcast),0,(sockaddr*)&from,&size);
to.sin_addr = from.sin_addr;
local.sin_addr.s_addr = inet_addr("0.0.0.0");
Then for the TCP connection I have
dac = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// cout << "SOCKET\n";
if (dac == INVALID_SOCKET)
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "TCP socket failed: " << WSAGetLastError();
connected_ = false;
return(1);
}
//set SO_REUSEADDR on a socket to true (1):
bool optval = true;
setsockopt(dac, SOL_SOCKET,SO_DONTLINGER,(const char*)&optval, sizeof(optval));
int pies = setsockopt(dac, SOL_SOCKET,SO_REUSEADDR,(const char*)&optval, sizeof(optval) );
if (pies == SOCKET_ERROR )
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "SETSOCKOPT ERROR: " << WSAGetLastError() << endl;
} // */
local_T = local;
local_T.sin_port = htons ((short)TCPport);
//bind the tcp socket
bndt = bind(dac,(SOCKADDR*) &local_T,sizeof(local_T) );
if (bndt == SOCKET_ERROR )
{
SetConsoleTextAttribute(console,(WORD)12);
cout << "BIND TCP FAILED: " << WSAGetLastError();
if (WSAGetLastError() == WSAEACCES)
cout << "ACCESS DENIED";
cout << endl;
SetConsoleTextAttribute(console,(WORD)7);
shutdown(dac,2);
closesocket(dac);
connected_ = false;
return 1;
}
c = connect(dac, (sockaddr*) &to, size); // <------- This hangs
if (c == SOCKET_ERROR)
{
cout << "connection problem: " << WSAGetLastError() <<endl;
}
connected_ = true;`
I found this to be an issue with VMWare virtual networking devices. Even though I had no virtual machines running, after much testing of various things, I found the device broadcast was being received on one of the virtual networking interfaces from VMWare somehow. Disabling these two devices has fixed this issue.