C++ , TCP Socket cannot receive data - c++

I created a BSD-POSIX TCP Socket class and now i have a problem.I have two wifi networks.One of them is an ADSL Router , and another one is hotspoted by an Android device.When i connect to ADSL Router wifi , i can't receive any data at all.The socket can send data , but there is no response.But when i connect to hotspoted wifi (Android device) , the program can receive data.I don't know what is the problem.Both WIFI Networks working fine.And also i used Wireshark to capture data.Data sent successful , but there is no receive.Here is my code:
-------------------ESocket.cpp---------------------
#include "ESocket.h"
#include "stdio.h"
SOCKET s = NULL;
ESocket::ESocket(string ip,int port)
{
struct sockaddr_in server;
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == -1)
{
s = NULL;
}
server.sin_addr.s_addr = inet_addr(ip.c_str());
server.sin_family = AF_INET;
server.sin_port = htons( port );
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
s = NULL;
}
}
ESocket::ESocket(SOCKET e)
{
s = e;
}
ESocket::~ESocket()
{
Destruct();
}
bool ESocket::isConnected()
{
return (s != NULL);
}
int ESocket::Destruct()
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}
int ESocket::Close()
{
int status = 0;
#ifdef _WIN32
status = shutdown(s, SD_BOTH);
if (status == 0) { status = closesocket(s); }
#else
status = shutdown(s, SHUT_RDWR);
if (status == 0) { status = close(s); }
#endif
return status;
}
bool ESocket::SendData(string data)
{
if( send(s , data.c_str() , data.length() , 0) < 0)
{
s = NULL;
return false;
}
return true;
}
string ESocket::ReceiveData(int len)
{
int recv_size;
char reply[len];
if((recv_size = recv(s , reply , len , 0)) < 0)
{
return "";
}
if (recv_size == 0)
{
s = NULL;
return "";
}
printf("%i",recv_size);
reply[recv_size] = '\0';
return reply;
}
int ESocket::setAsNonBlock()
{
int res;
#ifdef _WIN32
u_long iMode = 1;
res = ioctlsocket(s, FIONBIO, &iMode);
#else
int opts;
opts = fcntl(s, F_GETFL);
if(opts < 0)
{
res = -1;
}
opts = (opts | O_NONBLOCK);
if(fcntl(s, F_SETFL, opts) < 0)
{
res = -1;
}
#endif
return res;
}
-------------------ESocket.h---------------------
#ifndef ESOCKET_H
#define ESOCKET_H
#include <string>
#include <stdio.h>
#include <cstring>
using namespace std;
#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <winsock2.h>
#else
typedef int SOCKET;
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#endif
class ESocket
{
public:
ESocket(string ip,int port);
ESocket(SOCKET e);
virtual ~ESocket();
int Destruct();
int Close();
int setAsNonBlock();
bool SendData(string data);
bool isConnected();
string ReceiveData(int len);
static int Init()
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}
static string getIP(char* host)
{
struct hostent *he;
struct in_addr **addr_list;
char ip[100];
int i;
if ( (he = gethostbyname( host ) ) == NULL)
{
return "";
}
addr_list = (struct in_addr **) he->h_addr_list;
for(i = 0; addr_list[i] != NULL; i++)
{
strcpy(ip , inet_ntoa(*addr_list[i]) );
}
string x = ip;
return x;
}
protected:
private:
};
#endif // ESOCKET_H
------------------------MAIN-----------------------
ESocket::Init();
ESocket e(ESocket::getIP("www.google.com").c_str(),80);
if (e.isConnected())
{
cout<<e.SendData("GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\n\r\n");
}
else
{
printf("Not connected");
return 0;
}
while (e.isConnected()){
cout<<e.ReceiveData(100);
}
printf("\nEND OF CONNECTION");
EDIT: Solved by reset wifi router.

You have several serious bugs:
Your receive function has no code to support the "would block" condition and so it will not work reliably with non-blocking sockets.
Your receive function provides no reliable way to tell whether it got an error or not (as opposed to an empty string). It corrupts the socket value on an error, so calling it again after an error is potentially disastrous. Yet it provides no way at all to avoid this.
You set the socket to NULL. But nothing makes NULL an invalid value for a socket. On WIN32, use INVALID_SOCKET. On other platforms, use -1.
You also have a more minor issue. Your request claims HTTP 1.1 compliance, but it is not an HTTP 1.1 compliant request. For example, HTTP 1.1 makes "Host" headers mandatory. Don't claim compliance with a protocol you have no intention of supporting. What happens if you get back a reply that uses chunked encoding?
Likely what's happening is that receive is encountering a "would block" condition, corrupting the socket, and then you call receive again with an invalid socket which, of course, fails.

Related

Why are there a bunch of ╠ on the front of my packet?

EDIT: The first one answers the question in the title. It was initialized memory from my debugger. I didn't get the program to work however. Just going to go back to boost::asio for my sockets. Sockets are painful.
I'm following this tutorial on how to start sending and receiving packets using sockets. I've followed the tutorial to the best of my ability, but I get a bunch of ╠'s in front of my message. Can someone explain why I'm getting these? Their ASCII code is 204 so not null nor is it 0xFF. If you need anything more, please let me know.
Bonus points: Why is my console outputting this infinitely instead of breaking out of the while loop? I'm new and don't understand. D:
Output:
buffer: ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠Hello World!
(times infinity)
My main class
#include "common_include.h"
#include "Socket.h"
#include "Address.h"
#include <string>
bool Initialize_Sockets();
void Shutdown_Sockets();
int main()
{
Initialize_Sockets();
constexpr int port = 30000;
Sage::Socket socket(30000);
if (socket.Is_Initialized() == false)
{
printf("Socket failed to initialize\n");
return -1;
}
const char data[] = "Hello World!";
socket.Send(Sage::Address(127, 0, 0, 1, port), data, sizeof(data));
while (true)
{
Sage::Address sender;
unsigned char buffer[256];
int bytes_read = socket.Receive(sender, buffer, sizeof(buffer));
if (!bytes_read)
break;
printf("buffer: %s\n", buffer);
}
Shutdown_Sockets();
}
bool Initialize_Sockets()
{
#if PLATFORM == PLATFORM_WINDOWS
WSADATA Wsa_Data;
return WSAStartup(MAKEWORD(2, 2), &Wsa_Data) == NO_ERROR;
#else
return true;
#endif
}
void Shutdown_Sockets()
{
#if PLATFORM == PLATFORM_WINDOWS
WSACleanup();
#endif
}
My socket class
#include "Socket.h"
Sage::Socket::Socket(unsigned short port)
{
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
#if PLATFORM == PLATFORM_WINDOWS
if (handle == INVALID_SOCKET)
{
printf("Failed to create socket: %d\n", WSAGetLastError());
}
else
{
is_created = true;
}
#elif
if (handle <= 0)
{
printf("Failed to create socket\n");
is_created = false;
}
else
{
is_created = true;
}
#endif
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
#if PLATFORM == PLATFORM_WINDOWS
if (bind(handle, (sockaddr*)&address, sizeof(sockaddr_in)) == SOCKET_ERROR)
{
printf("Failed to bind socket: %d\n", WSAGetLastError());
is_bound = false;
}
else
{
is_bound = true;
}
#elif
if (bind(handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
{
printf("failed to bind socket\n");
is_bound = false;
}
else
{
is_bound = true;
}
#endif
#if PLATFORM == PLATFORM_WINDOWS
DWORD non_blocking = 1;
if (ioctlsocket(handle, FIONBIO, &non_blocking) == SOCKET_ERROR)
{
printf("Failed to set socket non-blocking: %d\n", WSAGetLastError());
is_non_blocking = false;
}
else
{
is_non_blocking = true;
}
#elif
int non_blocking = 1;
if (fcntl(handle, F_SETFL, O_NONBLOCK, non_blocking) == -1)
{
printf("Failed to set socket non-blocking\n");
is_non_blocking = false;
}
else
{
is_non_blocking = true;
}
#endif
is_initialized = is_created && is_bound && is_non_blocking;
if (!is_initialized)
{
printf("Failed to initialize socket\n");
}
}
int Sage::Socket::Send(Sage::Address address, const void* packet_data, int packet_size)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address.Get_Address());
addr.sin_port = htons(address.Get_Port());
unsigned int sendto_address = address.Get_Address();
int sent_bytes = sendto(handle, (const char*)packet_data, packet_size, 0, (sockaddr*)&sendto_address, sizeof(sockaddr_in));
#if PLATFORM == PLATFORM_WINDOWS
if (sent_bytes == SOCKET_ERROR)
{
printf("Failed to send packet: %d\n", WSAGetLastError());
return sent_bytes;
}
else if (sent_bytes != packet_size)
{
printf("Failed to send all bytes of packet(%d/%d)\n", sent_bytes, packet_size);
return sent_bytes;
}
#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
if (sent_bytes != packet_size)
{
printf("Failed to send all bytes of a packet(%d/%d)\n", sent_bytes, packet_size);
return sent_bytes;
}
#endif
return sent_bytes;
}
int Sage::Socket::Receive(Sage::Address& sender, void* data, int size)
{
#if PLATFORM == PLATFORM_WINDOWS
typedef int socklen_t;
#endif
sockaddr_in from;
socklen_t from_length = sizeof(from);
int bytes_received = recvfrom(handle, (char*)data, size, 0, (sockaddr*)&from, &from_length);
sender = Sage::Address(from);
return bytes_received;
}
Sage::Socket::~Socket()
{
#if PLATFORM == PLATFORM_WINDOWS
closesocket(handle);
#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX
close(handle);
#endif
}
0xCCCCCCCC is used by by Microsoft's C++ debugging runtime library to mark uninitialised stack memory.
204 is 0xCC.
Clearly you're missing a 0 in your buffer which would signal the end of the data: your output runs into the uninitialised memory.
Of course, don't rely on any of this behavior - your program behavior is undefined, but these sort of things do help to identify the problem.
Reference: https://en.wikipedia.org/wiki/Magic_number_(programming)#Debug_values

Two pairs of TCP server/client sharing same code, but only one client receives messages

I have two pairs of simple TCP server/client, i.e., one client per server, running on Windows:
Servers run in a process (app).
Clients run in the other process.
Servers keep sending heartbeats (a string) to their paired client.
The first pair of server/client run their mainloops in their own threads.
Once the first server/client have shaken hands with the first heartbeat, the second pair of server/client start their mainloops in their own threads.
For this test, they run on the same machine with different ports: 2345 and 2346.
Now my problem
The first client receives its server's heartbeat.
The second client does NOT, although the second server sent out heartbeats without errors.
Here is the server code:
// hello_dualchannel_server.cpp : This file contains the 'main' function.
#include "pch.h"
#include <iostream>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <spdlog/spdlog.h>
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifdef _DEBUG
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif // #if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_DEBUG_ON
#define SPDLOG_TRACE_ON
#define _trace SPDLOG_TRACE
#endif // #ifdef _DEBUG
using namespace spdlog;
SOCKET g_sockFirst = 0;
SOCKET g_sockClientFirst = 0;
std::thread g_threadFirst;
uint32_t g_timeLatestHeartBeatFirst = 0;
SOCKET g_sockSecond = 0;
SOCKET g_sockClientSecond = 0;
std::thread g_threadSecond;
uint32_t g_timeLatestHeartBeatSecond = 0;
void SetupLogger() {
#ifdef _DEBUG
spdlog::set_level(spdlog::level::trace);
spdlog::set_pattern("[%H:%M:%S%z][%^%L%$][%t:%s:%#] %v");
#else
spdlog::set_level(spdlog::level::info);
spdlog::set_pattern("[%H:%M:%S][%^%L%$][%t] %v");
#endif // #ifdef _DEBUG
}
int InitWinSock() {
WORD wVersionRequested;
WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else
printf("The Winsock 2.2 dll was found okay\n");
return 0;
}
bool Init(int host_port, SOCKET* p_sockServer, SOCKET*p_sockClient) {
int err = 0;
int* p_int = 0;
std::string host_name("127.0.0.1");
struct sockaddr_in my_addr;
int addr_size = 0;
sockaddr_in sadr_client;
if (!*p_sockServer) {
*p_sockServer = socket(AF_INET, SOCK_STREAM, 0);
if (*p_sockServer == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error initializing socket: {}", log);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(*p_sockServer, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)
|| (setsockopt(*p_sockServer, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error setting options: {}", log);
free(p_int);
goto FINISH;
}
free(p_int);
info("Server socket is set up.");
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(*p_sockServer, (sockaddr*)&my_addr, sizeof(my_addr)) == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error binding to socket, make sure nothing else is listening on this port: {}", log);
goto FINISH;
}
if (listen(*p_sockServer, 10) == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server Error listening: {}", log);
goto FINISH;
}
info("SUCCESS: Server socket listening ...");
}
info("Server accepting connection ...");
addr_size = sizeof(sockaddr_in);
char sAddress[MAX_PATH];
*p_sockClient = accept(*p_sockServer, (sockaddr*)&sadr_client, &addr_size);
if (*p_sockClient == INVALID_SOCKET) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Server error accepting client connection: {}", log);
// DO NOT close sockets here.
return false;
}
inet_ntop(sadr_client.sin_family, &sadr_client.sin_addr, sAddress, MAX_PATH);
g_timeLatestHeartBeatFirst = GetCurrentTime();
info("SUCCESS: Server accepted client connection.");
return true;
FINISH:
closesocket(*p_sockServer);
return false;
}
bool IsConnected(uint32_t timeLatestHeartBeat) {
// CAUTION: denser than client for sure catch
const unsigned long ConnTimeoutMs = 300;
auto cur = GetCurrentTime();
auto latest = timeLatestHeartBeat;
return cur - latest < ConnTimeoutMs;
}
bool StayInTouch(const char* name, SOCKET* pSockClient, uint32_t* pTimeLatestHeartBeat) {
if (IsConnected(*pTimeLatestHeartBeat))
return true;
char heartBeat[] = "biku";
int nBytesSent = 0;
int flags = 0;
int res = send(*pSockClient, heartBeat, sizeof(heartBeat), flags);
if (res == SOCKET_ERROR) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("{}: Server failed to send heartbeat: {}, Windows error: {}", name, log, GetLastError());
return false;
}
else if (res == 0) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("{}: Server sent zerobyte heartbeat: {}", name, log);
return false;
}
debug("{}: Heartbeat sent: {}", name, heartBeat);
*pTimeLatestHeartBeat = GetCurrentTime();
return true;
}
void Close(SOCKET* pSock) {
closesocket(*pSock);
*pSock = 0;
}
bool Connect() {
if (g_threadFirst.joinable()) {
warn("FirstTunnel already running. Skipped.");
return true;
}
g_threadFirst = std::thread([&]() {
bool isConnected = false;
while (true) {
while (!isConnected) {
isConnected = Init(2345, &g_sockFirst, &g_sockClientFirst);
}
isConnected = StayInTouch("FirstTunnel", &g_sockClientFirst, &g_timeLatestHeartBeatFirst);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
if (!g_threadSecond.joinable()) {
g_threadSecond = std::thread([&]() {
while (true) {
while (!isConnected) {
isConnected = Init(2346, &g_sockSecond, &g_sockClientSecond);
}
isConnected = StayInTouch("SecondTunnel", &g_sockClientSecond, &g_timeLatestHeartBeatSecond);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
}
info("SecondTunnel quitting...");
Close(&g_sockSecond);
});
}
}
info("FirstTunnel quitting...");
Close(&g_sockFirst);
});
while (true) {
//info("main thread ...");
Sleep(3000);
}
return g_threadFirst.joinable() ? true : false;
}
int main() {
SetupLogger();
info("Hello World!\n");
if (InitWinSock()) {
critical("Failed to initialize Window socket. Aborted.");
}
Connect();
if (g_threadSecond.joinable()) {
g_threadSecond.join();
}
if (g_threadFirst.joinable()) {
g_threadFirst.join();
}
WSACleanup();
info("Bye!");
}
Here is the client code
// hello_dualchannel_client.cpp : This file contains the 'main' function.
//
#include "pch.h"
#include <iostream>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <spdlog/spdlog.h>
#define SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifdef _DEBUG
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#endif // #if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_DEBUG_ON
#define SPDLOG_TRACE_ON
#define _trace SPDLOG_TRACE
#endif // #ifdef _DEBUG
using namespace spdlog;
SOCKET g_sockFirst = 0;
std::thread g_threadFirst;
uint32_t g_timeLatestHeartBeatFirst;
SOCKET g_sockSecond = 0;
std::thread g_threadSecond;
uint32_t g_timeLatestHeartBeatSecond;
void SetupLogger() {
#ifdef _DEBUG
spdlog::set_level(spdlog::level::trace);
spdlog::set_pattern("[%H:%M:%S%z][%^%L%$][%t:%s:%#] %v");
#else
spdlog::set_level(spdlog::level::info);
spdlog::set_pattern("[%H:%M:%S][%^%L%$][%t] %v");
#endif // #ifdef _DEBUG
}
int InitWinSock() {
WORD wVersionRequested;
WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else
printf("The Winsock 2.2 dll was found okay\n");
return 0;
}
bool Init(int host_port, SOCKET* p_sock) {
int err = 0;
int* p_int = 0;
std::string host_name("127.0.0.1");
struct sockaddr_in my_addr;
char handshake[] = "hello";
//int nBytesSent;
if (!*p_sock) {
*p_sock = socket(AF_INET, SOCK_STREAM, 0);
if (*p_sock == -1) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error initializing socket {}", log);
goto FINISH;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if ((setsockopt(*p_sock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1)
|| (setsockopt(*p_sock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1)) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error setting options {}", log);
free(p_int);
goto FINISH;
}
free(p_int);
info("SUCCESS: Client socket is set up.");
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
inet_pton(my_addr.sin_family, host_name.c_str(), &my_addr.sin_addr);
if (connect(*p_sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client Error connecting socket {}", log);
Sleep(1000);
goto FINISH;
}
/*nBytesSent = send(g_sockFirst, handshake, sizeof(handshake), 0);
if (nBytesSent <= 0) {
char log[MAX_PATH];
strerror_s(log, MAX_PATH, errno);
error("Client error sending handshake: {}", log);
goto FINISH;
}*/
g_timeLatestHeartBeatFirst = GetCurrentTime();
info("SUCCESS: Client connected to server.");
return true;
FINISH:
closesocket(*p_sock);
*p_sock = 0;
return false;
}
bool IsConnected(uint32_t timeLatestHeartBeat) {
const unsigned long ConnTimeoutMs = 3000;
auto cur = GetCurrentTime();
auto latest = timeLatestHeartBeat;
//if (cur - latest > ConnTimeoutMs)
//{
// debug("cur: {}, late: {}", cur, latest);
//}
return cur - latest < ConnTimeoutMs;
}
bool StayInTouch(const char* name, SOCKET* pSock, uint32_t* pTimeLatestHeartBeat) {
// Client checks inbox right away and measure timeout later.
char heartBeat[MAX_PATH] = { 0 };
// CAUTION: min 100ms required for receiving heartbeat.
//const uint32_t TimeoutMS = 100;
int flags = 0;
int nBytesRecved = recv(*pSock, heartBeat, sizeof(heartBeat), flags);
bool gotHeartbeat = nBytesRecved > 0;
if (gotHeartbeat) {
debug("{}: Heartbeat received: {}", name, heartBeat);
*pTimeLatestHeartBeat = GetCurrentTime();
}
return IsConnected(*pTimeLatestHeartBeat);
}
void Close(SOCKET* pSock) {
closesocket(*pSock);
*pSock = 0;
}
bool Connect() {
if (g_threadFirst.joinable()) {
warn("FirstTunnel already running. Skipped.");
return true;
}
g_threadFirst = std::thread([&]() {
bool isConnected = false;
while (true) {
while (!isConnected) {
isConnected = Init(2345, &g_sockFirst);
}
isConnected = StayInTouch("FirstTunnel", &g_sockFirst, &g_timeLatestHeartBeatFirst);
if (!isConnected) {
// We don't close as client.
// We keep connecting
Close(&g_sockFirst);
error("About to reconnect ...");
continue;
}
if (!g_threadSecond.joinable()) {
g_threadSecond = std::thread([&]() {
while (true) {
while (!isConnected) {
isConnected = Init(2346, &g_sockSecond);
}
isConnected = StayInTouch("SecondTunnel", &g_sockSecond, &g_timeLatestHeartBeatSecond);
if (!isConnected) {
// We don't close as client.
// We keep connecting
error("About to reconnect ...");
Sleep(1000);
continue;
}
}
info("SecondTunnel quitting...");
Close(&g_sockSecond);
});
}
}
info("FirstTunnel quitting.");
Close(&g_sockFirst);
});
while (true) {
//info("main thread ...");
Sleep(3000);
}
return g_threadFirst.joinable() ? true : false;
}
int main() {
SetupLogger();
info("Hello World!\n");
if (InitWinSock()) {
critical("Failed to initialize Window socket. Aborted.");
}
Connect();
if (g_threadSecond.joinable()) {
g_threadSecond.join();
}
if (g_threadFirst.joinable()) {
g_threadFirst.join();
}
WSACleanup();
info("Bye!");
}
The main connection logic is in the function Connect().
I'd appreciate tips on where I was wrong.
To run the code as is, you need one dependency spdlog
vcpkg install spdlog:x64-Windows
You can also replace all the spdlog-based logging code with your own.
UPDATE
Observation #1
I stepped into the code and confirmed
All the loops are running. So all the threads are spawned.
No redundant threads are spawned due to the joinable() guard.
The only failure point is the recv call of the second client.
So conclusion
No firewalls
No redundant threads
Both threads run on the client and server sides by design.
Observation #2
While running the server and client programs and having let the problem happen, I tried
Keep both programs open.
Run netcat (NMap's netcat port) like this C:\Apps\Nmap\ncat.exe 127.0.0.1 2346
This actually help fix things. It tells me that there is a connection problem, while I could definitely step into the client code and see that the connection is still there.
Observation #3
After I leave breakpoints in only the second connection code of the client program, and run the program, I could not step out into the first connection code. Note that they are in separate threads.
Leaving breakpoints in both connections, and quickly step over between them, I could keep the stepping going without getting trapped in only one thread. This is when I notice that the client starts receiving the messages it should.
So I suspect that there is a threading issue there. If that's the problem, How to fix this then?
I found the problem myself. It was a stupid bug on my part:
The two threads share a state by mistake: isConnected. So the original programs keep kicking each other after one of them gains a new connection or heartbeat. They should have used different states for that.
To give more detail: isConnected, which is initialized by g_threadFirst, falls through the closure of g_threadSecond's anonymous function.

Function Timeout not working as expected

I'm just starting to learn the C++ and I would like to test what I'm learning on a Raspberry. My project, for now, consist to transfert data from a Raspberry to another through WiFi. This works very well but the problem comes when the Raspberry client disconnects from WiFi. At this time, the Server wait indefinitely. So to avoid that, I search on Google to have a Timeout function and here it is:
class Timeout;
static Timeout * global_timeout_instance = 0;
class Timeout {
public:
int m_timeout;
jmp_buf env;
Timeout(int timeout) : m_timeout(timeout) {
if (global_timeout_instance) {
throw "Timeout already in use";
}
global_timeout_instance = this;
}
~Timeout() {
stop();
global_timeout_instance = 0;
}
static void alarm_handler(int signum) {
longjmp(global_timeout_instance->env, 1);
}
void start() {
Timeout * ptr = this;
if (setjmp(env) != 0) {
// Don't do anything except throw here, since the state
// is... funky...
printf("Alarm fired: %p\n", ptr);
throw global_timeout_instance;
}
signal(SIGALRM, alarm_handler);
alarm(2);
}
void stop() {
alarm(0);
}
};
So this function works very well because when the connection is lost, the program stop directly. But I would like to do some action after the loss of connection. So here is my entire code:
#include <exception>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstdio>
#include <setjmp.h>
#include <signal.h>
class Timeout;
static Timeout * global_timeout_instance = 0;
class Timeout {
public:
int m_timeout;
jmp_buf env;
Timeout(int timeout) : m_timeout(timeout) {
if (global_timeout_instance) {
throw "Timeout already in use";
}
global_timeout_instance = this;
}
~Timeout() {
stop();
global_timeout_instance = 0;
}
static void alarm_handler(int signum) {
longjmp(global_timeout_instance->env, 1);
}
void start() {
Timeout * ptr = this;
if (setjmp(env) != 0) {
// Don't do anything except throw here, since the state
// is... funky...
printf("Alarm fired: %p\n", ptr);
throw global_timeout_instance;
}
signal(SIGALRM, alarm_handler);
alarm(2);
}
void stop() {
alarm(0);
}
};
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char client_message[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
//accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
//Receive a message from client
while(1)
{
try
{
Timeout timeout(1);
timeout.start();
read_size = recv(client_sock , client_message , 2000 , MSG_WAITALL);
}
catch(Timeout * t)
{
printf("Timeout detected\n");
// Do some action later
}
printf("%d\n", read_size);
if(client_message !="")
{
puts(client_message);
}
else
{
printf("Not Ok");
}
memset(client_message, 0, sizeof(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
return 0;
}
I don't know how I can do some action after the Timeout.
Here is the message I received when the program stop:
Alarm fired: 0x7eff8c40 terminate called after throwing an instance of
'Timeout*' Aborted
Can someone help me on this problem?
Thank you.
Kevin

Multiple Broadcast Reception on Same port but different interfaces

I'm trying to build a little personal DHCP server to serve a specific scope if the broadcast is received on eth0 and another if received on wlan0 but I can't bind more than a single interface on the same address:port combination (255.255.255.255:67)
I heard about SO_REUSABLE but I have no idea about how to implement it and if of course it's the good way to do it
Actually this is my code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <vector>
#define BUFLEN 1024
#define PORT 67
using namespace std;
char *ipAddrFromInterface(char *apInterfaceName) //this function is not from me
{
return "255.255.255.255";
/*char *if_name = (char *) apInterfaceName;
struct ifreq ifr;
size_t if_name_len = strlen(if_name);
if(if_name_len < sizeof(ifr.ifr_name))
{
memcpy(ifr.ifr_name, if_name, if_name_len);
ifr.ifr_name[if_name_len] = 0;
}
else
printf("interface name is too long\n");
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd == -1)
printf("A => %s\n", strerror(errno));
if(ioctl(fd, SIOCGIFADDR, &ifr) == -1)
{
int temp_errno = errno;
close(fd);
printf("B => %s\n", strerror(temp_errno));
}
if(ioctl(fd, SIOCGIFADDR, &ifr) == -1)
{
int temp_errno = errno;
close(fd);
printf("C => %s\n", strerror(temp_errno));
}
close(fd);
struct sockaddr_in* ipaddr = (struct sockaddr_in*) &ifr.ifr_addr;
return inet_ntoa(ipaddr->sin_addr);*/
}
struct socketData
{
int sock;
sockaddr_in socket;
char *interfaceName;
};
void print(int i)
{
printf("%d\n", i);
fflush(stdout);
}
void server_receive_thread(vector<char*> aInterfaceList)
{
int socketIndex = 0;
struct sockaddr_in localSock;
int socketDescriptor; int socketLength;
vector<socketData> aSockets;
for( ; socketIndex < aInterfaceList.size(); socketIndex++)
{
socketData socketD;
char *apInterfaceName = aInterfaceList.at(socketIndex);
if((socketDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("can't listen on interface %s... sleeping\n", apInterfaceName);
}
else
{
memset(&localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(PORT);
inet_aton(ipAddrFromInterface(apInterfaceName), &localSock.sin_addr);
setsockopt(socketDescriptor, SOL_SOCKET, SO_BINDTODEVICE, apInterfaceName, sizeof(apInterfaceName));
if(bind(socketDescriptor, (struct sockaddr *) &localSock, sizeof(localSock)) == -1)
{
printf("can't bind interface %s to listen on port %d... sleeping\n", apInterfaceName, PORT);
}
else
{
printf("bound to interface %s on port %d\n", apInterfaceName, PORT);
socketD.sock = socketDescriptor;
socketD.socket = localSock;
socketD.interfaceName = apInterfaceName;
aSockets.push_back(socketD);
}
}
}
fd_set master;
int fdMax = -1;
while(1)
{
FD_ZERO(&master);
for(int iSock = 0; iSock < aSockets.size(); iSock++)
{
socketData d = aSockets.at(iSock);
FD_SET(d.sock, &master);
if(d.sock > fdMax)
fdMax = d.sock;
}
printf("fdmax is : ");
print(fdMax);
if(select(fdMax + 1, &master, NULL, NULL, NULL) == -1)
print(2);
print(200);
for(int iSock = 0; iSock < aSockets.size(); iSock++)
{
socketData d = aSockets.at(iSock);
if(FD_ISSET(d.sock, &master))
print(3);
}
print(1);
}
}
int main()
{
std::vector<char*> interfaceList;
interfaceList.push_back("wlan0");
interfaceList.push_back("eth0");
server_receive_thread(interfaceList);
return 0;
}
You don't need a socket per interface. Just bind a single socket to 0.0.0.0 and the desired port. Then it will receive via all interfaces. You certainly can't, and don't need to, bind to 255.255.255.255.
Or, bind it to the single IP address that is connected to the scope you want to serve.

socket programming( server and client on the same computer) something wrong with connection

I'm new to socket programming and I have this client that tries to connect to a server on the same computer. But the server hangs there after bind or accept—cause bind seems to be right but no output. I know that the server works because another client can connect just fine and the client seems to have done that. What causes the server to not see this incoming connection? I'm at the end of my wits here.
And I haven't been used to programming on Mac, so thank you so much for your patience if I have made some foolish mistakes.
My code is as follows:
server.cpp
using namespace std;
#include<iostream>
#include <netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define PORT 8888
#define BACKLOG 20
//#define DEST_IP "127.0.0.1"
int process_conn_server(int s)
{
ssize_t size =0;
char buffer[1024];
for( ; ; )
{
size = read(s,buffer,1024);
if(size == 0)
{
return 0;
}
}
sprintf(buffer, "%d bytes altogether\n", (int)size);
write(s, buffer,strlen(buffer)+1);
return 0;
}
int main(int argc,char *argv[])
{
//cout<<"?";
int ss, sc, r, err;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int opt=1;
pid_t pid;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
ss = socket(AF_INET, SOCK_STREAM, 0);
if(ss<0)
{
cout<<"[process infro]socket error"<<endl;
return -1;
}
cout<<"[process infro]socket successful"<<endl;
r = setsockopt(ss, SOL_SOCKET,SO_REUSEADDR, (void*)&opt,sizeof(opt));
if (r == -1)
{
perror("setsockopt(listen)");
return 0;
}
cout<<"[process infro]sockopt successful"<<endl;
cout<<"?";
err = bind(ss, (struct sockaddr*) &server_addr, sizeof( server_addr));
cout<<"err";
if(err < 0)
{
cout<<"[process infro]bind error"<<endl;
return -1;
}
cout<<"[process infro]bind successful";
err=listen(ss, BACKLOG);
if(err <0)
{
cout<<"[process infro]listen error"<<endl;
return -1;
}
cout<<"[process infro]lisen successful";
for( ; ; )
{
int addrlen = sizeof(struct sockaddr);
sc = accept(ss, (struct sockaddr*)&client_addr, (socklen_t *)&addrlen);
if(sc < 0)
{
continue;
}
pid = fork();
if (pid == 0)
{
close(ss);
process_conn_server(sc);
}
else
{
close(sc);
}
}
//opt=0;
//setsockopt(ss,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(len));
}
client.cpp
using namespace std;
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <time.h>
#include <arpa/inet.h>
#include <fstream.h>
#define PORT 8888
#define DEST_IP "127.0.0.1"
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024];
//read from the file to be sent
fstream outfile("programm.txt",ios::in|ios::out);
if (outfile.fail())
{
printf("[process infro]cannot open the file to be sent\n");
return ;
}
printf("[process infro]successfully open the file to be sent\n");
while(!outfile.eof())
{
outfile.getline(buffer,1025,'\n');
write(s,buffer,1024);
size = read(s, buffer, 1024);
if(size = 0)
{
return ;
}
//write to the server
write(s,buffer,size);
//get response from the server
size=read(s,buffer,1024);
write(1,buffer,size);
}
outfile.close(); //关闭文件
}
int main(int argc,char *argv[])
{
int s;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(DEST_IP);
server_addr.sin_port = htons(PORT);
s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
{
cout<<"[process infro]socke error"<<endl;
return -1;
}
cout<<"[process infro] socket built successfully\n";
//inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
cout<<"[process infor] connected\n";
process_conn_client(s);
close(s);
return 0;
}
This may be unrelated.... but it won't fit in a comment...
In your server you do this:
int process_conn_server(int s)
{
ssize_t size =0;
char buffer[1024];
for( ; ; )
{
// keep reading until read returns 0
size = read(s,buffer,1024);
if(size == 0)
{
return 0;
}
}
sprintf(buffer, "%d bytes altogether\n", (int)size);
write(s, buffer,strlen(buffer)+1);
return 0;
}
In your client you do this:
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024];
//read from the file to be sent
fstream outfile("programm.txt",ios::in|ios::out);
if (outfile.fail())
{
printf("[process infro]cannot open the file to be sent\n");
return ;
}
printf("[process infro]successfully open the file to be sent\n");
while(!outfile.eof())
{
outfile.getline(buffer,1025,'\n');
// write to server?
write(s,buffer,1024);
// read from server?
size = read(s, buffer, 1024);
if(size = 0)
{
return ;
}
//write to the server
write(s,buffer,size);
//get response from the server
size=read(s,buffer,1024);
write(1,buffer,size);
}
outfile.close();
}
It's a bit hard to follow because of your variable names, but it looks like your client is working under the assumption that your server will send back a response for every chunk of data received, which isn't the case. You server doesn't appear to have changed the accepted socket to non-blocking, so it's going to block on the read call until there is some data to read (it's never going to get 0)...
Are you sure it's failing before this point? Do you have some sample output?
Aso, in your call to accept, you pass addrlen...
int addrlen = sizeof(struct sockaddr);
I think this should be:
int addrlen = sizeof(struct sockaddr_in); /* sizeof(client_addr) */