0

So I'm using Unix Domain Socket (datagram) to communicate between two processes on my machine. The client sends queries to the server which is making some calculations and returns the result to the client.

My server receives queries from the client using recvfrom(), and my problem is that on the first time recvfrom() is being called, it does not set struct sockaddr *restrict address which is the address of the sender.

This happens only on the first time recvfrom() is being called, the following queries are working perfectly fine.

What am I doing wrong here?

client.c:

/* relevant code from client.c */

sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);

memset(&client, 0, sizeof(client));
client.sun_family = AF_UNIX;
strcpy(client.sun_path, CLIENT_PATH);

bind(sockfd, (struct sockaddr *)&client, sizeof(struct sockaddr_un);

memset(&server, 0, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, SERVER_PATH);

while(1) {

  FD_ZERO(&readfds);
  FD_SET(sockfd, &readfds);
  FD_SET(STDIN, &readfds);

      select(sockfd+1, &readfds, NULL, NULL, NULL);


      if (FD_ISSET(STDIN, &readfds)) {
          nbytes = read(STDIN, buf, sizeof buf);
          buf[nbytes] = '\0';
          if (sendto(sockfd, buf, strlen(buf), 0,
                  (struct sockaddr *)&server,
                  sizeof(struct sockaddr_un)) < strlen(buf)) {
              perror("send");
          }
      }

      if (FD_ISSET(sockfd, &readfds)) {
          if ((nbytes = recvfrom(sockfd, buf, MAXDATASIZE, 0, NULL, NULL)) < 0) {
              perror("recv");
          }
          buf[nbytes] = '\0';
          printf(">> %s", buf);
      }
}

server.c:

/* relevant code from server.c */


FD_ZERO(&master);
FD_ZERO(&read_fds);


  if ((client = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
      perror("client socket");
      exit(3);
  }

  memset(&server, 0, sizeof(struct sockaddr_un));
  server.sun_family = AF_UNIX;
  strcpy(server.sun_path, SOCK_PATH);

  unlink(server.sun_path);
  if (bind(client, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
      perror("uds bind");
      exit(3);
  }

  FD_SET(client, &master);

  // keep track of the biggest file descriptor
  fdmax = client; //so far, it's this one

  // main loop
  for(;;) {
      read_fds = master; // copy it
      if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
          perror("select");
          exit(4);
      }

      // run through the existing connections looking for data to read
      for(i = 0; i <= fdmax; i++) {
          if (FD_ISSET(i, &read_fds)) { // we got one!!
                  if (i == client) {
                      // data is from client console
                      if ((nbytes = recvfrom(i, &buf, sizeof buf, 0, (struct sockaddr *)&client_addr, &remotelen)) <= 0) {
                          if (nbytes == 0) {
                              FD_CLR(i, &master);
                              close(i);
                          } else {
                              perror("client: recv");
                          }
                      }

                      buf[nbytes-1] = '\0';
                      if (strcmp(buf, "command-1") == 0) {
                          if ((nbytes = sendto(i, cmd1_str, strlen(cmd1_str), 0, (struct sockaddr *)&client_addr, remotelen)) < 0) {
                              perror("sendto");
                          }
                          buf[0] = '\0';
                      } else {
                          sendto(i, unknown_str, strlen(unknown_str), 0, (struct sockaddr *)&client_addr, remotelen);
                          buf[0] = '\0';
                      }
                  }     
              } 
          } // END got new incoming connection
      } // END looping through file descriptors
  } // END for(;;)--and you thought it would never end!

Code was trimmed a to include only what's supposed to be important and relevant. Please, if anything important is missing, let me know and I'll add it.

Quaker
  • 1,483
  • 3
  • 20
  • 36
  • Where do you define, and more importantly *initialize* the `remotelen` variable? – Some programmer dude Apr 04 '15 at 11:24
  • check the return value you get from `select()` The fd_sets are only usable if select returns > zero. – wildplasser Apr 04 '15 at 11:25
  • @JoachimPileborg, I define it earlier in the code, and I don't initialize it, I thought that `recvfrom()` does that, as long as initializing `client_addr`. – Quaker Apr 04 '15 at 11:26
  • @wildplasser, it is a part of the code that was trimmed by me, I am checking for errors in `select()` and there are no. – Quaker Apr 04 '15 at 11:26
  • 2
    You *must* initialize the address length, it's used by `recvfrom` to decide what kind of address structure the `address` points to. *Always* read the [manual page](http://man7.org/linux/man-pages/man2/recvfrom.2.html), where this is stated very clearly. – Some programmer dude Apr 04 '15 at 11:29

0 Answers0