jade-raw-recv.c

/**
 * @file jade-raw-recv.c
 * @date October 14, 2010
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/timex.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct sockaddr    sockaddr;
typedef struct sockaddr_in sockaddr_in;
typedef struct timespec    timespec;

/**
 * Receives all data from the server.  For each line of text received from the
 * server, this function prints the server text and the time when the text was
 * received.
 *
 * @param fd The file descriptor for the socket.
 */
static int recv_all(int fd)
{
  /* Loop until the server has sent all its data. */
  for (;;) {
    char     msg[100];
    timespec now;
    char *   ptr;
    int      result;

    /* Receive the line of text from the server and check for errors. */
    if (0 > (result = recv(fd, msg, sizeof(msg) - 1, 0))) {
      perror("recv");
      return EXIT_FAILURE;
    }

    /* Check for the end of the data. */
    if (0 == result)
      return EXIT_SUCCESS;

    /* Get the current time for the client. */
    if (0 != clock_gettime(CLOCK_REALTIME, &now)) {
      perror("clock_gettime");
      return EXIT_FAILURE;
    }

    /* Parse the data from the server; it should end with "\r\n". Ignore lines
     * that are bad. */
    if (NULL == (ptr = strstr(msg, "\r\n"))) {
      printf(
        "\t%lu.%09lu\r\n",
        (unsigned long)now.tv_sec,
        (unsigned long)now.tv_nsec);
      continue;
    }

    /* Do not display the EOL in the line the client prints. */
    *ptr = '\0';

    /* Print the output, the server's time and then the client's time,
     * separated by a '\t'. */
    printf(
      "%s\t%lu.%09lu\r\n",
      msg,
      (unsigned long)now.tv_sec,
      (unsigned long)now.tv_nsec);
  }

  /* Return successfully. */
  return EXIT_SUCCESS;
}

/**
 * Connects to the server and then receives data from the server until the
 * server closes the connection.
 *
 * @param host The host IP address.
 * @param port The port number.
 *
 * @param EXIT_SUCCESS if successful; otherwise, EXIT_FAILURE.
 */
int connect_and_recv(const char * host, unsigned short port)
{
  int         fd;
  int         result;
  sockaddr_in sin;

  /* Create the socket for TCP/IP communications. */
  if (-1 == (fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
    perror("socket");
    return EXIT_FAILURE;
  }

  /* Prepare the socket address to connect to. */
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port   = htons(port);
  if (0 >= inet_pton(AF_INET, host, &sin.sin_addr)) {
    fprintf(stderr, "Invalid host IP address '%s'.\n", host);
    close(fd);
    return EXIT_FAILURE;
  }

  /* Connect to the server. */
  printf("Connecting to %s on port %hu...\n", host, port);
  if (-1 == connect(fd, (sockaddr *)&sin, sizeof(sin))) {
    perror("connect");
    close(fd);
    return EXIT_FAILURE;
  }

  /* Receive all data from the server. */
  result = recv_all(fd);

  /* Shutdown and close the socket. */
  shutdown(fd, SHUT_RDWR);
  close(fd);

  /* Return the result. */
  return result;
}

/**
 * The main entry point of the program.  This function checks for syntax
 * errors, displays usage if requested, and then connects to the server.
 *
 * @param argc The number of command-line arguments.
 * @param argv The command-line arguments.
 *
 * @return EXIT_SUCCESS if successful; otherwise, EXIT_FAILURE.
 */
int main(int argc, char * argv[])
{
  unsigned short port;

  /* Check for the "--help" option. */
  if (argc == 2 && 0 == strcmp("--help", argv[1])) {
    puts("usage: jade-raw-recv host port");
    puts("Implements Jade's raw receive program.");
    puts("");
    puts("  host  The host IP address (not host name)");
    puts("  port  The port number used by the server when listening for connections");
    puts("");
    return EXIT_SUCCESS;
  }

  /* Check for the correct number of arguments. */
  if (argc != 3) {
    fputs("The syntax of the command is incorrect.\n", stderr);
    return EXIT_FAILURE;
  }

  /* Parse the port number. */
  if (1 != sscanf(argv[2], "%hu", &port)) {
    fprintf(stderr, "Invalid port %s.\n", argv[2]);
    return EXIT_FAILURE;
  }

  /* Connect to the server and return the result. */
  return connect_and_recv(argv[1], port);
}
Valid HTML 4.01 Valid CSS