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

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.

Related

App stucks in accept() when LAN interfaces changed

I created a small app on small router with 4 LAN ports. Router has been flashed with OpenWrt system, Linux kernel 5.4.154
Devices connected to LAN ports are sending date over TCP POSTs. The app is listening on specified TCP port and sends data to the server or stores it in SD card. Everything work fine until someone will start playing with plugs on the LAN side. Somethings is happening and app hangs in accept() function waiting for incomming data.
I assume (please correct me if I'm wrong) system changes?/resets? port routing and data are not delivered to the app socket any more.
Is there a simple solution to keep the 'subscription' of TCP port?
I've tried to rewrite app in async mode, but not everything is working correctly, is this the only solution for this problem?
Below simpyfied working(!) code in blocking mode (I removed all unnecesary stuff, so it may not compile)
int main() {
// Create server_socket as socket
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
cerr << "Can't create a socket! Quitting" << endl;
}
int enable = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
{
cout << GetTime() << "Can't use SO_REUSEADDR" << endl;
}
while (true) {
// Bind the ip address and port to a socket
listenningport = 55555;
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(listenningport);
inet_pton(AF_INET, "0.0.0.0", &hint.sin_addr);
if (bind(server_socket, (sockaddr*) &hint, sizeof(hint)) == -1) {
cerr << "Can't bind to IP/port" << endl;
}
// Tell Winsock the socket is for server_socket
if (listen(server_socket, SOMAXCONN) == -1) // handle multiconnections SOMAXCONN(4096, queue)
{
cerr << "Can't listen!" << endl;
}
// Wait for a connection
sockaddr_in client;
socklen_t clientSize = sizeof(client);
while (true) {
// Waiting for data on socket; block mode
int clientSocket = accept(server_socket, (sockaddr*) &client, &clientSize);
if (clientSocket == -1) {
cerr << "Problem with client connecting!" << endl;
// break the loop and try to renew socket connection
break;
}
else {
// receive all data till the end of message
int bytesReceived = 0;
while ((bytesReceived = recv(readSocket, out_data + msgSize, maxSizeOutData - msgSize - 1, 0)) > 0) {
msgSize += bytesReceived;
if (msgSize > maxSizeOutData + 1)
break;
}
// no data received
if (bytesReceived == -1) {
cerr << "Error in recv(). BytesReceived = -1" << endl;
}
close(clientSocket);
}
}
}

I coded a c++ server/client program using windows sockets. getting 10061 from wsagetlasterror() trying to connect using my public ip addr

Im attempting to connect to my server via my client and if i use my local host address 127.0.0.1 everything works perfectly fine. it connects and im able to send data. however whenever i switch it to my public address it fails to connect. i already went through my router and forwarded the port im using. and ive tested if the port is open with canyouseeme.org and port forward network utilities. the error code i get from getlasterror() is 10061. i also called my isp and they told me the port is open so i should be able to connect but im not. i turned off my firewall and AV as well. i have windows 10 64 bit. im at a loss and would really appreciate the help. the error code means that the server is actively refusing the connection. but nothing happens on my server side...it stays in the accept() call.
this is the server code. how do i solve this issue? i currently have both the server and client on one computer.
class Server
{
public:
Server(int port)
:
port(port)
{
std::cout << "Initializing server...\n";
if (WSAStartup(version, &wsData) == 0)
{
auto result = createListenSock();
//if no value is returned, it was a success
if (!result.has_value())
std::cout << "Successfully created a server! Accepting Clients now.\n";
else
std::cout << result.value() << std::endl;
}
else
std::cout << "Failed to initialize WinSock. Error : " << WSAGetLastError() << std::endl;
}
~Server()
{
closesocket(listensock);
closesocket(client);
WSACleanup();
}
std::optional<std::string> acceptClient()
{
int sz = sizeof(clientinfo);
if ((client = accept(listensock, (sockaddr*)&clientinfo, &sz)) == INVALID_SOCKET)
return {};
else
{
char clientipaddr[100];
inet_ntop(AF_INET, &clientinfo.sin_addr, clientipaddr, sizeof(clientipaddr));
return std::string(clientipaddr);
}
}
private:
std::optional<std::string> createListenSock()
{
//AF_INET for ipv4
//SOCK_STREAM A socket type that provides sequenced, reliable, two-way,
//connection-based byte streams with an OOB data transmission mechanism.
if ((listensock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
return "Failed to created listen socket...\n";
initConnectionInfo();
if (bind(listensock, (sockaddr*)&serverInfo, sizeof(serverInfo)) == SOCKET_ERROR)
return "Failed to bind...\n";
if (listen(listensock, SOMAXCONN) == SOCKET_ERROR)
return "Failed to put into listening mode...\n";
//if it returns an empty container, that means it was successful
return {};
}
void initConnectionInfo()
{
//make it use ipv4
serverInfo.sin_family = AF_INET;
//htons converts the port from host to network byte order.
serverInfo.sin_port = htons(port);
//specify that we can accept any ip address
serverInfo.sin_addr.S_un.S_addr = INADDR_ANY;
}
private:
WSADATA wsData;
int version = MAKEWORD(2,2);
SOCKET listensock;
sockaddr_in serverInfo;
int port;
private:
//client variables
SOCKET client;
sockaddr_in clientinfo;
};
int main()
{
//create server
Server server(1024);
auto clientip = server.acceptClient();
if (!clientip.has_value())
{
std::cout << "Couldn't connect to client.";
system("pause");
return 0;
}
std::cout << "Connected to client!" << std::endl << "Client IP Address: " << clientip.value() << std::endl;
and this is the client code
SOCKET startclient()
{
WSADATA data;
//server to connect to
std::string ipAddress = "127.0.0.1"; //IF I CHANGE THIS TO MY PUBLIC IP ADDRESS IT FAILS TO CONNECT
int port = 1024;
// initialize winsock
if (WSAStartup(MAKEWORD(2, 2), &data) != 0)
{
std::cout << "Could not initialize WinSock...\n";
return SOCKET_ERROR;
}
//create a socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "Couldn't create a socket, Error " << WSAGetLastError() << std::endl;
WSACleanup();
return SOCKET_ERROR;
}
//this tells our socket what info to use to connect to the server
sockaddr_in serverinfo;
serverinfo.sin_family = AF_INET;
//htons converts the port number from host to network byte order
serverinfo.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &serverinfo.sin_addr);
std::cout << "Attempting to connect..." << std::endl;
if (connect(sock, (sockaddr*)&serverinfo, sizeof(serverinfo)) == SOCKET_ERROR)
{
std::cout << "Failed to connect... Error : " << WSAGetLastError() << std::endl;
WSACleanup();
closesocket(sock);
return SOCKET_ERROR;
}
else
std::cout << "Connected!" << std::endl;
return sock;
}
int main()
{
SOCKET client = startclient();
if (client == SOCKET_ERROR)
{
system("pause");
return 0;
}

winsock error 10049 trying to bind

I have a problem with server connection. When I try to bind the server to my external device IP I got a winsock error: 10049 Cannot assign requested address. Using localhost server works correctly.
This IP address: 192.168.0.202 ping successfully.
I worked on win8.1. I turned off firewall and windows defender and it did not help.
Code with server implementation has been taken from http://www.planetchili.net/forum/viewtopic.php?f=3&t=3433
#include "Server.h"
Server::Server(int PORT, bool BroadcastPublically) //Port = port to broadcast on. BroadcastPublically = false if server is not open to the public (people outside of your router), true = server is open to everyone (assumes that the port is properly forwarded on router settings)
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}
addr.sin_addr.s_addr = inet_addr("192.168.0.202");
addr.sin_port = htons(1234); //Port
addr.sin_family = AF_INET; //IPv4 Socket
sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
if (bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) //Bind the address to the socket, if we fail to bind the address..
{
std::string ErrorMsg = "Failed to bind the address to our listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
if (listen(sListen, SOMAXCONN) == SOCKET_ERROR) //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections, if we fail to listen on listening socket...
{
std::string ErrorMsg = "Failed to listen on listening socket. Winsock Error:" + std::to_string(WSAGetLastError());
MessageBoxA(NULL, ErrorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
exit(1);
}
serverptr = this;
}
bool Server::ListenForNewConnection()
{
SOCKET newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == 0) //If accepting the client connection failed
{
std::cout << "Failed to accept the client's connection." << std::endl;
return false;
}
else //If client connection properly accepted
{
std::cout << "Client Connected! ID:" << TotalConnections << std::endl;
Connections[TotalConnections] = newConnection; //Set socket in array to be the newest connection before creating the thread to handle this client's socket.
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(TotalConnections), NULL, NULL); //Create Thread to handle this client. The index in the socket array for this thread is the value (i).
//std::string MOTD = "MOTD: Welcome! This is the message of the day!.";
//SendString(TotalConnections, MOTD);
TotalConnections += 1; //Incremenent total # of clients that have connected
return true;
}
}
bool Server::ProcessPacket(int ID, Packet _packettype)
{
switch (_packettype)
{
case P_ChatMessage: //Packet Type: chat message
{
std::string Message; //string to store our message we received
if (!GetString(ID, Message)) //Get the chat message and store it in variable: Message
return false; //If we do not properly get the chat message, return false
//Next we need to send the message out to each user
for (int i = 0; i < TotalConnections; i++)
{
if (i == ID) //If connection is the user who sent the message...
continue;//Skip to the next user since there is no purpose in sending the message back to the user who sent it.
if (!SendString(i, Message)) //Send message to connection at index i, if message fails to be sent...
{
std::cout << "Failed to send message from client ID: " << ID << " to client ID: " << i << std::endl;
}
}
//std::cout << "Processed chat message packet from user ID: " << ID << std::endl;
if(Message == "go")
std::cout << "MESSAGE:GO!" << std::endl;
else if(Message == "left")
std::cout << "MESSAGE: GO LEFT!" << std::endl;
else if (Message == "right")
std::cout << "MESSAGE:GO RIGHT!" << std::endl;
else
std::cout << "MESSAGE:DO NOTHING!" << std::endl;
break;
}
default: //If packet type is not accounted for
{
std::cout << "Unrecognized packet: " << _packettype << std::endl; //Display that packet was not found
break;
}
}
return true;
}
void Server::ClientHandlerThread(int ID) //ID = the index in the SOCKET Connections array
{
Packet PacketType;
while (true)
{
if (!serverptr->GetPacketType(ID, PacketType)) //Get packet type
break; //If there is an issue getting the packet type, exit this loop
if (!serverptr->ProcessPacket(ID, PacketType)) //Process packet (packet type)
break; //If there is an issue processing the packet, exit this loop
}
std::cout << "Lost connection to client ID: " << ID << std::endl;
closesocket(serverptr->Connections[ID]);
return;
}
Any ideas?
The bind() function is used to specify which address of the server system is used to accept connections from remote clients, not to specify which remote client is allowed to connect to the server. The bind() function can only be used with addresses that are valid for the server itself, not for addresses of remote devices or hosts.
In order to limit which remote host is allowed to connect to your server, you need to accept the connection and validate the remote address at that time. If the address is not the correct one, the connection is closed.
In general, you want to use INADDR_ANY unless your server is multi-homed (more than one physical connection to more than one network), and only then if you are trying to restrict connections to one of the networks to which your server is attached.
Winsock returns the error flag 10049 (WSAEADDRNOTAVAIL) through its API WSAGetLastError whenever an application tries to bind to an invalid ip Addrress.
binding to a specific IP address means that whenever you run the program (server) the address should be valid (available) but however DHCP gives you dynamic ip addresses everytime you disconnect/connect your adapter so you the address you bound the server the previous time is not valid to correct it open cmd and enter :
ipconfig
you'll get the list of ip4/ip6 addresses then you can pick one of them and bind your server to however this method is really dull so the alternative is to bind to INADDR_ANY so you let the system do the job for you.
you need only from the client to enter the server address and port and connect.

Reading RSysLog tcp messages

I am attempting to read RSysLog log from a machine running debian linux. I have setup a server on another linux machine and can read the log messages. I want to be able to read them on a windows machine from c++. I have setup the remote machine to distribute the logs to the windows machine. I have an application running on the machine that writes log messages at intervals. The setup to distribute the logs is of the form local1.* ##192.168.1.8 which is the ip address of the windows machine.
I know I am not thinking about this correctly, the remote machine does not attempt a connection to the windows machine and the program hangs on the accept call.
Edit:
After some further testing I figured out that the connect occurs when the syslog daemon is started. To use tcp the server has to be alive when the daemon is started. This is not what I want so I will work more with the UDP implementation.
Here is the code I am using, I have tried to make it as simple as possible.
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
SOCKET h;
h = socket(AF_INET, SOCK_STREAM, 0);
if (h == INVALID_SOCKET)
{
std::cout << "Socket Failure: " << std::endl;
return 1;
}
std::cout << "Socket Success: " << std::endl;
// The server
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("192.168.1.8");
server.sin_port = htons(514);
iResult = bind(h, (SOCKADDR *)&server, sizeof(server));
if (iResult == SOCKET_ERROR)
{
std::cout << "Bind Failure: " << std::endl;
closesocket(h);
return 1;
}
std::cout << "Bind Success: " << std::endl;
if (listen(h, SOMAXCONN))
{
std::cout << "Listen Failure: " << std::endl;
errcode = WSAGetLastError();
closesocket(h);
return 1;
}
std::cout << "Listen Success: " << std::endl;
struct sockaddr_in dest;
int addrlen = sizeof(dest);
SOCKET s = accept(h, (sockaddr *)&dest, &addrlen);
if (s == INVALID_SOCKET)
{
std::cout << "Accept Failure: " << std::endl;
}
else
{
std::cout << "Accept Success: " << std::endl;
}
WSACleanup();
return 0;
You probably need SOCK_DGRAM instead of SOCK_STREAM.
Syslog on port 514 seems to send UDP packets, not TCP.
You could also try to connect to the server with a browser to check if all the rest is ok (seems ok though) - 192.168.1.8:514 (while still in TCP mode).

not getting a Winsock error when ethernet unplugged

I'm working on a client application that sends sensor data one way to a remote server. After the initial login there is no return data from the server. My problem is when the ethernet is disconnected such as a hard disconnect i.e. wireless link goes down, my application does not get a error return value after attempting a 'send' call. I am using a single non-blocking socket instance. The thread checks for a 'recv' each loop using 'select'. It does eventually get an error on 'recv' but never on 'send'.
When the remote PC has a internet connectivity loss it will cause the program to be disconnected from the server for minutes to hours before it recognises the connection loss happened and switches to re-login the server. What can be done to help detect the hard disconnect?
void checkConnect(NTRIP& server)
{
//1st check for recv or gracefully closed socket
char databuf[SERIAL_BUFFERSIZE];
fd_set Reader, Writer, Err;
TIMEVAL Timeout;
Timeout.tv_sec = 1; // timeout after 1 seconds
Timeout.tv_usec = 0;
FD_ZERO(&Reader);
FD_ZERO(&Err);
FD_SET(server.socket, &Reader);
FD_SET(server.socket, &Err);
int iResult = select(0, &Reader, NULL, &Err, &Timeout);
if(iResult > 0)
{
if(FD_ISSET(server.socket, &Reader) )
{
int recvBytes = recv(server.socket, databuf, sizeof(databuf), 0);
if(recvBytes == SOCKET_ERROR)
{
cout << "socket error on receive call from server " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else if(recvBytes == 0)
{
cout << "server closed the connection gracefully" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
else //>0 bytes were received so read data if needed
{
}
}
if(FD_ISSET(server.socket, &Err))
{
cout << "select returned socket in error state" << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else if(iResult == SOCKET_ERROR)
{
cout << "ip thread select socket error " << WSAGetLastError() << endl;
closesocket(server.socket);
server.connected_IP = false;
}
//2nd check hard disconnect if no other data has been sent recently
if(server.connected_IP == true && getTimePrecise() - server.lastDataSendTime > 5.0)
{
char buf1[] = "hello";
cout << "checking send for error" << endl;
iResult = send(server_main.socket, buf1, sizeof(buf1), 0);
if(iResult == SOCKET_ERROR)
{
int lasterror = WSAGetLastError();
if(lasterror == WSAEWOULDBLOCK)
{
cout << "server send WSAEWOULDBLOCK" << endl;
}
if(lasterror != WSAEWOULDBLOCK)
{
cout << "server testing connection send function error " << lasterror << endl;
closesocket(server.socket);
server.connected_IP = false;
}
}
else
{
cout << "sent out " << iResult << " bytes" << endl;
}
server.lastDataSendTime = getTimePrecise();
}
}
It is not possible to detect disconnect until you try to send something.
The solution for you is the following:
You detect that you have received no data for a certain period of time and you want to check is the connection is alive.
You send some data to the server using send function. It could be protocol-specific ping packet or either garbage. The send function returns immediately, because it does not wait for actual data send. It only fills internal send buffer.
You begin waiting for socket read.
While you are waiting, OS tries to send the data in the send buffer to the server.
When OS detects that it cannot deliver data to the server, then the connection is marked as erroneous.
Now you will get an error when calling recv and send functions.
The send timeout is system specific and can be configured. Usually, it is about 20 seconds (Linux) - 2 minutes (Windows). It means that you need to wait a lot before you receive an error.
Notes:
You can also turn on TCP keep alive mechanism, but I don't recommend you to do this.
You can also modify TCP timeout intervals. It can be helpful when you want the connection to survive the temporary network disconnect.
That's how TCP works and is intended to work. You will get an error from a subsequent send, but never from the first send after the disconnect. There is buffering, and retry, and retry timeout to overcome before an error is signalled.