Perry's Lab Two Answer
#include "funcs.h"
#define MAXLINE 256
#define QUIT "9"
#define TERMINATOR '\01'
int active;
int readn (char *buf, int bytes);
int writen(char *buf, int bytes);
int main(int argc, char **argv)
{
char *GetTokens(void);
char QuitPacket[MAXLINE], replyline[MAXLINE], packet[MAXLINE], *username;
char LegalFirstChars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
FILE *more;
void ConnectToServer(void), SetUpSignals(void);
SetUpSignals();
ConnectToServer();
while (username = GetTokens(), username ? strcmp(username, QUIT) : 1)
{
if (!username) continue;
if (strchr(LegalFirstChars, *username) == NULL)
{
printf ("Usernames start with a letter or underscore!\n");
continue;
}
/*
*** Send username packet to server.
***
*/
memset(packet, 0, MAXLINE);
memcpy(packet, username, MAXLINE);
writen(packet, 1);
writen(packet + 1, MAXLINE - 1);
/*
*** Get login info lines for username from server.
*/
more = Popen("more", "w");
while (readn(replyline, MAXLINE), *replyline != TERMINATOR)
fprintf(more, "%s\n", replyline);
Pclose(more);
}
/*
*** Send quit packet after normal exit.
*/
memset(QuitPacket, 0, MAXLINE);
strcpy(QuitPacket, QUIT);
writen(QuitPacket, 1);
writen(QuitPacket + 1, MAXLINE - 1);
}
void SetUpSignals(void)
{
struct sigaction sa;
void handler(int signum);
Sigfillset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = 0;
Sigaction(SIGPIPE, &sa, NULL);
Sigaction(SIGQUIT, &sa, NULL);
Sigaction(SIGINT, &sa, NULL);
Sigaction(SIGALRM, &sa, NULL);
}
void handler(int signum)
{
char QuitPacket[MAXLINE];
memset(QuitPacket, 0, MAXLINE);
strcpy(QuitPacket, QUIT);
switch (signum)
{
case SIGPIPE: printf("Server disconnected!\n");
exit(0);
case SIGQUIT:
case SIGINT:
case SIGALRM: writen(QuitPacket, 1);
writen(QuitPacket + 1, MAXLINE - 1);
exit(0);
}
}
void ConnectToServer()
{
struct sockaddr_in sin;
active = Socket(AF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(3777);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("153.18.17.12");
Connect(active, (struct sockaddr *)&sin, sizeof(sin));
}
char *GetTokens(void)
{
static char line[MAXLINE], *username, *extra = NULL;
printf("Enter username (9 to quit): ");
alarm(50);
fgets(line, MAXLINE, stdin);
alarm(0);
username = strtok(line, "\040\t\n");
if (username) extra = strtok(NULL, "\040\t\n");
if (extra)
{
printf("Only one username per request!\n");
return NULL;
}
return username;
}
int readn(char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(active,mover,nleft)) < 0)
return -1; /**** Error!! ****/
else if (nread == 0)
break; /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(active,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
#include "funcs.h"
#define MAXLINE 256
#define QUIT '9'
#define TERMINATOR '\01'
struct whonode
{
char wholine[MAXLINE];
struct whonode *next;
};
typedef struct whonode WHONODE;
WHONODE *list;
int readn(int active, char *buffer, int buffer_size);
int writen(int active, char *buffer, int buffer_size);
pid_t pid;
main()
{
struct sigaction sa;
int passive, active;
socklen_t addr_len;
char username[MAXLINE];
struct sockaddr_in client;
int CreatePassiveSocket(void);
void SetUpSignals(void);
void FindSendWhoLines(int active, WHONODE *list, char *username);
WHONODE *MakeWhoList(void);
SetUpSignals();
passive = CreatePassiveSocket();
addr_len = sizeof(struct sockaddr_in);
while (1) /***** Server stays alive for ever!!! *****/
{
active = accept(passive, (struct sockaddr *)&client, &addr_len);
if (active < 0)
{
if (errno == EINTR)
{
errno = 0;
continue;
}
else
{
perror("Accept error!");
exit(1);
}
}
pid = Fork();
if (pid != 0) /****** Parent ******/
{
Close(active);
continue;
}
else /****** Child ******/
{
sa.sa_flags = 0;
sa.sa_handler = SIG_DFL;
Sigfillset(&sa.sa_mask);
Sigaction(SIGCHLD, &sa, NULL);
list = MakeWhoList();
while(alarm(30), memset(username, 0, MAXLINE),
readn(active, username, MAXLINE), *username != QUIT)
{
alarm(0);
FindSendWhoLines(active, list, username);
}
exit(0); /***** Don't forget this!!!!! *****/
}
} /*** end while(1) ***/
}
/************** Handle timeout/disappearance of client **************/
void SetUpSignals(void)
{
struct sigaction sa;
void handler(int signum);
Sigfillset(&sa.sa_mask); /**** Take care of signals. ****/
sa.sa_flags = 0;
sa.sa_handler = handler;
Sigaction(SIGALRM, &sa, NULL);
Sigaction(SIGPIPE, &sa, NULL);
Sigaction(SIGCHLD, &sa, NULL);
}
int CreatePassiveSocket(void)
{
struct sockaddr_in sin;
int passive;
passive = Socket(AF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(sin));
sin.sin_port = htons(3777);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
Bind(passive, (struct sockaddr *)&sin, (socklen_t) sizeof(sin));
Listen(passive, 1);
return passive;
}
void handler(int signum)
{
int status;
switch (signum)
{
case SIGCHLD: while (waitpid(-1, &status, WNOHANG) > 0);
break;
case SIGALRM:
case SIGPIPE: exit(0);
}
}
WHONODE *MakeWhoList(void)
{
WHONODE *list, *prev, *cur, *new;
FILE *who;
char wholine[MAXLINE], tempwho[MAXLINE], *username;
/*
*** Make dummy header/trailer of ordered list.
*/
list = (WHONODE *) Malloc(sizeof(WHONODE));
strcpy(list->wholine, "");
list->next = (WHONODE *) Malloc(sizeof(WHONODE));
strcpy(list->next->wholine, "\177");
list->next->next = NULL;
who = Popen("who", "r");
while (fgets(wholine, MAXLINE, who))
{
prev = list;
cur = list->next;
strcpy(tempwho, wholine);
username = strtok(tempwho, "\040\t");
while (strcmp(username, cur->wholine) > 0)
{
prev = cur;
cur = cur->next;
}
new = (WHONODE *) Malloc(sizeof(WHONODE));
prev->next = new;
new->next = cur;
strcpy(new->wholine, wholine);
}
Pclose(who);
return list;
}
void FindSendWhoLines(int active, WHONODE *list, char *username)
{
int result;
char resultline[MAXLINE], tempwho[MAXLINE], *searchuser;
do
{
list = list->next;
strcpy(tempwho, list->wholine);
searchuser = strtok(tempwho, "\040\t");
}
while (strcmp(username, searchuser) > 0);
if ((result = strcmp(username, searchuser)) < 0) /* User not found */
{
memset(resultline, 0, MAXLINE);
strcpy(resultline, "User not logged in!\n");
writen(active, resultline, 1);
writen(active, resultline + 1, MAXLINE - 1);
memset(resultline, 0, MAXLINE);
*resultline = TERMINATOR;
writen(active, resultline, 1);
writen(active, resultline + 1, MAXLINE - 1);
}
else /* result == 0 */
{
do
{
memset(resultline, 0, MAXLINE);
strcpy(resultline, list->wholine);
writen(active, resultline, 1);
writen(active, resultline + 1, MAXLINE - 1);
list = list->next;
strcpy(tempwho, list->wholine);
searchuser = strtok(tempwho, "\040\t");
}
while (strcmp(username, searchuser) == 0);
memset(resultline, 0, MAXLINE);
*resultline = TERMINATOR;
writen(active, resultline, 1);
writen(active, resultline + 1, MAXLINE - 1);
}
}
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
else if (nread == 0)
break; /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
/******************************** Session Output **************************/
$ s&
[1] 18656
$ c
Enter username (9 to quit): foo
User not logged in!
Enter username (9 to quit):
Enter username (9 to quit): perry
perry pts/1 May 5 02:03 (user-2ivfmtn.dialup.mindspring.com)
perry pts/8 May 5 00:34 (user-2ivfmtn.dialup.mindspring.com)
Enter username (9 to quit): quit
User not logged in!
Enter username (9 to quit): 9
$ c
Enter username (9 to quit):
[2]+ Stopped c
$ c /* Prove multi-user */
Enter username (9 to quit): perry
perry pts/1 May 5 02:03 (user-2ivfmtn.dialup.mindspring.com)
perry pts/8 May 5 00:34 (user-2ivfmtn.dialup.mindspring.com)
Enter username (9 to quit):
Enter username (9 to quit): 9
$ c
Enter username (9 to quit): foobar
User not logged in!
Enter username (9 to quit): 9
$ fg /*** Bring back alarmed-out client ***/
c
foobar
Server disconnected! /*** SIGPIPE on client side!! ***/
$ c
Enter username (9 to quit): tran
tran pts/5 May 4 14:50 (153.18.17.99)
Enter username (9 to quit): 9