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