/* File: timediffthr.c */
/* Chalvatzis Konstantinos */
#include <stdlib.h> /* For exit */
#include <string.h> /* For strings */
#include <unistd.h> /* For fork, read, write, close */
#include <sys/wait.h> /* For wait */
#include <signal.h> /* For signal */
#include <pthread.h> /* For threads */
#include <sys/types.h> /* For sockets */
#include <sys/socket.h> /* For sockets */
#include <netinet/in.h> /* For Internet sockets */
#include <netdb.h> /* For gethostbyaddr */
#include <stdio.h> /* For I/O */
enum bool {FALSE=0, TRUE=1};
void panic (char *s);
void perror2(char *s, int err);
void sig_handler (int sig);
void reverse (char *);
void* daytime (void *arg);
void lathos(char *s);
void errors(char *s);
int h, m;
#define BUFSIZE 1024
#define PRNAME "timediffthr"
int main (int argc, char *argv[]) /* Server with Internet stream sockets */
{
int bytes;
int port, sock, newsock;
socklen_t serverlen, clientlen;
char buf[BUFSIZE];
struct sockaddr_in server, client;
struct sockaddr *serverptr, *clientptr;
struct hostent *rem;
int i, n;
char *tok;
char bufcopy[BUFSIZE];
char seps[] = " \r\n";
enum bool skip;
int *diff;
pthread_t *thr;
int err;
if (argc < 2) { /* Check if server's port number is given */
fprintf (stderr, "timediffthr: Please give the port number\n");
exit (EXIT_FAILURE);
}
/* To be informed when child exits */
signal (SIGCHLD, sig_handler);
/* Create socket */
if ((sock=socket(PF_INET,SOCK_STREAM,0)) < 0)
errors ("socket");
/* Convert port number to integer */
if (sscanf(argv[1],"%d",&port) != 1) {
fprintf (stderr, "timediffthr: invalid port number\n");
exit (EXIT_FAILURE);
}
/* Internet domain */
server.sin_family = PF_INET;
/* My Internet address */
server.sin_addr.s_addr = htonl(INADDR_ANY);
/* The given port */
server.sin_port = htons(port);
serverptr = (struct sockaddr*)&server;
serverlen = sizeof(server);
/* Bind socket to address */
if (bind(sock,serverptr,serverlen) < 0)
errors ("bind");
/* Listen for connections */
if (listen(sock,5) < 0)
errors ("listen");
printf ("Waiting connections to serve time difference requests at port number %d\n", port);
while (TRUE) {
clientptr = (struct sockaddr*)&client;
clientlen = sizeof(client);
/* Accept connection */
if ((newsock=accept(sock,clientptr,&clientlen)) < 0)
errors ("accept");
/* Find client's address */
if ((rem=gethostbyaddr((char*)&client.sin_addr.s_addr,
sizeof(client.sin_addr.s_addr),
client.sin_family)) == NULL)
errors ("gethostbyaddr");
printf ("Accepted connection from %s\n", rem->h_name);
/* Create child for serving the client */
switch (fork()) {
case -1:
errors ("fork");
break;
case 0: /* Child process */
while (TRUE) {
skip = FALSE;
/* Initialize buffer */
bzero (buf, sizeof(buf));
/* Get message */
if ((bytes=read(newsock,buf,sizeof(buf))) < 0)
errors ("read");
if (bytes == 0)
break;
strcpy (bufcopy, buf);
tok = strtok(bufcopy,seps);
if (sscanf(tok,"%d:%d",&h,&m) != 2) {
strcpy (bufcopy, "Syntax error: Syntax is: <hh>:<mm> <host>1 <host2> ... <host>n\n");
skip = TRUE;
}
if ( !skip && (h<0 || h>=24 || m<0 || m>=60)) {
strcpy (bufcopy, "Invalid local time\n");
skip = TRUE;
}
if ( !skip ) {
n = 0;
while ((tok=strtok(NULL,seps)) != NULL)
++n;
if (n == 0) {
strcpy (bufcopy, "Please provide one or more daytime servers\n");
skip = TRUE;
}
}
if ( !skip ) {
printf ("Local time: %d:%02d\n", h, m);
if ((thr=malloc(n*sizeof(pthread_t))) == NULL)
errors ("malloc");
tok = strtok(buf,seps);
i = 0;
while ((tok=strtok(NULL,seps)) != NULL) {
if ((err=pthread_create(&thr[i++],NULL,daytime,tok)) != 0)
perror2 ("pthread_create", err);
}
bytes = 0;
for (i=0; i<n-1; ++i) {
if ((err=pthread_join(thr[i],(void*)&diff)) != 0)
perror2 ("pthread_join", err);
if (diff != NULL)
bytes += sprintf(bufcopy+bytes,"%s%d / ",(*diff>0)?"+":"",*diff);
else
bytes += sprintf(bufcopy+bytes,"%s / ","NotAvailable");
}
if ((err=pthread_join(thr[i],(void*)&diff)) != 0)
perror2 ("pthread_join", err);
if (diff != NULL)
sprintf (bufcopy+bytes, "%s%d\n", (*diff>0)?"+":"", *diff);
else
sprintf(bufcopy+bytes,"%s\n","NotAvailable");
free (diff);
free (thr);
}
bzero (buf, sizeof(buf));
strcpy (buf, bufcopy);
/* Send message */
if (write(newsock,buf,sizeof(buf)) < 0)
errors ("write");
}
printf ("Connection closed by %s\n", rem->h_name);
if (close(newsock) == -1) /* Close socket */
errors ("close");
exit (EXIT_SUCCESS);
break;
default:
break;
}
}
return 0;
}
void* daytime (void *arg)
{
char *servername = arg;
int hs, ms, timecorrect, *diff;
int port, sock;
char buf[BUFSIZE];
socklen_t serverlen;
struct sockaddr_in server;
struct sockaddr *serverptr;
struct hostent *rem;
/* Create socket */
if ((sock=socket(PF_INET,SOCK_STREAM,0)) < 0)
lathos ("socket");
/* Find server address */
if ((rem=gethostbyname(servername)) == NULL)
lathos ("gethostbyname");
port = 13;
server.sin_family = PF_INET; /* Internet domain */
bcopy ((char*)rem->h_addr, (char*)&server.sin_addr,
rem->h_length);
server.sin_port = htons(port);/* Server's Internet address and port */
serverptr = (struct sockaddr*)&server;
serverlen = sizeof(server);
/* Request connection */
if (connect(sock,serverptr,serverlen) < 0)
lathos ("connect");
bzero(buf, sizeof(buf)); /* Initialize buffer */
/* Receive message */
if (read(sock,buf,sizeof(buf)) < 0)
lathos ("read");
if (close(sock) == -1) /* Close socket */
lathos ("close");
if (sscanf(buf,"%*s %*s %*d %d:%d",&hs,&ms) != 2)
lathos ("sscanf");
printf("Thread %d: %s: Daytime is %s", (int)pthread_self(), servername, buf);
if ((diff=malloc(sizeof(int))) == NULL)
lathos ("malloc");
if (ms-m < -30)
timecorrect = -1;
else if (ms-m > 30)
timecorrect = 1;
else
timecorrect = 0;
*diff = hs-h + timecorrect;
if (*diff <= -12)
*diff += 24;
else if (*diff > 12)
*diff -= 24;
printf ("Thread %d: %s: Time difference is %s%d hours\n", (int)pthread_self(), servername, (*diff>0)?"+":"", *diff);
pthread_exit (diff);
return NULL;
}
void sig_handler (int sig) /* Handler for SIGCHLD */
{
int status;
if (sig == SIGCHLD)
wait(&status);
}
void errors(char *s)
{
fprintf (stderr, "%s: ", PRNAME);
perror (s);
exit (EXIT_FAILURE);
}
void perror2(char *s, int err)
{
fprintf (stderr, "%s: %s: %s\n", PRNAME, s, strerror(err));
exit (EXIT_FAILURE);
}
void lathos(char *s)
{
fprintf (stderr, "Thread %d: %s error\n", (int)pthread_self(), s);
pthread_exit (NULL);
}