views:

161

answers:

1

My problem is quite infuriating, actually. I'll show you the code first.

/*
** listener.c -- a datagram sockets "server" demo
*/
//Original Code: Brian Hall ([email protected])
//Commented and modified by Vishal Kotcherlakota (PID A07124450)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define MYPORT "4960" // the port users will be connecting to
#define YOURPORT "4961"
#define MAXBUFLEN 10000 

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
 //If the socket address struct says it's an IPv4...
 if (sa->sa_family == AF_INET) {
  //...return the IPv4 variable.
  return &(((struct sockaddr_in*)sa)->sin_addr);
 }
 //otherwise, assume it's IPv6, and get the IPv6 variable
 return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[])
{
 int sockfd, sockfdAck; //socket file descriptor (handle)
 struct addrinfo hints, *servinfo, *p, *q;
 int rv;
 int numbytes;
 unsigned int seqNum, stateNum=0, ackNum;
 struct sockaddr_storage their_addr;
 struct timeval recvTime, timeStamp, latency;
 char buf[MAXBUFLEN], junk[MAXBUFLEN];
 size_t addr_len;
 char *ackBack;
 char s[INET6_ADDRSTRLEN];

 if (argc != 2)
 {
  fprintf(stderr, "usage: <executable> <hostname>\n");
  exit(0);
 }

 memset(&hints, 0, sizeof hints);
 hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
 hints.ai_socktype = SOCK_DGRAM;
 hints.ai_flags = AI_PASSIVE; // use my IP

 if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
  return 1;
 }

 // loop through all the results and bind to the first we can
 for(q = servinfo; q != NULL; q = q->ai_next) {
  if ((sockfd = socket(q->ai_family, q->ai_socktype,
    q->ai_protocol)) == -1) {
   perror("listener: socket");
   continue;
  }

  if (bind(sockfd, q->ai_addr, q->ai_addrlen) == -1) {
   close(sockfd);
   perror("listener: bind");
   continue;
  }

  break;
 }

 if (q == NULL) {
  fprintf(stderr, "listener: failed to bind socket\n");
  return 2;
 }

 freeaddrinfo(servinfo);

 memset(&hints, 0, sizeof hints);
 hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
 hints.ai_socktype = SOCK_DGRAM;

 if ((rv = getaddrinfo(argv[1], BACKPORT, &hints, &servinfo)) != 0) {
  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
  return 1;
 }

 // loop through all the results and bind to the first we can
 for(p = servinfo; p != NULL; p = p->ai_next) {
  if ((sockfdAck = socket(p->ai_family, p->ai_socktype,
    p->ai_protocol)) == -1) {
   perror("listener: socket");
   continue;
  }

  break;
 }

 if (p == NULL) {
  fprintf(stderr, "listener: failed to bind socket\n");
  return 2;
 }

 freeaddrinfo(servinfo);
  printf("listener: waiting to recvfrom...\n");
 while (1)
 {

  addr_len = sizeof their_addr;
  if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
   (struct sockaddr *)&their_addr, &addr_len)) == -1) {
   perror("recvfrom");
   exit(1);
  }

  /*printf("listener: got packet from %s\n",
   inet_ntop(their_addr.ss_family,
    get_in_addr((struct sockaddr *)&their_addr),
    s, sizeof s));
  printf("listener: packet is %d bytes long\n", numbytes);
  */
  buf[numbytes] = '\0';
  sscanf(buf,"%u %s",&seqNum, junk);
  if (seqNum == stateNum + 1)
  {
   stateNum = seqNum;
   printf("Ok, state is now %u.\n", stateNum);
  }
  ackBack = malloc(20*sizeof(char));
  sprintf(ackBack, "%u acknowledged\0", stateNum);
  numbytes = sendto(sockfdAck, ackBack, strlen(ackBack), 0, p->ai_addr, p->ai_addrlen);
  if (numbytes == -1);
  {
   perror("sendto");
   exit(1);
  }
  free(ackBack);
 }

 return 0;
}

Please forgive the sloppy code; I'm desperately trying to finish this assignment on time. The goal is to develop an ARQ protocol using datagram sockets. This code should work, but when I run it, I get an error sendto: Success, meaning that my sendto() call failed. I can't find documentation for this anywhere, and I'm getting to be extremely desperate.

+4  A: 

It has nothing to do with having to bind() - in fact take a look at this syntax:

            if (numbytes == -1);
            {
                    perror("sendto");
                    exit(1);
            }

you have a condidion without the body, and then the body without the condition, which always executes (as you can observe:).

Add the printf of numbytes and you will see it is set correct, there is no error.

To avoid this kind of hard-to-see errors, I generally put the opening brace immediately after the condition - then you would have spotted this immediately. But of course this is a matter of the coding convention for the company/project.

Andrew Y
It is indeed always the little things. Thank you so very much!
Vishal Kotcherlakota
Yes you are right, I answered too quickly.