/** * @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); }