Bad file descriptor in recvfrom function - c

This is my server side code for udp
#include"headers.h"
int main(int argc,char **argv)
{
//------------udp server socket connection------//
int sd1;
struct sockaddr_in serveraddr, clientaddr;
char buffer[100];
char *bufptr = buffer;
int cnt=1,ret;
socklen_t clen;
clen=sizeof(clientaddr);
//int buflen = sizeof(buffer);
sd1=socket(AF_INET,SOCK_DGRAM,0);
printf("udp socket id=%d\n",sd1);
printf("socket created for udp..\n");
if(sd1<0)
{
perror("udp_sfd");
exit(0);
}
printf("server socket created..\n");
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr=INADDR_ANY;
if(bind(sd1,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
{
perror("bind\n");
exit(0);
}
else
{
while(1)
{
printf("server accept from client\n");
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
printf("ret=%d\n",ret);
//printf("hello\n");
if(ret<0)
{
perror("recvfrom");
exit(0);
}
else
{
printf("UDP Server received the following:\n \"%s\" message\n", bufptr);
}
//close(sd1);
}
}
close(sd1);
return 0;
}
I am sending tht buffer from client side... and in server side it is giving me an error like this....
Bad file descriptor .... what should I do...
I also changed the name of file descriptor 2 times... still it is not working...

Your recvfrom is bad. Instead of strlen(buffer), you should use sizeof(buffer). Since buffer is on the stack, you may have a large string in there and then you are overflowing the buffer if the recvfrom gets a large amount of data.
I will studying it up some more if that doesn't help.

The problem is in your call to recvfrom:
ret=recvfrom(sd1,(char *)bufptr,strlen(buffer),0,(struct sockaddr *)&clientaddr,&clen);
The third parameter should be the size of the input buffer. But instead, you're calling strlen on the buffer. Because buffer is uninitialized, calling strlen on it is reading uninitialized data which can cause undefined behavior.
Also, unless the client is sending a null terminated string (i.e. some printer characters followed by a null byte) the call to printf will also invoke undefined behavior since any bytes past what was read will be uninitialized.
Pass in the buffer size minus 1 (to leave space for a null byte) instead of calling strlen, and clear the buffer just beforehand.
memset(buffer, 0, sizeof(buffer));
ret=recvfrom(sd1,(char *)bufptr,sizeof(buffer)-1,0,(struct sockaddr *)&clientaddr,&clen);

I think you are closing the socket some where else in your program.
The Bad file descriptor may refer to an invalid file descriptor or it is closed somewhere else in your code or it is already being used somewhere else. I think you need to debug your code a little bit and then manage your socket well.
It is possible that your socket is being closed somewhere by mistake or being corrupted.
You can try creating the new socket as well with different port number.

Related

Does fgets change the file descriptor set?

So, I can use FD_ZERO, FD_SET and FD_ISSET to mess around with the file descriptor set. The select() function may now be used to observe if a certain file object becomes readable (hope my wording is right here). What I want to do is: Read in a sequence of characters from stdin and then send this sequence to a server. I leave out some error messages of the socket stuff here, however, because my question is about FD_ISSET.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet.in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
static char buffer[256];
int sock_fd, length, port;
struct sockaddr_in server_addr;
fd_set input_fdset
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
connect(sock_fd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in));
while (1)
{
FD_ZERO(&input_fdset);
FD_SET(STDIN_FILENO, &input_fdset);
FD_SET(sock_fd, &input_fdset);
if (select(sock_fd+1, &input_fdset, NULL, NULL, NULL) == -1)
perror("some error");
if (FD_ISSET(STDIN_FILENO, &input_fdset))
{
if(fgets(buffer, 256, stdin) == NULL)
{
printf("connect: Closing socket.");
break;
}
length = strlen(buffer);
send(sock_fd, buffer, length, 0);
}
else
{
length = recv(sock_fd, buffer, 256, 0);
if(length == 0)
{
printf( "Connection closed by remote host.");
break;
}
write(STDOUT_FILENO, buffer, length);
}
}
close(sock_fd);
return(0);
}
You can probably guess I came across this code.
I have troubles to understand the following: Within the while-loop, I add both the socket object and stdin to the file descriptor set. In the next step select checks whether there is anything to read from either of these two objects. Then the if(FD_ISSET(STDIN_FILENO, &input_fdset)) should ALWAYS be executed, right? I mean the condition is always fulfilled, because we set the STDIN_FILENO using FD_SET(STDIN_FILENO, &input_fdset). Now, I am within this if-statement. fgets reads in my terminal input line by line. When I end this input with ENTER, a newline-character is appended to my buffer and reading from stdin stops. But only until the while-loop is executed again, right? Because in that case fgets gets called again as well. Btw I think it is kind of weird to have fgets only within this if-statement. Shouldn't it be called before? How can fgets become NULL? Only if EOF is reached without reading in any character. This won't happen though, will it? I cannot reach EOF when I am reading from stdin. I think. And now the last question: When would I execute the else-block? For this to happen, the previous if-statement would need to fail. But as I said, if(FD_ISSET(STDIN_FILENO, &input_fdset) will never fail.
Ofc I realize I am missunderstanding this code.
Can somebody help me figure this out?
From the documentation for select (man select):
"On return, select() replaces the given descriptor sets with subsets consisting of those descriptors that are ready for the requested operation."
The purpose of FD_ISSET is to determine which sets are ready to be read. The set is changed by the select call, by design.

When abruptly exiting a C program mid-loop, why do additional loop iterations occur?

Consider the basic client and server programs below (just bare bones / to illustrate my question). The client initiates a connection with the server, prompts the user to enter a message, which is then sent to the server and printed to screen.
If I abruptly quit the client program in the middle of the loop (e.g. by closing the terminal window), sometimes the client will continue to iterate through the loop for a period of time (i.e. the last message sent to the server / currently residing in the write buffer at the time the client is closed, is repeatedly sent to the server, typically until the loop is exhausted). Other times however, the read() call on the server correctly returns 0, and the connection is closed without issue (the behavior seems to be fairly random).
I don't quite understand what's going on here. First off, why do additional loop iterations occur after the program closes? Is there just a lag time between when the terminal window is closed, and when the actual process itself ends? Even if additional loop iterations do occur, shouldn't the call to fgets() block until a message is entered by the user?
I'm using Fedora 25 Workstation with XFCE desktop.
I tried searching for info on this, but didn't have much luck (I'm not sure how to search for this in a succinct way). Any help is much appreciated.
Thanks
CLIENT:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void) {
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3000);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);
connect(sockfd, (struct sockaddr *)&server, sizeof(server));
int i;
for (i = 0; i < 20; i++) {
char buf[512];
printf("Send a message: ");
fgets(buf, 512, stdin);
write(sockfd, buf, sizeof(buf));
}
close(sockfd);
}
SERVER:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void) {
int listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3000);
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);
bind(listenfd, (struct sockaddr *)&server, sizeof(server));
listen(listenfd, 10);
printf("Listening...\n");
struct sockaddr_in client;
socklen_t client_size = sizeof(client);
int clientfd = accept(listenfd, (struct sockaddr *)&client, &client_size);
for (;;) {
char buf[512];
int i = read(clientfd, buf, sizeof(buf));
if (i == 0) {
close(clientfd);
printf("Connection Closed\n");
break;
} else {
printf("%s", buf);
}
}
close(listenfd);
}
When your terminal (and thus the remote/master side of the pty device connected to your process's stdin/out/err) is closed, fgets will see end-of-file status on stdin, and will return immediately with either an incomplete line (not ending in \n) or no input at all (null return value); in practice it's going to be the latter. If you checked the result, you would see this and be able to act accordingly.
in the server, this line:
printf("%s", buf);
should be replaced with:
*buf[i] = '\n';
printf( "%s", buf );
so there is a valid string to print (read() will not terminate the string)
Note: if a I/O error occurs or a signal occurs, etc then read() will return a value less than 0 and should result in exiting the for(;;;) loop, not continuing in the loop, printing the 'old' contents of buf[]
in this line in the client:
write(sockfd, buf, sizeof(buf));
if the write fails, it will return a value less than 0 if/when such an event occurs, the loop should exit, not continue looping,
It is very important to check all error conditions. such error checking (and the resulting handling of the error) can easily double the size of the code, but it must be done; otherwise such 'odd' events as you are seeing will happen, with no simple explanation of what happened.
When a system function returns an error indication, use the function perror() to have some text you provide displayed on stderr, along with the message from the system as to why it thinks the error occurred.
If I abruptly quit the client program in the middle of the loop (e.g. by closing the terminal window),
Closing the terminal window does not quit the client program -- it continues running, just with no input (so any reads from the now-closed terminal will return EOF). However, you never check the return value of fgets in the client so you you never notice, you just keep looping, sending the same buffer.
In addition, the code:
fgets(buf, 512, stdin);
write(sockfd, buf, sizeof(buf));
reads a line of up to 511 chars from the input, but then sends the entire 512 byte buffer, regardless of how long the actual message is. What you want is something more like:
if (fgets(buf, 512, stdin))
write(sockfd, buf, strlen(buf));
else
break; // there was an error or EOF on reading from stdin
Of course, this still has issues with lines longer than 511 bytes and then there's the issue that TCP does not preserve message boundaries, so on the server you might get more than one or only part of a message in a single read call.

why write() doesn't return 0 when it should?

I've encountered a case where using write() server-side on a remotely closed client doesn't return 0.
According to man 2 write :
On success, the number of bytes written is returned (zero indicates
nothing was written). On error, -1 is returned, and errno is set
appropriately.
From my understanding: when using read/write on a remotely closed socket, the first attempt is supposed to fail (thus return 0), and the next try should trigger a broken pipe. But it doesn't. write() acts as if it succeeded in sending the data on the first attempt, and then i get a broken pipe on the next try.
My question is why?
I know how to handle a broken pipe properly, that's not the issue. I'm just trying to understand why write doesn't return 0 in this case.
Below is the server code I wrote. Client-side, I tried a basic C client (with close() and shutdown() for closing the socket) and netcat. All three gave me the same result.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define MY_STR "hello world!"
int start_server(int port)
{
int fd;
struct sockaddr_in sin;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
perror(NULL);
return (-1);
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1
|| listen(fd, 0) == -1)
{
perror(NULL);
close(fd);
return (-1);
}
return (fd);
}
int accept_client(int fd)
{
int client_fd;
struct sockaddr_in client_sin;
socklen_t client_addrlen;
client_addrlen = sizeof(struct sockaddr_in);
client_fd = accept(fd, (struct sockaddr *)&client_sin, &client_addrlen);
if (client_fd == -1)
return (-1);
return (client_fd);
}
int main(int argc, char **argv)
{
int fd, fd_client;
int port;
int ret;
port = 1234;
if (argc == 2)
port = atoi(argv[1]);
fd = start_server(port);
if (fd == -1)
return (EXIT_FAILURE);
printf("Server listening on port %d\n", port);
fd_client = accept_client(fd);
if (fd_client == -1)
{
close(fd);
printf("Failed to accept a client\n");
return (EXIT_FAILURE);
}
printf("Client connected!\n");
while (1)
{
getchar();
ret = write(fd_client, MY_STR, strlen(MY_STR));
printf("%d\n", ret);
if (ret < 1)
break ;
}
printf("the end.\n");
return (0);
}
The only way to make write return zero on a socket is to ask it to write zero bytes. If there's an error on the socket you will always get -1.
If you want to get a "connection closed" indicator, you need to use read which will return 0 for a remotely closed connection.
This is just how the sockets interface was written. When you have a connected socket or pipe, you are supposed to close the transmitting end first, and then the receiving end will get EOF and can shut down. Closing the receiving end first is "unexpected" and so it returns an error instead of returning 0.
This is important for pipes, because it allows complicated commands to finish much more quickly than they would otherwise. For example,
bunzip2 < big_file.bz2 | head -n 10
Suppose big_file.bz2 is huge. Only the first part will be read, because bunzip2 will get killed once it tries sending more data to head. This makes the whole command finish much quicker, and with less CPU usage.
Sockets inherited the same behavior, with the added complication that you have to close the transmitting and receiving parts of the socket separately.
The point to be observed is that, in TCP, when one side of the connection closes its
socket, it is actually ceasing to transmit on that socket; it sends a packet to
inform its remote peer that it will not transmit anymore through that
connection. It doesn't mean, however, that it stopped receiving too. (To
continue receiving is a local decision of the closing side; if it stops receiving, it can
lose packets transmitted by the remote peer.)
So, when you write() to a socket that is remotely closed, but
not locally closed, you can't know if the other end is still waiting to read
more packets, and so the TCP stack will buffer your data and try to send it. As
stated in send() manual page,
No indication of failure to deliver is implicit in a send(). Locally detected
errors are indicated by a return value of -1.
(When you write() to a socket, you are actually send()ing to it.)
When you write() a second time, though, and the remote peer has definitely
closed the socket (not only shutdown() writing), the local TCP stack has probably
already received a reset packet from the peer informing it about the error on
the last transmitted packet. Only then can write() return an error, telling
its user that this pipe is broken (EPIPE error code).
If the remote peer has only shutdown() writing, but still has the socket open,
its TCP stack will successfully receive the packet and will acknowledge the
received data back to the sender.
if you read the whole man page then you would read, in error return values:
"EPIPE fd is connected to a pipe or *socket whose reading end is closed*."
So, the call to write() will not return a 0 but rather -1 and errno will be set to 'EPIPE'

select() returns with no incoming connection

I'm writing a very simple server application just for the purpose of testing some code.
After creating a socket and bind()ing it to my localhost and some port I'd like to use select() to know when an incoming connection arrives to the bound socket. After that the application should print the message up to a certain lenght and then exit().
My question is basically if I need to use listen() and accept() when I'm expecting only one connection (please remember this is just for testing). I believe these functions are not needed in this case and are only needed for accepting multiple incoming requests. Am I wrong?
With the above ideia in mind I wrote the following code
int main()
{
int fd = TCPcreate(atoh("127.0.0.1"), 15000); /*my localhost address*/
char *str = malloc(100);
int a;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd,&rfds);
a = select(fd+1,&rfds,(fd_set*)NULL,(fd_set*)NULL,(struct timeval*)NULL);
// printf("select returns %d\nfd = %d\n", a, fd);
// printf("fd is set? %s\n", FD_ISSET(fd,&rfds) ? "yes" : "no");
a = TCPrecv(fd, str, 100); /*receive at most 100B */
// printf("%d\n", a);
printf("%s\n", str);
close(fd);
exit(0);
}
TCPcreate()
int TCPcreate(unsigned long IP, unsigned short port)
{
int fd;
struct sockaddr_in address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd==-1)
{
return -1;
}
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(IP);
address.sin_port = htons(port);
/* struct sockaddr_in is the same size as struct sockaddr */
if(bind(fd, (struct sockaddr*)&address, sizeof(address))==-1)
{
return -2;
}
return fd;
}
atoh() simply returns its argument in host byte order.
What happens when I run the program is that select() doesn't block waiting for a connection. Instead, it immediately returns 1. If I uncomment the printf()s what I get is
select returns 1
fd = 3
is set? yes
-1
(blank line)
What am I missing here?...
If you look at the POSIX specification of select(), the file descriptors returned are ready for reading, writing, or have an error condition on them. This does not list 'a socket on which listen() would succeed' as one of the detectable conditions. So, you will need to use listen() and accept(); only after you've accepted the connection can you use select() on the descriptors.
As Gonçalo Ribeiro notes, the specification for select() also says:
If the socket is currently listening, then it shall be marked as readable if an incoming connection request has been received, and a call to the accept() function shall complete without blocking.
That means you must have done a listen() on the bound socket, but you can wait on multiple sockets for incoming connections.
If you want blocking call - use listen().
The problem with the select is in your code is - keep the select in the loop. As it is a non-blocking call, it will only check once that someone is there to listen or not. So, you can use loop to check for listen many times.

why recv() changed unrelated variables

there are total of 3 processes, one manager and two client, the manager send a message to both clients by TCP, the code below is part from client's. as i pass all the parameters into the add_to_ring function, and start to recv() from TCP socket which is from the passed parameter. the recv() functions will and both clients received correct message, but then i discovered that the parameters passed to this function are all changed, i have no idea who changed them, they are correct before the recv() and have been changed right after the recv(), nothing happened in between.i also tried assign these parameters to some variable in the function, and after recv() those variables changed too. can anyone see why is that? thanks!
void add_to_ring(int pid,int s_sockfd,int i,traid_info *traidinfo,tcp_recv recvbytcp, unsigned identifier, struct sockaddr_in my_addr)
{
//receive add message from TCP
printf("client %d:pid is %d,i is %d,nonce is %lu,identifier is %lu,port is %d\n",i,pid,i,recvbytcp.nonce,identifier,my_addr.sin_port);
char addmsg[100];
int apid=pid;
int as_sockfd=s_sockfd;
int ai=i;
tcp_recv arecvbytcp=recvbytcp;
unsigned long int aidentifier=identifier;
struct sockaddr_in amy_addr=my_addr;
if((recv(s_sockfd, addmsg, MAXDATASIZE, 0)) == -1)
{
perror("recv1");
exit(1);
}
printf("client %d:pid is %d,i is %d,nonce is %lu,identifier is %lu,port is %d\n",i,pid,i,recvbytcp.nonce,identifier,my_addr.sin_port);
printf("client %d:pid is %d,i is %d,nonce is %lu,identifier is %lu,port is %d\n",ai,apid,ai,arecvbytcp.nonce,aidentifier,amy_addr.sin_port);
//start add to ring
if(addmsg[0]=='a')
{
if(i==1)
{
traidinfo->succ_port = recvbytcp.FP;
traidinfo->succ_identifier = identifier;
traidinfo->pred_port = recvbytcp.FP;
traidinfo->pred_identifier = identifier;
traidinfo->my_port = my_addr.sin_port;
traidinfo->my_identifier = identifier;
}
}
printf("client %d:pid is %d,i is %d,nonce is %lu,identifier is %lu,port is %d\n",ai,apid,ai,arecvbytcp.nonce,aidentifier,amy_addr.sin_port);
//finished adding,send back my message by TCP
char msg2man[100];
data_process(arecvbytcp.nonce, msg2man, apid, amy_addr.sin_port);
printf("client %d: port is %lu\n",ai,amy_addr.sin_port);
if(send(as_sockfd, msg2man, MAXDATASIZE, 0) == -1)
{
perror("send");
exit(1);
}
}
addmsg is only 100 bytes, but you recv up to MAXDATASIZE bytes. If you receive more than 100 bytes then apid and as_sockfd will get overwritten.
Try changing the declaration of addmsg:
char addmsg[MAXDATASIZE];
Besides the problem with you possibly receiving (and sending as well) more than can fit in the array, you have to remember that TCP doesn't promise to receive all that you ask for, or even a complete message.
You have to check the amount received, and if to little you have to receive again while appending to the buffer.

Resources