0

I am trying to send and receive in different threads. When I use the code below I get a bad address error, I guess because my server address could not be properly passed to the thread function.

Code:

#include "client.h"
struct global_table{
 struct sockaddr_in *serveraddr;
 int sockID;
};
void *recvFromServer(struct global_table *rec){
 char recBuf[RECVBUFSIZE];
 int serverSize = sizeof(rec->serveraddr);
 while(1)
 {
 int n = recvfrom(rec->sockID, recBuf, RECVBUFSIZE, 0, &rec->serveraddr, &serverSize);
 if (n < 0)
 perror("ERROR in recvfrom");
 decryptData(recBuf);
 printf("Recieved: %s\n", recBuf);
 pthread_exit(NULL);
 }
}
void pingServer(char *hostname, int portno)
{
 int sockfd, n, serverlen;
 struct sockaddr_in serveraddr;
 struct sockaddr_in client_addr; 
 struct hostent *server;
 char *buf;
 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 if (sockfd < 0) 
 perror("ERROR opening socket");
 server = gethostbyname(hostname);
 if (server == NULL) 
 perror("ERROR, no host found");
 bzero((char *) &serveraddr, sizeof(serveraddr));
 serveraddr.sin_family = AF_INET;
 bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, server->h_length);
 serveraddr.sin_port = htons(portno);
 client_addr.sin_family = AF_INET;
 client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 client_addr.sin_port = htons(5500);
 if (bind(sockfd,(struct sockaddr *)&client_addr, sizeof(struct sockaddr)) == -1)
 perror("Socket could not be binded");
 if(setsockopt(sockfd,IPPROTO_IP,IP_TOS,&tos,sizeof(tos)))
 perror("Could not set socket option");
 pthread_t threads[2];
 serverlen = sizeof(serveraddr);
 struct global_table server_info;
 server_info.sockID = sockfd;
 server_info.serveraddr = &serveraddr;
 pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread
 pthread_join(threads[0],NULL);
}
int main(int argc, char **argv) {
 char *hostname;
 int portno;
 if (argc != 3)
 perror("usage: <hostname> <port>\n");
 hostname = argv[1];
 portno = atoi(argv[2]);
 pingServer(hostname, portno);
 return 0;
}

How can I fix the problem?

asked May 4, 2017 at 15:49
9
  • It works on the main thread. I think the way it should be passed to struct and then get the address is problematic. Commented May 4, 2017 at 15:56
  • looks like too much indirection on that recvfrom call, is the compiler complaining. &rec->serveraddr shoudl surely be rec->serveraddr Commented May 4, 2017 at 15:56
  • If i run everything on the main thread, the code works fine. No errors on compile time. Commented May 4, 2017 at 15:57
  • 2
    struct global_table contains a pointer to struct sockaddr_in, and you take the address of that pointer to pass to recvfrom() -- that's one too many levels of indirection. Also, you point the serveraddr member at a struct that's local to the pingServer() function, then try to use it after that function returns (via the thread you created right before returning)... the struct isn't valid anymore then, and you'd have undefined behaviour even if the indirection were correct. Commented May 4, 2017 at 15:59
  • 1
    server_info lives on pingServer()'s stack which is invalid a wink after the pthread_create() returned. Also the whole process, along with all it's threads ends another wink later, the moment main() returns. To fix this you could for example add a call to pthread_join() after having created the thread. Commented May 4, 2017 at 16:37

1 Answer 1

1

In addition to the problems noted in the comments (and by now, this problem is also noted in the comments...), this line

struct global_table server_info;

creates a local variable in your pingServer() function.

This line

pthread_create(&threads[0],NULL,recvFromServer, &server_info); // Trying to recv on a different thread

of code passes the address of that variable to the recvFromServer() function, which will run in a different thread. But then pingServer() immediately returns and the local server_info variable ceases to exist.

One fix is to define the server_info and serveraddr variable as static:

static struct global_table server_info;
static struct sockaddr_in serveraddr;

That will create one copy of the server_info variable that will be shared by every invocation of pingServer(), but that one copy will exist for the lifetime of your program.

Hassan Abbas
1,3161 gold badge22 silver badges50 bronze badges
answered May 4, 2017 at 16:05
Sign up to request clarification or add additional context in comments.

3 Comments

I get your point but still this does not resolve the issue. The error it says at run time is "ERROR in recvfrom: Bad address".
It's not just struct global_table server_info, but also struct sockaddr_in serveraddr which server_info.serveraddr gets pointed at that would need to be static. And, that would still mean he couldn't later call pingServer() more than once to have more than one thread at a time.
@Dmitri Absolutely true.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.