why recv() changed unrelated variables - c

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.

Related

Bad file descriptor in recvfrom function

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.

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'

C - accept() accepting the same client twice?

I am facing one of the strangest programming problems in my life.
I've built a few servers in the past and the clients would connect normally, without any problems.
Now I'm creating one which is basically a web server. However, I'm facing a VERY strange situation (at least to me).
Suppose that you connect to localhost:8080 and that accept() accepts your connection and then the code will process your request in a separate thread (the idea is to have multiple forks and threads across each child - that's implemented on another file temporarily but I'm facing this issue on that setup as well so...better make it simple first). So your request gets processed but then after being processed and the socket being closed AND you see the output on your browser, accept() accepts a connection again - but no one connects of course because only one connection was created.
errno = 0 (Success) after recv (that's where the program blows up)
recv returns 0 though - so no bytes read (of course, because the connection was not supposed to exist)
int main(int argc, char * argv[]){
int sock;
int fd_list[2];
int fork_id;
/* Socket */
sock=create_socket(PORT);
int i, active_n=0;
pthread_t tvec;
char address[BUFFSIZE];
thread_buffer t_buffer;
int msgsock;
conf = read_config("./www.config");
if(conf == NULL)
{
conf = (config*)malloc(sizeof(config));
if(conf == NULL)
{
perror("\nError allocating configuration:");
exit(-1);
}
// Set defaults
sprintf(conf->httpdocs, DOCUMENT_ROOT);
sprintf(conf->cgibin, CGI_ROOT);
}
while(cicle) {
printf("\tWaiting for connections\n");
// Waits for a client
msgsock = wait_connection(sock, address);
printf("\nSocket: %d\n", msgsock);
t_buffer.msg = &address;
t_buffer.sock = msgsock;
t_buffer.conf = conf;
/* Send socket to thread */
if (pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer) != 0)
{
perror("Error creating thread: ");
exit(-1);
}
}
free(conf);
return 0;
}
Here are two important functions used:
int create_socket(int port) {
struct sockaddr_in server, remote;
char buffer[BUFF];
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_in))) {
perror("binding stream socket");
exit(1);
}
gethostname(buffer, BUFF);
printf("\n\tServidor a espera de ligações.\n");
printf("\tUse o endereço %s:%d\n\n", buffer,port);
if (listen(sock, MAXPENDING) < 0) {
perror("Impossível criar o socket. O servidor vai sair.\n");
exit(1);
}
return(sock);
}
int wait_connection(int serversock, char *remote_address){
int clientlen;
int clientsock;
struct sockaddr_in echoclient;
clientlen = sizeof(echoclient);
/* Wait for client connection */
if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0)
{
perror("Impossivel estabelecer ligacao ao cliente. O servidor vai sair.\n");
exit(-1);
}
printf("\n11111111111111Received request - %d\n", clientsock);
sprintf(remote_address, "%s", inet_ntoa(echoclient.sin_addr));
return clientsock;
}
So basically you'd see:
11111111111111Received request - D
D is different both times so the fd is different definitely.
Twice! One after the other has been processed and then it blows up after recv in the thread function. Some times it takes a bit for the second to be processed and show but it does after a few seconds. Now, this doesn't always happen. Some times it does, some times it doesn't.
It's so weird...
I've rolled out the possibility of being an addon causing it to reconnect or something because Apache's ab tool causes the same issue after a few requests.
I'd like to note that even if I Don't run a thread for the client and simply close the socket, it happens as well! I've considered the possibility of the headers not being fully read and therefore the browsers sends another request. But the browser receives the data back properly otherwise it wouldn't show the result fine and if it shows the result fine, the connection must have been closed well - otherwise a connection reset should appear.
Any tips? I appreciate your help.
EDIT:
If I take out the start thread part of the code, sometimes the connection is accepted 4, 5, 6 times...
EDIT 2: Note that I know that the program blows up after recv failing, I exit on purpose.
This is certainly a bug waiting to happen:
pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer
You're passing t_buffer, a local variable, to your thread. The next time you accept a client, which can happen
before another client finished, you'll pass the same variable to that thread too, leading to a lot of very indeterministic behavior.(e.g. 2 threads reading from the same connection, double close() on a descriptor and other oddities. )
Instead of passing the same local variable to every thread, dynamically allocate a new t_buffer for each new client.
Suppose ... after being processed and the socket being closed AND you see the output on your browser, accept() accepts a connection again - but no one connects of course because only one connection was created.
So if no-one connects, there is nothing to accept(), so this never happens.
So whatever you're seeing, that isn't it.

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.

how read all the server's responses from a socket?

I have a very big problem... I'm working with sockets in C. I send a request to the server which sends me many responses. The problem is that the client receives the first response and then the connection is closed. What can I do? I tried with setsockopt()... SO_KEEPALIVE or SO_LINGER but I haven't resolved the problem. Can you help me? Thanks a lot
To be more clear here is the code. The socket is automatically closed after a certain amount of time or after the client received the first response... I'm not sure.
char* demarre_client( client_args * c_args,char* message, /*char* SERVEUR_PORT*/int port){
int socket_client=socket(PF_INET,SOCK_STREAM,0);
memset(&(c_args->adresse_serveur),0,sizeof(c_args->adresse_serveur));
c_args->adresse_serveur.sin_family=AF_INET;
c_args->adresse_serveur.sin_addr.s_addr=inet_addr(SERVEUR_IP);
//int port=APHash(SERVEUR_PORT,strlen(SERVEUR_PORT));
c_args->adresse_serveur.sin_port=htons(port);
int err=0;
if ((err=connect(socket_client, (struct sockaddr *) &(c_args->adresse_serveur), sizeof(c_args->adresse_serveur)))<0)
{
printf("CONNECT error %d\n", errno);
exit(-1);
}
if (send(socket_client, message, strlen(message), 0)!=strlen(message))
{
printf("send error!!\n");
exit(-2);
}
char* raspFin=(char* )malloc(sizeof(char)*1024);
strcpy(raspFin,"");
int num=-1;
int nn=0;
char* rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
/* here it reads the first response and after he get out of while */
while ((num=recv(socket_client, rasp,1024,MSG_WAITALL))>0)
{
printf("recu %s mun=%d\n" , rasp,num);
strcat(raspFin,rasp);
strcat(raspFin,"\n");
rasp=(char* )malloc(sizeof(char)*1024);
memset (rasp, 0, 1024 * sizeof(char ));
}
if (num<0)
{
printf("rasp error!!\n");
exit(-3);
}
Are you sure you don't get all responses on first call?
TCP/IP is stream protocol without flow control built-in so different messages, sent using separate send() calls, can be received in one recv(). Because you use printf(), it prints the buffer until it sees null-terminator - maybe other responses beyond the terminator?
Try to use some flow control, like sending message length prefix or using some special characters (like STX/ETX, but make sure your message doesn't contain such characters). You'd need to implement some flow-control anyway if you plan to use this software.
For now try replacing your printf() with
char *ptr;
for (ptr = buffer; ptr <= buffer + num; ptr += strlen(ptr)+1;)
printf("%s\n", ptr);
It will print all strings from your response buffer.
And you don't need malloc() inside the loop - you leak memory.
BTW SO_KEEPALIVE and SO_LINGER have nothing to do with this problem.
My suggestion would be to fire up Wireshark network analyzer and see what's happening packet-wise. In filters set
tcp.srcport == <insert_server_port> || tcp.dstport == <insert_server_port>
You should see what data actually gets sent to and who closes the connection (sends FIN/RST packets).

Resources