Socket Handle Read Is never read In Ns3 - c++

I stayed many days to find where the error is and I'm stuck.Can anyone help me please.
MY application is a clustering program in NS3 that was written from one else and free to anyone.
The program is run and no errors and print messages but always the number of neighbors in every Cluster Head CH is zero, this mean that the hellow messages are not reach every node and every node consider itself as cluster head because it dosn't see any neighbor node!. every node (vehicle) has two sockets one for send data m_socket and one for listening m_socketlistening, the code is:
if (!m_socket)
{
// TypeId::LookupByName ("ns3::UdpSocketFactory
TypeId m_tid = TypeId::LookupByName("ns3::UdpSocketFactory");
//m_socket = Socket::CreateSocket(GetNode() , TypeId::LookupByName("ns3::UdpSocketFactory"));
m_socket = Socket::CreateSocket(GetNode(), m_tid);
// i added the down line
// InetSocketAddress remote = InetSocketAddress(Ipv4Address::GetBroadcast(),80);
if (Inet6SocketAddress::IsMatchingType(m_peer))
{
m_socket->Bind6();
}
else if (InetSocketAddress::IsMatchingType(m_peer)
|| PacketSocketAddress::IsMatchingType(m_peer))
{
m_socket->Bind();
}
m_socket->SetAllowBroadcast(true);
m_socket->ShutdownRecv();
m_socket->SetConnectCallback(
MakeCallback(&V2vControlClient::ConnectionSucceeded, this),
MakeCallback(&V2vControlClient::ConnectionFailed, this));
//m_socket->Connect(Ipv4Address::GetBroadcast());
m_socket->Connect(m_peer);
}
now this is a part pf the listening socket creation
if (!m_socketListening)
{
NS_LOG_UNCOND("\n ...creating socket muhsen...");
m_socketListening = Socket::CreateSocket(GetNode(), m_tidListening);
m_socketListening->Bind(m_peerListening);
m_socketListening->Listen();
m_socketListening->ShutdownSend();
if (addressUtils::IsMulticast(m_peerListening))
{
Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketListening);
if (udpSocket)
{
// equivalent to setsockopt (MCAST_JOIN_GROUP)
udpSocket->MulticastJoinGroup(0, m_peerListening);
}
else
{
NS_FATAL_ERROR("Error: joining multicast on a non-UDP socket");
}
}
}
m_socketListening->SetRecvCallback(MakeCallback(&V2vControlClient::HandleRead, this));
m_socketListening->SetAcceptCallback(
MakeNullCallback<bool, Ptr<Socket>, const Address &>(),
MakeCallback(&V2vControlClient::HandleAccept, this));
m_socketListening->SetCloseCallbacks(
MakeCallback(&V2vControlClient::HandlePeerClose, this),
MakeCallback(&V2vControlClient::HandlePeerError, this));
void V2vControlClient::HandleRead (Ptr<Socket> socket)
{
NS_LOG_UNCOND("\n this message is never executed..");
NS_LOG_FUNCTION (this << socket);
Ptr<Packet> packet;
Address from;
while ((packet = socket->RecvFrom(from)))
{
if (packet->GetSize() == 0)
{ //EOF
break;
}
When i run the application the first statement after the HandleRead Function which is
NS_LOG_UNCOND("\n this message is never executed..");
is never printed when run the program, this means that the handle read is never executed.
Any help is very appreciate!

Related

Writing Data to Poll Invalid Socket Causes Uncatchable Exception

I am working on a game server that uses sockets and implemented a polling function that sends the message "[POLL]" over all player sockets in a lobby every second to notify the player clients that their connection is still alive.
If I disconnect on the client-side the socket is still polled with no errors, however, if I create a new connection with the same client (Gets a new FD and is added to the map as a second player), the whole server crashes without any exceptions/warnings/messages when it attempts to write to the previous socket FD. My call to Write on the socket is wrapped in a try/catch that doesn't catch any exceptions and, when debugging using gdb, I am not given any error messaging.
This is the Socket Write function:
int Socket::Write(ByteArray const& buffer)
{
if (!open)
{
return -1;
}
// Convert buffer to raw char array
char* raw = new char[buffer.v.size()];
for (int i=0; i < buffer.v.size(); i++)
{
raw[i] = buffer.v[i];
}
// Perform the write operation
int returnValue = write(GetFD(), raw, buffer.v.size()); // <- Crashes program
if (returnValue <= 0)
{
open = false;
}
return returnValue;
}
And this is the Poll function (Players are stored in a map of uint -> Socket*):
/*
Polls all connected players to tell them
to keep their connections alive.
*/
void Lobby::Poll()
{
playerMtx.lock();
for (auto it = players.begin(); it != players.end(); it++)
{
try
{
if (it->second != nullptr && it->second->IsOpen())
{
it->second->Write("[POLL]");
}
}
catch (...)
{
std::cout << "Failed to write to " << it->first << std::endl;
}
}
playerMtx.unlock();
}
I would expect to see the "Failed to write to " message but instead the entire server program exits with no messaging. What could be happening here?
I was unable to find a reason for the program crashing in the call to write but I was able to find a workaround.
I perform a poll operation on the file descriptor prior to calling write and I query the POLLNVAL event. If I receive a nonzero value, the FD is now invalid.
// Check if FD is valid
struct pollfd pollFd;
pollFd.fd = GetFD();
pollFd.events = POLLNVAL;
if (poll(&pollFd, 1, 0) > 0)
{
open = false;
return -1;
}

Let recv() only the previous accepted socket

I am using this server application:
I'd like to add some conditions to FD_ISSET() before recv():
if (`client's socket` was the previous `accepted socket`) {
canRecv = TRUE;
} else {
canRecv = FALSE;
}
This is my idea of ​​program functionality:
recv only from the previous accepted socket
Wait for the communication to end
FD_CLR()
I don't know how to:
loop through each fd from select()
let only one recv()
return the others to the queue of select()
I use simple example from IBM Knowledge Center:
https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzab6/xnonblock.htm
You could create a std::vector<int> sockets; to keep your sockets. Checking if it's the latest you added will then be done by just checking if(current_socket == sockets[sockets.size()-1]) ...
Here's an example with a helper class to keep a list of your sockets and function for waiting on activity.
#include <cerrno>
#include <cstring>
#include <utility>
#include <vector>
constexpr unsigned other_socket = 0b00;
constexpr unsigned server_socket = 0b01;
constexpr unsigned latest_addition = 0b10;
class SocketList {
public:
explicit SocketList(int server) : readfds{} { add(server); }
void add(int s) {
sockets.push_back(s);
FD_SET(s, &readfds);
if(s > max_fd) max_fd = s;
}
// return the ready sockets and a state for each
std::vector<std::pair<int, unsigned>> wait() {
int ready_sockets;
do {
ready_sockets = select(max_fd + 1, &readfds, nullptr, nullptr, nullptr);
} while(ready_sockets == -1 && errno == EINTR); // retry if interrupted
// throw if an error occured
if(ready_sockets == -1) throw std::runtime_error(std::strerror(errno));
std::vector<std::pair<int, unsigned>> result;
// loop through each fd used in the select()
for(int s : sockets) {
if(FD_ISSET(s, &readfds)) {
auto x = other_socket;
if(s == sockets[0]) x |= server_socket;
if(s == sockets[sockets.size() - 1]) x |= latest_addition;
result.emplace_back(s, x);
}
}
return result;
}
private:
int max_fd = 0;
fd_set readfds;
std::vector<int> sockets;
};
It can be used like this:
int server = socket(...);
SocketList ss(server);
// all sockets in result are ready
auto result = ss.wait();
for(auto [sock, state] : result) {
if(state & server_socket) {
// do server things on sock
} else if(state & latest_addition) {
// do stuff if sock was the latest addition
} else {
// do this if sock is not the server socket or the latest addition
}
}
recv only from the previous accepted socket
Wait for the communication to end
FD_CLR()
For that you really don't need select. Just recv directly on the previously accepted socket. This is usually not a good behavior of a server that is supposed to server many clients simultaneously since a bad client could connect without sending anything, and that would stop the server from responding to any new clients - until the bad client decides to disconnect (if that ever happens).
I don't know how to:
1. loop through each fd from select()
That is shown in the code above.
let only one recv()
When you have the result vector in the example above, you can loop through them and only keep the part dealing with latest_addition:
if(state & latest_addition) {
// do stuff if sock was the latest addition
}
return the others to the queue of select()
The state of the other ready sockets in result will remain unchanged if you don't read from them, so they are returned automatically. This also means that the next select will return immediately if you don't read from all fds that are ready, so the program will spin really fast until there's some action on the latest added socket again, effectively making this a polling program and the select is sort of useless.

Cant put Accept() (CSocket) in its own thread

I use blocking server-client to do a FTP homework.
But i got stuck when try to put Accept into a thread. (Everytime i run the CServer , it crahses and shut down)
Anyone know the answer or can suggest me sth else. i really appreciate it.
I really want to use blocking and CSocket ,so dont't suggest me non-blocking
I also took a look at p_thread, but i still won't if any chance my code works
void CServerDlg::OnBnClickedListen()
{
// TODO: Add your control notification handler code here
if (listen.Create(PORT, SOCK_STREAM, _T("127.0.0.1")) == 0) {
showMessage("Failed to init socket");
listen.GetLastError();
return;
}
else {
if (listen.Listen(1) == FALSE) {
showMessage("Can't listen to the port");
listen.Close();
return;
}
}
connectThread = thread(&CServerDlg::ThreadMain, this);
}
void CServerDlg::ThreadMain() {
int cnt = -1;
CSocket* client;
while (1)
{
client = new CSocket();
if (listen.Accept(*client)) // it crashes everytime i got here
{
cnt++;
char * id = Converter::StringToChar(Converter::NumberToString(*client));
clients.push_back(client);
ClientId.push_back(id);
showMessage("Found a connection with client " + Converter::CharToString(id));
/*
Thread here
*/
threads.push_back(thread(&CServerDlg::ThreadProc, this, cnt));
}
else break;
}
}

Sockets - keeping a socket open after data transfer

I have written simple server/client programs, in which the client sends some hardcoded data in small chunks to the server program, which is waiting for the data so that it can print it to the terminal. In the client, I'm calling send() in a loop while there is more data to send, and on the server, I'm doing the same with read(), that is, while the number of bytes returned is > 0, I continue to read.
This example works perfectly if I specifically call close() on the client's socket after I've finished sending, but if I don't, the server won't actually exit the read() loop until I close the client and break the connection. On the server side, I'm using:
while((bytesRead = read(socket, buffer, BUFFER_SIZE)) > 0)
Shouldn't bytesRead be 0 when all the data has been received? And if so, why will it not exit this loop until I close the socket? In my final application, it will be beneficial to keep the socket open between requests, but all of the sample code and information I can find calls close() immediately after sending data, which is not what I want.
What am I missing?
When the other end of the socket is connected to some other network system halfway around the world, the only way that the receiving socket knows "when all the data has been received" is precisely when the other side of the socket is closed. That's what tells the other side of the socket that "all the data has been received".
All that a socket knows about is that it's connected to some other socket endpoint. That's it. End of story. The socket has no special knowledge of the inner workings of the program that has the other side of the socket connection. Nor should it know. That happens to be the responsibility of the program that has the socket open, and not the socket itself.
If your program, on the receiving side, has knowledge -- by the virtue of knowing what data it is expected to receive -- that it has now received everything that it needs to receive, then it can close its end of the socket, and move on to the next task at hand.
You will have to incorporate in your program's logic, a way to determine, in some form or fashion, that all the data has been transmitted. The exact nature of that is going to be up to you to define. Perhaps, before sending all the data on the socket, your sending program will send in advance, on the same socket, the number of bytes that will be in the data to follow. Then, your receiving program reads the number of bytes first, followed by the data itself, and then knows that it has received everything, and can move on.
That's one simplistic approach. The exact details is up to you. Alternatively, you can also implement a timeout: set a timer and if any data is not received in some prescribed period of time, assume that there is no more.
You can set a flag on the recv call to prevent blocking.
One way to detect this easily is to wrap the recv call:
enum class read_result
{
// note: numerically in increasing order of severity
ok,
would_block,
end_of_file,
error,
};
template<std::size_t BufferLength>
read_result read(int socket_fd, char (&buffer)[BufferLength], int& bytes_read)
{
auto result = recv(socket_fd, buffer, BufferLength, MSG_DONTWAIT);
if (result > 0)
{
return read_result::ok;
}
else if (result == 0)
{
return read_result::end_of_file;
}
else {
auto err = errno;
if (err == EAGAIN or err == EWOULDBLOCK) {
return read_result::would_block;
}
else {
return read_result ::error;
}
}
}
One use case might be:
#include <unistd.h>
#include <sys/socket.h>
#include <cstdlib>
#include <cerrno>
#include <iostream>
enum class read_result
{
// note: numerically in increasing order of severity
ok,
would_block,
end_of_file,
error,
};
template<std::size_t BufferLength>
read_result read(int socket_fd, char (&buffer)[BufferLength], int& bytes_read)
{
auto result = recv(socket_fd, buffer, BufferLength, MSG_DONTWAIT);
if (result > 0)
{
return read_result::ok;
}
else if (result == 0)
{
return read_result::end_of_file;
}
else {
auto err = errno;
if (err == EAGAIN or err == EWOULDBLOCK) {
return read_result::would_block;
}
else {
return read_result ::error;
}
}
}
struct keep_reading
{
keep_reading& operator=(read_result result)
{
result_ = result;
}
const operator bool() const {
return result_ < read_result::end_of_file;
}
auto get_result() const -> read_result { return result_; }
private:
read_result result_ = read_result::ok;
};
int main()
{
int socket; // = open my socket and wait for it to be connected etc
char buffer [1024];
int bytes_read = 0;
keep_reading should_keep_reading;
while(keep_reading = read(socket, buffer, bytes_read))
{
if (should_keep_reading.get_result() != read_result::would_block) {
// read things here
}
else {
// idle processing here
}
}
std::cout << "reason for stopping: " << should_keep_reading.get_result() << std::endl;
}

why shutdown on udp socket blocks?

I'm writing a UDP server application for windows desktop/server.
My code uses the WSA API suggested by windows the following way (This is my simplified receivePacket method):
struct Packet
{
unsigned int size;
char buffer[MAX_SIZE(1024)];
}
bool receivePacket(Packet packet)
{
WSABUFFER wsa_buffer[2];
wsa_buffer[0].buf = &packet.size;
wsa_buffer[0].len = sizeof(packet.size);
wsa_buffer[1].buf = packet.buffer;
wsa_buffer[1].len = MAX_SIZE;
bool retval = false;
int flags = 0;
int recv_bytes = 0;
inet_addr client_addr;
int client_addr_len = sizeof(client_addr);
if(WSARecvFrom(_socket, wsa_buffer, sizeof(wsa_buffer)/sizeof(wsa_buffer[0]), &bytes_recv, &flags, (sockaddr *)&client_addr, &client_addr_len, NULL, NULL) == 0)
{
//Packet received successfully
}
else
{
//Report
}
}
Now, when I'm trying to close my application gracefully, not network-wise, but rather application-wise (going through all the d'tors and stuff), i'm trying to unblock this call.
To do this, I call the shutdown(_socket, SD_BOTH) method. Unfortunately, the call to shutdown itself BLOCKS!
After reading every possible page in the MSDN, I didn't find any reference to why this happens, other ways of attacking the problem or any way out.
Another thing I checked was using the SO_RCVTIMEO. Surprisingly, this sockopt didn't work as expected as well.
Is there any problem with my code/approach?
Did you run shutdown on duplicated handle? Shutdown on the same handle will wait any active operation on this handle to complete.