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