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?

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.

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

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.