ways to send messages to a service? - c++

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.

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?

Can I use the same sockaddr_in in TCP and UDP?

In my serveur, I bind the TCP and UDP on two different ports.
I first connect my Client with TCP (via accept, etc)
Then I want to use UDP to communicate between my server and my client.
So I tried to use the same sockaddr_in like that :
void AUDPMonitor::sendMessage(Message &msg)
{
for (ISocket *socket: *_fdListClients)
{
if (msg.getClientId() == socket->getSock())
{
UDPSocket *UdpSocket = reinterpret_cast<UDPSocket *>(socket);
UdpSocket->send(msg, socket->getUserAddr());
break;
}
}
}
The _fdListClients is a vector of Socket I got from the TCP connexion.
There is no error messages but my client doesn't receive anything.
So I want to know if it's possible to use the same sockaddr_in or if it's impossible.
Edit : When I accept the client socket
socklen_t client_sin_len;
sockaddr_in *client_sin = new sockaddr_in;
client_sin_len = sizeof(sockaddr_in );
std::cout << "New User ! " << std::endl;
if ((cs = accept(fd, reinterpret_cast<struct sockaddr *>(client_sin), &client_sin_len)) == -1)
You can use the same copy of the sockaddr_in for TCP and UDP, but they have to be on different sockets.
A given socket created with AF_INET also specifies either SOCK_STREAM making TCP or SOCK_DGRAM making it UDP.
So if you have this:
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(12345);
You can pass this to bind with a TCP socket to bind to TCP/12345, and you can pass it to bind with a UDP socket to bind to UDP/12345.
you can use the same SOCAKADDR_IN structure for a TCP or UDP server or client but whenever you want to use it for a different one you should change the values of port and address because servers cannot be bound to the same port.
so if we have two remote stations running a TCP server and a UDP Server then the client to connect them:
SOCKET servTcp; // a remote bound and listing tcp socket waiting for remote clients through the blocking function `accept`
SOCKET servUdp; // a remote bound Udp server waiting for clients
// for the client:
SOCKET clientTcp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SOCKET clientUdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKADDR_IN sa_serv;
sa_serv.sin_addr.S_un.S_addr = inet_addr("127.168.0.1");
sa_serv.sin_family = AF_INET;
sa_serv.sin_port = htons(777);
now the socket clientTcp can connect to the remote tcp server using this address structure.
to use the same SOCKADDR_IN structure sa_serv for the the udp server:
as long as the tpc and the udp servers on the same remote machine we only change the port:
sa_serv.sin_port = htons(1000); // the port is unique for servers to bind on.
now we the udp socket clientUdp can use use sa_serv to send and receive data from the remote udp serv.
SOCKADDR_IN is the same for udp and tcp just change the value of port and sometimes address if server.

Set sockopt of QTcpSocket

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.

Mix mode communication between IPv4 and IPv6

I have a application which acts as client and server both. As a server it accepts SOAP requests on port xxxx[Agent URL] and send notifications to the sender on port yyyy [notification URL].
So basically it acts as a server on port xxxx and client on port yyyy. My service has a dedicated IP either IPv6 or IPv4.
We are using GSOAP for communication and overriding GSOAP function tcp_connect() for client side binding.
Currently I am facing issues with transition of service to IPv6. Use case: when I listening on IPv6 address and my notification URL is IPv4...
From the GSOAP implementation a socket is created from the Notification URL.
sk = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
Now we try to bind to this socket accordingly(either IPv4 or IPv6):
struct addrinfo hints, *res, *p;
int status;
const char* client_ip = AGENT_CLIENT_IP;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if( (status=getaddrinfo(client_ip, NULL, &hints, &res))!=0 )
{
sprintf(err_msg_buf,"bind failed in tcp_connect()");
soap->fclosesocket(soap, sk);
return error;
}
for( p=res; p!=NULL; p=p->ai_next){
if(p->ai_family == AF_INET)
{
struct sockaddr_in * ipv4 = (struct sockaddr_in *)p->ai_addr;
status = bind(sk, ipv4, (int)sizeof(struct sockaddr_in));
}
else if(p->ai_family == AF_INET6)
{
struct sockaddr_in6 * ipv6 = (struct sockaddr_in6 *)p->ai_addr;
status = bind(sk, ipv6, (int)sizeof(struct sockaddr_in6));
}
else
{
sprintf(err_msg_buf,"tcp_connect() error. IP Address neither IPv6 nor IPv4 ");
soap->fclosesocket(soap, sk);
return error;
}
break;
}
if(-1 == status)
{
sprintf(err_msg_buf," Binding to client host ip failed in tcp_connect()");
return error;
}
Since the socket is already created(according to the type of Notification URL), bind fails if the socket is of type mismatch is there.
How can I make my client side binding work when socket family and agent ip address are of different family ?
Maybe I am not getting what you are trying or you have some misunderstanding of how TCP/IP and RPC normally works.
Let me paraphrase your set up and then show what I think is odd about it.
You have a server and one or multiple clients. The server accepts IPv4 and IPV6 connections on a fixed port, let us say 1337. To answer the request you open a new TCP stream (or maybe SOAP) on a different fixed port, say 1338. You are now wondering why, when a second client connects the bind to 1338 fails?
The short answer is: "The port is in use, duh, us a different port!"
But that misses the point that the setup, to say the least ODD. Although I have never used GSOAP, I have used SOAP and other RPC frameworks and what you outline is weird, unless I am missing something you did not outline.
The first thing that is odd, if you need an answer to a SOAP request, why do you simply formulate one with a return value? Call the SOAP function and the client will block until it gets an answer. If you don't want the call to block for the relatively long duration of the call do the entire thing asynchronously.
So you want to pass data to the client back later? Here you have two solutions, either the client polls the server or you open a new SOAP connection to the client. The first solution is basically desirable, because in most cases the client can connect to the server but not the other way around. For example the client can be behind a NAT, what do you do now? The second solution works well when you know that the client will always be reachable.
It seems to me that you are trying to do the second "return channel" solution. In this case why are you binding to a port? The client side of any IP connection does not need to bound to a port. The OS will automatically assign an available port. What you need to do is then bind the port on the client to a well known IP. You then use this well known client port and use it in connect on the server (or not, since you are using SOAP).
Since this is all confusing let me illustrate this with a small diagram:
Client Server
------ ------
Request Channel <random port> 1337
Back Channel 1338 <random port>
To sum up:
So either you are reimplementing something that works in SOAP and should stop doing that or if you absolutely need a back channel, simply don't call bind on a client socket.

Unable to connect to server (over a remote connection)

I have been working on this project for a while and wanted to test some new features over a remote connection, but the client failed to connect (while it was able to connect in the past). Everything works fine locally. At the moment I am not able to port foward so I'm using hamachi. I have tried capturing the hamachi network traffic with wireshark, and the client requests do arrive, but the server doesn't receive them.
Any help is greatly appreciated.
Code (error checking left out to make the code more readable):
Client:
addrinfo ADDRESSINFO, *CLIENTINFO=NULL;
ZeroMemory(&ADDRESSINFO, sizeof(ADDRESSINFO));
ADDRESSINFO.ai_family = AF_INET;
ADDRESSINFO.ai_socktype = SOCK_STREAM;
ADDRESSINFO.ai_protocol = IPPROTO_TCP;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
getaddrinfo(strIP.c_str(), strPort.c_str(), &ADDRESSINFO, &CLIENTINFO);
connect(ConnectSocket, CLIENTINFO->ai_addr, CLIENTINFO->ai_addrlen);
freeaddrinfo(CLIENTINFO);
Server:
addrinfo ADDRESSINFO, *SERVERINFO=NULL;
ZeroMemory(&ADDRESSINFO, sizeof(ADDRESSINFO));
ADDRESSINFO.ai_family = AF_INET;
ADDRESSINFO.ai_socktype = SOCK_STREAM;
ADDRESSINFO.ai_protocol = IPPROTO_TCP;
getaddrinfo(SERVER_IP, SERVER_PORT, &ADDRESSINFO, &SERVERINFO);
ListenSocket = socket(SERVERINFO->ai_family, SERVERINFO->ai_socktype, SERVERINFO->ai_protocol);
ConnectionSocket = socket(SERVERINFO->ai_family, SERVERINFO->ai_socktype, SERVERINFO->ai_protocol);
bind(ListenSocket, SERVERINFO->ai_addr, SERVERINFO->ai_addrlen);
freeaddrinfo(SERVERINFO);
listen( ListenSocket, SOMAXCONN )
while(true)
{
if(ConnectionSocket = accept(ListenSocket, NULL, NULL))
{
//do stuff
}
}
I do not know how abridged the code that you've pasted is but:
1) There is no place where you set destination address
2) There is no place you set destination port
3) To which port is server trying to bind?
...so this just cannot work at all.
Moreover please do handle errors - (yes you said you've omitted them on purpose) but I bet that if server refuses connection your error handling shows that. Otherwise it connects fine but you claim otherwise. You also say:
1) 'the client failed to connect'
2) and later you say 'the client requests do arrive, but the server doesn't receive them'
If you are able to connect - you should see 3 way handshake (TCP stream connection). If not error handling and wireshark will show that. You say that client requests do arrive but your code is not sending anything (no sending code available). You also say that server does not receive them - if it connects and you send anything there is no way that your error handling shows nothing and server receives nothing (but server code lacks any receive routine call).
I think right now you cannot receive much help with that. Update your code, verify if it really works locally (you mean loopback here right?), then test 'not locally', add error handling and use wireshark on both client and server side.