Set sockopt of QTcpSocket - c++

I am creating a Linux C++/Qt5 app which opens a TCP socket for an outbound connection (to a remote server). I create a QTcpSocket and then try to set sockopt options as follows:
m_tcpSocket = new QTcpSocket(this);
int fd = m_tcpSocket->socketDescriptor();
int enableKeepAlive = 1; // Enable
if ( setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive)) != 0)
reportsockoptError("SOL_SOCKET","SO_KEEPALIVE");
Unfortunately my setsockopt is failing with 'Bad file descriptor' error, because m_tcpSocket->socketDescriptor() is returning -1. How do I get the socket descriptor for an outbound socket before it connects? Or do I have to do this AFTER connect? (which seems to contract what I understand from the Qt docs)
The above works fine for a listening socket (QTcpServer)....just not QTcpSocket.

From the QAbstractSocket documentation
The socket descriptor is not available when QAbstractSocket is in
UnconnectedState.
So, before calling socketDescriptor, you should change the TCP socket internal state. In the case of a client socket, you probably need to connect it to a server, thus passing it to ConnectedState.

Related

Setting up sockets for distributed system communication

I am writing client/server distributed instance for chat implementation. I want each instance to be capable of being server and client at the same time, so I am trying to assign both physical address (using bind, so other nodes could connect to node) and remote address (using connect, so the node could communicate with others). As far as I know this is impossible by sockets programming because bind/connect function can be used only once in a process. But if I want to send and receive messages (using sockets by send/recv functions) I don't see other possibility. Could you please tell me how to achieve mentioned above functionality (exchanging message through sockets by send/recv)? I am getting error (connect: Transport endpoint is already connected) if I try to use connect function after bind function like this:
if((*socket_handler = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
error("socket");
}
struct sockaddr_in socket_address;
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = INADDR_ANY;
socket_address.sin_port = htons(port);
if(bind(*socket_handler, (struct sockaddr*)&socket_address, sizeof(socket_address)) == -1) {
error("bind");
}
if(listen(*socket_handler, 5) == -1) {
error("listen");
}
if (port == port_to_connect) {
return;
}
// is it ok to connect that way?
socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr = INADDR_ANY;
socket_address.sins_port = htons(port_to_connect);
if(connect(*socket_handler, (struct sockaddr*)&socket_address, sizeof(socket_address)) == -1) {
error("connect");
} am_i_pointing_to_myself = false;
A TCP socket can either listen/accept, or it can connect, but it cannot do both.
Your application will likely need two separate threads. One thread would open a socket for listening, wait for a connection and handle that connection. The other one would makes a connection when the user requests it.
To keep things simple, the user thread that does the connection should send the user's message and close the connection, while the background listening thread should read a message from the accepted socket, display it to the user, and close the connection.
Another option is to have the application ask the user for server or client mode. For server mode, the app would listen and wait for a connection, then when it has a connection it can send back and forth over the connected socket. For client mode, it would make a connection to the server, then use the socket to communicate in both directions.
The problem is that you're using the same socket for both the listen() and the connect(). That is why you're getting that error.
You should be able to both listen and connect but you'll need a different socket for each.
What exactly are you trying to accomplish overall?
You said you need to have each instance be able to be a client or a server. That sounds like a P2P sort of thing.
Why do you need to both accept and make connections?

winsock udp connect missing or dropped packets

I am in the process of adding client/server UDP support to thekogans stream library and have run into a problem on Windows. Here is what I am doing;
server udp socket is bound to 0.0.0.0:8854.
server udp socket has IP_PKTINFO = true.
server udp socket has SO_REUSEADDR = true.
server udp socket starts an overlapped WSARecvMsg operation.
client binds to 0.0.0.0:0 and connects to 127.0.0.1:8854.
client sends a message using WSASend.
server socket receives the message and creates a new UDP socket with the following attributes:
SO_REUSEADDR = true
bind to address returned by IP_PKTINFO (127.0.0.1:8854).
connect to whatever address was returned by WSARecvMsg.
client and the new server UDP socket exchange a bunch of messages (using WSASend and WSARecv).
Here is the behavior I am seeing:
the first connection between client and server works flawlessly.
I then have the client exit and restart.
all other packets from the client are dropped.
if I set a timeout on the new server UDP socket (127.0.0.1:8854) and it times out and is closed, then the client can connect again. In other words, the scheme seems to work but only one client at a time. If the server has a concrete (not wildcard) socket created for the same port, no other client can send it messages.
Some more information that may be helpful: The server is async and uses IOCP. This code (using epoll and kqueue) works perfectly on Linux and OS X. I feel like I am missing some flag somewhere that winsock needs set but I can't seem to find it. I have tried googling various search terms but have hit a wall.
Any and all help would be greatly appreciated. thank you.

ways to send messages to a service?

i had a client server program and i wanted to change the server to a service. so i took some code from here Svp.cpp. it works fine but i created the client server using UDP so i was wondering is there another way to send messages to a service? The client sends messages to the server(service) and the server just echoes them back. is it necessary to have a UDP or TCP connection to send and receive messages?
here is the part of the program that receives the messages from the client (the rest of the code is taken from Svp.cpp)
SOCKET socketS;
InitWinsock();
struct sockaddr_in local;
struct sockaddr_in from;
int fromlen = sizeof(from);
local.sin_family = AF_INET;
local.sin_port = htons(1234);
local.sin_addr.s_addr = INADDR_ANY;
socketS = socket(AF_INET,SOCK_DGRAM,0);
bind(socketS,(sockaddr*)&local,sizeof(local));
while (1)
{
char buffer[1024];
ZeroMemory(buffer, sizeof(buffer));
if (recvfrom(socketS,buffer,sizeof(buffer),0,(sockaddr*)&from,&fromlen)!=SOCKET_ERROR)
{
sendto(socketS, buffer, sizeof(buffer), 0, (sockaddr*)&from, fromlen);
}
}
closesocket(socketS);
If the client and server applications are on the same machine, you could use Named Pipes instead.
Named Pipes
I had a system service that I had to remove the UI, and instead of creating a socket to communicate between the UI and the service, we used Named Pipes. This was nice, because some of our clients were worried about security with an open listening TCP socket on the machine.
If you go this route, you have to set up some sort of signaling between the two applications, because the pipes do not notify you of reads/writes like sockets do. But it is a very workable solution.

How to listen for a server reply from broadcast?

As part of a simple networking project I'm trying to connect two computers together to send a simple data packet. The client uses a broadcast to find servers, and my server successfully detects this broadcast from the client.
The server then sends a reply packet, however I am unable to get the client to listen to the packet.
The problem seems to lie with the broadcasting method, since if I use a direct server connection, aka instead of INADDR_BROADCAST I specify the IP address 127.0.0.1 or 192.168.0.x then the server connects, sends a reply, and the client receives it.
The listening code in the client:
// Stop the client from waiting for packets if there are none.
fd_set checksockets;
checksockets.fd_count = 1;
checksockets.fd_array[0]=m_listenSocket;
struct timeval t;
t.tv_sec=0;
t.tv_usec=0;
int waiting = select(NULL, &checksockets, NULL, NULL, &t);
// If there is at least one packet receive it.
if(waiting>0) {
std::cout << "Packet received.\n";
}
From this point I attempt to find the server address with the recvfrom() method.
I've made sure to use the broadcast flag on the client socket, right after creating it. This returns no errors.
int value=true;
int result = setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, (char*)&value, sizeof( value ) );
I've checked all possible WINSOCK functions that I've used and none return any errors.
I've also tried creating a second socket only for listening on the same port, but this conflicts with the server and therefore fails to open.
So essentially, what I'm trying to ask: How can I have a client listen for a reply from a broadcast? - aka the server address is unknown at first, I'm attempting to create a new socket using the reply address, however I'm not getting a reply address from a broadcast, despite the server receiving the broadcast and definitely sending a reply.
As you point out you won't receive any back when bound to INADDR_BROADCAST. This is normal: when you are bound to an address you only receive packets from that address. You don't need to bind the sockets to any address at all. This operation is usually required for connected sockets (i.e. TCP). If the receiving socket works I guess it is because you're doing all your tests on the same machine.
If you want to receive packets from a given address you can try to use connect or sendto and receivefrom.

Resetting socket connection

My application connects as a client across an ethernet to a server process.
As the server is well known and will not change, UDP and TCP are both setup using
socket();
setsockopt(SO_REUSEADDR);
bind();
connect();
The connection protocol includes heartbeats sent both ways.
When I detect an error with the connection e.g. hearbeat timeout, I need to reset the connection.
Is it sufficient just to connect() to the NULL address and then re-connect() after a short pause, or should I close the socket and then reinitialise from scratch?
thanks
After a socket error you have to discard the one in hand and restart the setup with a new socket.
Winsock documentation, for example:
When a connection between sockets is
broken, the sockets should be
discarded and recreated. When a
problem develops on a connected
socket, the application must discard
and recreate the needed sockets in
order to return to a stable point.
You have to close(2) the socket and re-do everything again. Why do you bind(2) on the client?