Unix – Time Server – Sockets

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