Linux c++ recvfrom() changes (destroys) the [socket] file descriptor - c++

I have written a simple UDP server. Well, naturally I use recvfrom() function somewhere in it. I have searched the net for it, and found that it is caused by the buffer overflow. Is this true? But I can't figure why my code fails and throws the same error, here is the part associated with recvfrom():
char messageFromClient[1024] = {0};
returnStatus = recvfrom(udpSocket, &messageFromClient, strlen(messageFromClient), 0, (struct sockaddr*)&udpSocket,
&addrlen);
The file descriptor before invocation of recvfrom() is 3 but when I call it, it changes to -187301886

Your code fails because you specify 0 receive buffer size and you pass the socket file descriptor as the peer address argument (which overwrites its value):
Fix:
char messageFromClient[1024];
sockaddr_in addr;
socklen_t addrlen = sizeof addr;
ssize_t received = recvfrom(udpSocket, messageFromClient, sizeof messageFromClient, 0, (sockaddr*)&addr, &addrlen);

Related

Can a UDP multicast socket be configured so that write() can be called rather than sendto()?

I am writing a C++ multicasting application on Linux Ubuntu.
In my C++ multicast sender class I do this:
uint16_t port = 5678;
const char* group = "239.128.128.128";
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(group);
addr.sin_port = htons(port);
const char* buf = "Hi there";
size_t bytes_to_write = 8;
size_t bytes_sent = sendto(fd, buf, bytes_to_write, 0, (struct sockaddr*) &addr, sizeof(addr));
Is there any way to configure the file descriptor so that I can call write() rather than sendto()? I would have thought there would be a setsockopt option or similar to do this?
Yes.
Per the documentation man 7 udp
When
connect(2) is called on the socket, the default destination address
is set and datagrams can now be sent using send(2) or write(2)
without specifying a destination address.
and, for generality, the POSIX spec for connect says
If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions.
It's always worth checking the documentation for these, things, it isn't that impenetrable. FWIW I couldn't remember immediately whether you need connect() or bind() for this, and it took me a few seconds to find out.

C++: Classic communication exercise between server and client

Good day.
As a computer science student, learning low-level C programming, i'm stucked in the "classic" practice exercise of writting a server-client communicating program.
The goal is to develop a server component which receives a command from a remote client component, and execute it as a local shell command; then, the command's output is send again to the client. Pretty simple.
My code send the command from the client, the server succesfully receive it, execute it and captures the output. But at this point, when the sayd server tries to reply with that output to the client ... something goes wrong and the client receives nothing. No clue if the problem is in the server part, or in the client counterpart.
Any idea? Thanks in advance!
Server:
struct sockaddr_in srvaddr, cliaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
int sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
srvaddr.sin_port = htons(42000);
bind(sk, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
recvfrom(sk, recepcion, sizeof(recepcion), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
// [...] Portion of code with a Pipe pointing to a Fork which runs the command...
// And here is where, maybe, the communication is lost:
sendto(sk, recepcion, sizeof(recepcion), 0, (struct sockaddr*)&cliaddr, sizeof(cliaddr));
Client:
struct sockaddr_in srvaddr, cliaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
int sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
cliaddr.sin_port = htons(42001);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
srvaddr.sin_port = htons(42000);
// [...] Some other code catching the command from the argument paramenters:
sendto(sk, comando, strlen(comando), 0, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
// And here's where the server reply should be, but theres nothing:
recvfrom(sk, buff, sizeof(buff), 0, (struct sockaddr*)&srvaddr, sizeof(srvaddr));
Say i print all the traces with:
fprintf(stderr, "");
So, loosing the terminal's focus due to forking should not be an issue.
Bye and thanks!
The problem is most likely the recvfrom call. If you check the manual page you will see that the source-address length is a pointer. I don't know how you managed to get it to compile without errors or warnings.
You need to initialize the size to the actual size of the socket-address structure, pass a pointer to it, and the recvfrom function will fill in the actual size:
socklen_t cliaddrlen = sizeof(cliaddr);
recvfrom(sk, recepcion, sizeof(recepcion), 0,
(struct sockaddr *) &cliaddr, &cliaddrlen);
Oh, and I do assume you check for errors in your actual code?

echo server not responding udp

Am trying to implement a echo client. Client using sendto() is transmitting the message and server is receiving n displaying it. but then server is not sending the message (echo back). here is the code of both server and client. Can anyone help me with this?
Server:
char msg[100]="";
int conn_sock,n;
struct sockaddr_in server_addr,client_addr;
conn_sock=socket(AF_INET,SOCK_DGRAM,0);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(1234);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
err=bind(conn_sock, (struct sockaddr *)&server_addr,sizeof(server_addr));
n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr);
n=sendto(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,sizeof(client_addr));
in recvfrom the value of n is number of bytes. but in sendto() value of n is -1
Client:
char msg[100];
int conn_sock,n,err;
struct sockaddr_in server_addr;
conn_sock=socket(AF_INET,SOCK_DGRAM,0);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(1234);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
cin>>msg;
n=sendto(conn_sock,msg,strlen(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr);
recvfrom() is not receiving any data from the server.
These two lines are both wrong:
// In the server
n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr);
// In the client
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr);
The last two parameters of recvfrom() are supposed to point to two separate variables. One of them receives the other peer's network address, and the other one receives the length of that network address. That you're passing the same pointer value into both means that the address length is overwriting the first several bytes of the address data, corrupting it and resulting in badness.
Here's how the server should work, receiving the length into a separate variable:
struct sockaddr_storage client_addr;
socklen_t client_addr_len = sizeof(client_addr); // This is an in+out parameter
n=recvfrom(..., (struct sockaddr *)&client_addr, &client_addr_len);
n=sendto(..., (struct sockaddr *)&client_addr, client_addr_len);
Note that I used a sockaddr_storage instead of sockaddr_in. A sockaddr_storage is guaranteed to be large enough to hold any valid socket address type for supported address families, so that this code will be forward-compatible with IPv6.
Likewise, here's how the client should work:
n=sendto(..., &server_addr, sizeof(server_addr));
do
{
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
n=recvfrom(..., (struct sockaddr *)&peer_addr, &peer_addr_len);
} while (!areSockAddrsEqual((struct sockaddr *)&server_addr, (struct sockaddr *)&peer_addr));
...
bool areSockAddrsEqual(struct sockaddr *addr1, struct sockaddr *addr2)
{
if (addr1->sa_family != addr2->sa_family)
return false;
switch (addr1->sa_family)
{
case AF_INET:
struct sockaddr_in *addr1_in = (struct sockaddr_in *)addr1;
struct sockaddr_in *addr2_in = (struct sockaddr_in *)addr2;
return (addr1_in->sin_port == addr2_in->sin_port &&
addr1_in->sin_addr.s_addr == addr2_in->sin_addr.s_addr);
...
// Other address families such as AF_INET6 left as an exercise
}
}
Here again we make sure to pass a separate socklen_t pointer to receive the address length, and then I also added a loop to make sure that the actual packet we received was the one we were expecting from the intended server. If we instead received a different packet (say, due to another peer that just happened to send us a packet at the wrong time), we ignore it.
The check for whether or not two socket addresses are equal is a little gnarly, since it depends on the address family, and supporting both IPv4 and IPv6 is tricky.

C++: Linux: TCP/IP program crashes when calling write()

I have a loop which keeps writing data to a client through TCP/IP. The connection is opened as follows:
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
The following line is executed continuously in a loop (with sleep of 0.1 sec) in order to write the data to the client:
n = write(newsockfd,data.c_str(),data.length()+1); //+1 to include NULL in null terminated string
if(n>=0)
{
cout<<"success"<<endl;
}
else
{
cout<<"Fail"<<endl;
close(newsockfd);
newsockfd = -1;
}
I want the server to become reading for receiving a new connections if the connection is broken for any reason. So if writing fails, I get ready again to accept a new connection with the first command.
My problem is the following: the method succeeds for the first time, so if the connection is broken from the client, write() returns a negative number and I know immediately that the connection has a problem, so I close it and expect a new one. The server receives the new connection, but at the next time when using write(), the program crashes immediately.
Why does this happen? Please help, I'm new in TCP/IP stuff.
Please ask for more information if you require it.
Requested from helpers:
Stack trace:
Error: signal 13:
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402155]
/lib/x86_64-linux-gnu/libc.so.6(+0x364a0)[0x7ffc57ac04a0]
/lib/x86_64-linux-gnu/libpthread.so.0(write+0x10)[0x7ffc5836dcb0]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x4023b6]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x401b54]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffc57aab76d]
/mnt/hgfs/Dropbox/common_src/LinuxTCP/Server/ServerLinux-build-desktop-Qt_4_8_1_in_PATH__System__Release/ServerLinux[0x402081]
Variable definitions: it's a class:
Body:
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
Constructor starts the stuff:
LinuxTCPServer::LinuxTCPServer(int port, bool nonblocking)
{
if(nonblocking)
sockfd = socket(AF_INET, SOCK_NONBLOCK | SOCK_STREAM, 0);
else
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = port;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
}
Assuming Linux >= 2.2, replace this:
n = write(newsockfd,data.c_str(),data.length()+1);
with this:
n = send(newsockfd, data.c_str(), data.length()+1, MSG_NOSIGNAL);
send(2) will then return -1 with errno set to EPIPE, rather than generating a fatal SIGPIPE. Alternatively, ignore SIGPIPE.
When you receive the SIGPIPE, the connection behind newsockfd has been broken. We don't have enough code to reproduce the problem, client and server, so it's rather moot to say what might actually be wrong. However, converting SIGPIPEs to EPIPEs will at least give your server a chance to handle the broken connection.
Your stack trace indicates that the program is crashing with signal 13, which means you have a broken pipe.
That would indicate that your connection is broken, but you are still trying to write to it. See this thread for why that might causes the broken pipe error: What causes the Broken Pipe Error?
Now, on how to solve the issue, I suspect you're not actually getting a proper connection setup on your 'accept' call. Make sure you check the status of your 'accept' call before calling write.
The problems that are causing your accept call to fail are likely on the other side of the connection I think.

UDP server connecting and sending data weirdness

I am making async (well non-blocking rly) sockets lib for educational purposes. TCP part works just fine, but when it comes to UDP i experience weird behavior. Following code works as expected - server receives data:
MyUDPSocket server;
server.Bind(5551);
MyUDPSocket client;
client.Connect("192.168.0.103", 5551);
Sleep(10);
client.Write("\x0", 1);
Sleep(10);
client.Write("test", 5);
But if either of Sleep() or client.Write("\x0", 1); are commented out - it stops working. Server just would not get data. Here are some parts of my library to give you clue how exactly sockets are made:
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
...............................................
memset( &name, 0, sizeof(name) );
name.sin_family = AF_INET;
name.sin_port = htons( port );
hostent* hostinfo = gethostbyname( address );
name.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
connect(s, (sockaddr*)&name, sizeof name)
Nothing fancy as you see. Maybe it is some unspoken rule that sending one byte of data to initialize connection is required or something? I am really confused here.
Edit:
Write function as requested. name variable is very same that is set in Connect call whose code is above.
virtual int Write( void* data, int size )
{
return sendto(s, (const char*)data, size, 0, (sockaddr*)&name, sizeof name);
}
Edit:
Also in select() loop i check only for sockets being readable. Could it be case that socket is not writable due to connection being initialized? If that is the case it should solve First sleep. But what about sending one byte then?