\File{netserv.c},{12:19},{Feb  6 1997}
\L{\LB{\K{\#include} \S{}\"squid.h\"\SE{}}}
\L{\LB{}}
\L{\LB{\C{}\/* global variable that points to the main host table *\/\CE{}}}
\L{\LB{\K{struct} hostinfo *tablePtr = NULL;}}
\L{\LB{}}
\L{\LB{\C{}\/* default number of points to assign a host *\/\CE{}}}
\L{\LB{\K{int} opt\_points = 1;}}
\L{\LB{}}
\L{\LB{\C{}\/* Junk so we can link with debug.o *\/\CE{}}}
\L{\LB{\K{int} opt\_syslog\_enable = 0;}}
\L{\LB{volatile \K{int} unbuffered\_logs = 1;}}
\L{\LB{const \K{char} *const appname = \S{}\"netserv\"\SE{};}}
\L{\LB{\K{struct} timeval current\_time;}}
\L{\LB{time\_t squid\_curtime;}}
\L{\LB{\K{struct} SquidConfig Config;}}
\L{\LB{}}
\L{\LB{\K{void} nsusage \_PARAMS((\K{char} *name));}}
\L{\LB{\K{int} deal \_PARAMS((\K{char} caddr\_new[MAXADDR], \K{int} newsockfd, time\_t ntime, \K{char} buf[MAXLINE], FILE *logPtr));}}
\L{\LB{\K{int} myexit \_PARAMS(());}}
\L{\LB{}}
\L{\LB{\C{}\/* main loop. start up, wait for connections and deal with them *\/\CE{}}}
\L{\LB{\K{int} main(\K{int} argc, \K{char} *argv[])}}
\L{\LB{\{}}
\L{\LB{  \K{int} sockfd, newsockfd, cli\_len, count;}}
\L{\LB{  \K{struct} sockaddr\_in serv\_addr, cli\_addr;}}
\L{\LB{  \K{int} one = 1;}}
\L{\LB{  FILE *logPtr;}}
\L{\LB{  \K{struct} list *fdlist = NULL;}}
\L{\LB{  \K{struct} timeval timeout;}}
\L{\LB{  \K{extern} \K{char} *optarg;}}
\L{\LB{  \K{int} c;}}
\L{\LB{}}
\L{\LB{  \K{while} ((c = getopt(argc, argv, \S{}\"hp:?\"\SE{})) != \-1) \{}}
\L{\LB{    \K{switch} (c) \{}}
\L{\LB{    \K{case} \S{}\'h\'\SE{}:}}
\L{\LB{      nsusage(argv[0]);}}
\L{\LB{      \K{break};}}
\L{\LB{    \K{case} \S{}\'p\'\SE{}:}}
\L{\LB{      opt\_points = atoi(optarg);}}
\L{\LB{      \K{break};}}
\L{\LB{    \K{case} \S{}\'?\'\SE{}:}}
\L{\LB{    \K{default}:}}
\L{\LB{      nsusage(argv[0]);}}
\L{\LB{      \K{break};}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{  \C{}\/* debugging message *\/\CE{}}}
\L{\LB{  debug(1,0,\S{}\"Starting up...\!n\"\SE{});}}
\L{\LB{}}
\L{\LB{  \C{}\/* open the log file for appending *\/\CE{}}}
\L{\LB{  \K{if} ((logPtr = fopen(NLOG\_FILE,\S{}\"a\"\SE{})) == NULL) \{}}
\L{\LB{    debug(1,0,\S{}\"Can\'t open log file \%s.\!n\"\SE{},NLOG\_FILE);}}
\L{\LB{    exit(\-1);}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* open a socket *\/\CE{}}}
\L{\LB{  \K{if}( (sockfd = socket(AF\_INET, SOCK\_STREAM,0)) \< 0) \{}}
\L{\LB{    perror(\S{}\"socket\"\SE{});}}
\L{\LB{    exit(\-1);}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* clear out and set the struct for the server address *\/\CE{}  }}
\L{\LB{  memset(\&serv\_addr, 0, \K{sizeof}(serv\_addr));}}
\L{\LB{  serv\_addr.sin\_family = AF\_INET;}}
\L{\LB{  serv\_addr.sin\_addr.s\_addr = htonl(INADDR\_ANY);}}
\L{\LB{  serv\_addr.sin\_port = htons(SERV\_PORT);}}
\L{\LB{}}
\L{\LB{  \C{}\/* allow the socket to be reused immediately *\/\CE{}}}
\L{\LB{  setsockopt(sockfd, SOL\_SOCKET, SO\_REUSEADDR, (\K{char} *)\&one, \K{sizeof}(one));}}
\L{\LB{  }}
\L{\LB{  \C{}\/* bind to the socket *\/\CE{}}}
\L{\LB{  \K{if} (bind(sockfd, (\K{struct} sockaddr *) \&serv\_addr, \K{sizeof}(serv\_addr)) \< 0) \{}}
\L{\LB{    perror(\S{}\"bind\"\SE{});}}
\L{\LB{    exit(\-1);}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* list on the socket *\/\CE{}}}
\L{\LB{  listen(sockfd,5);}}
\L{\LB{}}
\L{\LB{  \C{}\/* read in the saved network status from the dump file *\/\CE{}}}
\L{\LB{  readdump();}}
\L{\LB{}}
\L{\LB{  \C{}\/* catch SIGINT and SIGHUP and exit if you get them *\/\CE{}}}
\L{\LB{  signal(SIGINT,(\K{void} *) myexit);}}
\L{\LB{  signal(SIGHUP,(\K{void} *) myexit);}}
\L{\LB{}}
\L{\LB{  \C{}\/* select loop *\/\CE{}}}
\L{\LB{  \K{for}(;;)\{}}
\L{\LB{    fd\_set fdvar;}}
\L{\LB{    \K{struct} list *listPtr, **lastPtr, *currPtr = fdlist;}}
\L{\LB{}}
\L{\LB{    FD\_ZERO(\&fdvar);}}
\L{\LB{    FD\_SET(sockfd,\&fdvar);}}
\L{\LB{    }}
\L{\LB{    \K{while} (currPtr != NULL) \{}}
\L{\LB{      FD\_SET(currPtr\-\>num,\&fdvar);}}
\L{\LB{      currPtr = currPtr\-\>next;}}
\L{\LB{    \}}}
\L{\LB{}}
\L{\LB{    \C{}\/* set the timeout to wait for the client to send something *\/\CE{}}}
\L{\LB{    timeout.tv\_sec = TIMEOUT;}}
\L{\LB{    timeout.tv\_usec = U\_TIMEOUT;}}
\L{\LB{}}
\L{\LB{    \C{}\/* check what file descriptors need managing *\/\CE{}}}
\L{\LB{    count = select(NOFILE,(fd\_set *)\&fdvar,(fd\_set *)0,(fd\_set *)0,\&timeout);}}
\L{\LB{    \K{if} (count \< 0) \{ }}
\L{\LB{      perror(\S{}\"select\"\SE{});}}
\L{\LB{      exit(\-1); }}
\L{\LB{    \} }}
\L{\LB{    \K{if} (count == 0)\{}}
\L{\LB{      time\_t currtime =  time((time\_t *)0);}}
\L{\LB{      lastPtr = \&fdlist;}}
\L{\LB{      \K{while} (*lastPtr != NULL) \{}}
\L{\LB{}\Tab{8}{\K{if} ((currtime \- TIMEOUT) \> (*lastPtr)\-\>ctime) \{}}
\L{\LB{}\Tab{8}{  debug(1,0,\S{}\"Timeout on sockfd \%d.\!n\"\SE{},(*lastPtr)\-\>num);}}
\L{\LB{}\Tab{8}{  close((*lastPtr)\-\>num);}}
\L{\LB{}\Tab{8}{  currPtr= *lastPtr;}}
\L{\LB{}\Tab{8}{  *lastPtr = (*lastPtr)\-\>next;}}
\L{\LB{}\Tab{8}{  free(currPtr);}}
\L{\LB{        \}}}
\L{\LB{        \K{else} \{}}
\L{\LB{}\Tab{8}{  lastPtr = \&(*lastPtr)\-\>next;}}
\L{\LB{        \}}}
\L{\LB{      \}}}
\L{\LB{    \}}}
\L{\LB{    \K{else} \{ }}
\L{\LB{      \K{char} caddr\_new[MAXADDR];}}
\L{\LB{      \K{struct} hostent *hp;}}
\L{\LB{      \K{if} (FD\_ISSET(sockfd,\&fdvar)) \{}}
\L{\LB{}\Tab{8}{cli\_len = \K{sizeof}(cli\_addr);}}
\L{\LB{}\Tab{8}{\K{if} ((newsockfd = accept(sockfd, (\K{struct} sockaddr *) \&cli\_addr, }}
\L{\LB{}\Tab{32}{\&cli\_len)) \< 0) \{}}
\L{\LB{}\Tab{8}{  perror(\S{}\"accept\"\SE{});}}
\L{\LB{}\Tab{8}{  exit(\-1);}}
\L{\LB{}\Tab{8}{\}}}
\L{\LB{}\Tab{8}{\C{}\/* convert the IP address of the host that connected to its cname. *\/\CE{}}}
\L{\LB{}\Tab{8}{hp = gethostbyaddr((const \K{char} *) \&cli\_addr.sin\_addr, \K{sizeof}(cli\_addr.sin\_addr), AF\_INET);}}
\L{\LB{}\Tab{8}{strcpy(caddr\_new,hp\-\>h\_name);}}
\L{\LB{}}
\L{\LB{}\Tab{8}{debug(1,0,\S{}\"\%s connected.\!n\"\SE{},caddr\_new);}}
\L{\LB{    }}
\L{\LB{}\Tab{8}{listPtr = (\K{struct} list *) malloc(\K{sizeof}(\K{struct} list));}}
\L{\LB{}\Tab{8}{listPtr\-\>num = newsockfd;}}
\L{\LB{}\Tab{8}{listPtr\-\>ctime = time((time\_t *)0);}}
\L{\LB{}\Tab{8}{listPtr\-\>next = fdlist;}}
\L{\LB{}\Tab{8}{fdlist = listPtr;}}
\L{\LB{      \}}}
\L{\LB{      }}
\L{\LB{      lastPtr = \&fdlist;}}
\L{\LB{      \K{while} (*lastPtr != NULL) \{}}
\L{\LB{}\Tab{8}{\K{if} (FD\_ISSET((*lastPtr)\-\>num,\&fdvar)) \{}}
\L{\LB{}\Tab{8}{  \K{char} buf[MAXLINE] = \S{}\"\!0\"\SE{};}}
\L{\LB{}\Tab{8}{  read((*lastPtr)\-\>num, buf, MAXLINE);}}
\L{\LB{}\Tab{8}{  deal(caddr\_new, (*lastPtr)\-\>num, (*lastPtr)\-\>ctime,buf,logPtr);}}
\L{\LB{}\Tab{8}{  close((*lastPtr)\-\>num);}}
\L{\LB{}\Tab{8}{  currPtr= *lastPtr;}}
\L{\LB{}\Tab{8}{  *lastPtr = (*lastPtr)\-\>next;}}
\L{\LB{}\Tab{8}{  free(currPtr);}}
\L{\LB{}\Tab{8}{\}}}
\L{\LB{}\Tab{8}{\K{else} \{}}
\L{\LB{}\Tab{8}{  lastPtr = \&(*lastPtr)\-\>next;}}
\L{\LB{}\Tab{8}{\}}}
\L{\LB{      \}}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{  close(sockfd); }}
\L{\LB{  fclose(logPtr);}}
\L{\LB{\}}}
\L{\LB{}}
\L{\LB{\C{}\/* print a usage message *\/\CE{}}}
\L{\LB{\K{void} nsusage(\K{char} *name) \{}}
\L{\LB{  fprintf(stderr, \S{}\"Usage: \%s [\-h] [\-p points]\!n\"\SE{}}}
\L{\LB{          \S{}\"       \-p points Set the default number of points.\!n\"\SE{}}}
\L{\LB{          \S{}\"       \-h        Get this help message.\!n\"\SE{},name);}}
\L{\LB{  myexit();}}
\L{\LB{\}}}
\L{\LB{}}
\L{\LB{\C{}\/* check what we received and call the appropriate function *\/\CE{}}}
\L{\LB{\K{int} deal(\K{char} caddr\_new[MAXADDR], \K{int} newsockfd, time\_t ntime, \K{char} buf[MAXLINE], FILE *logPtr) \{}}
\L{\LB{  \K{int} reply\_len, retval;}}
\L{\LB{  \K{char} reply[MAXLINE] = \S{}\"\!0\"\SE{};}}
\L{\LB{  ntime = time((time\_t *)0);}}
\L{\LB{}}
\L{\LB{  \C{}\/* check for a join request *\/\CE{}}}
\L{\LB{  \K{if} ((strncmp(buf,\S{}\"join\"\SE{},4)) == 0) \{}}
\L{\LB{}}
\L{\LB{    \C{}\/* get the number of points if given *\/\CE{}}}
\L{\LB{    \K{int} num;}}
\L{\LB{    \K{char} s[5];}}
\L{\LB{    \K{if} (sscanf(buf, \S{}\"\%s \%d\"\SE{}, s, \&num) != 2) \{}}
\L{\LB{      num = opt\_points;}}
\L{\LB{    \}}}
\L{\LB{    \C{}\/* try to add the host to the network *\/\CE{}}}
\L{\LB{    retval = addhost(caddr\_new,ntime,num);}}
\L{\LB{    }}
\L{\LB{    \C{}\/* if the host was added... *\/\CE{}}}
\L{\LB{    \K{if} ( retval == 0) \{}}
\L{\LB{      }}
\L{\LB{      \C{}\/* Write this to the log file and flush it *\/\CE{}}}
\L{\LB{      fprintf(logPtr,\S{}\"+ \%s \%d \%d\!n\"\SE{},caddr\_new,(\K{int}) ntime, num);}}
\L{\LB{      fflush(logPtr);}}
\L{\LB{}}
\L{\LB{      \C{}\/* reply to the client *\/\CE{}}}
\L{\LB{      sprintf(reply, \S{}\"200 You have been added to the network.\!n\"\SE{});}}
\L{\LB{      reply\_len = strlen(reply);}}
\L{\LB{      write(newsockfd,reply,reply\_len);}}
\L{\LB{      debug(1,0,\S{}\"\%s joined at \%d with \%d points.\!n\"\SE{},caddr\_new,(\K{int}) ntime,num);}}
\L{\LB{    \}}}
\L{\LB{}}
\L{\LB{    \C{}\/* if the host is already in the network, tell the client that *\/\CE{}}}
\L{\LB{    \K{else} \K{if} (retval == 1)\{}}
\L{\LB{      sprintf(reply, \S{}\"401 Duplicate address, not added.\!n\"\SE{});}}
\L{\LB{      reply\_len = strlen(reply);}}
\L{\LB{      write(newsockfd,reply,reply\_len);}}
\L{\LB{      debug(1,0,\S{}\"Duplicate request from \%s at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{    \C{}\/* for other errors *\/\CE{}}}
\L{\LB{    \K{else} \{}}
\L{\LB{      debug(1,0,\S{}\"Couldn\'t add new host \%s to network at \%d.\!n\"\SE{}, caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* check for dele requests *\/\CE{}}}
\L{\LB{  \K{else} \K{if} ((strncmp(buf,\S{}\"dele\"\SE{},4)) == 0) \{}}
\L{\LB{}}
\L{\LB{    \C{}\/* try to delete the host from the network *\/\CE{}}}
\L{\LB{    retval = delhost(caddr\_new);}}
\L{\LB{}}
\L{\LB{    \C{}\/* if it was successfully deleted... *\/\CE{}}}
\L{\LB{    \K{if} ( retval == 0 )\{}}
\L{\LB{}}
\L{\LB{      \C{}\/* write this to the log file and flush it *\/\CE{}}}
\L{\LB{      fprintf(logPtr,\S{}\"\- \%s \%d\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{      fflush(logPtr);}}
\L{\LB{}}
\L{\LB{      \C{}\/* reply to the client *\/\CE{}}}
\L{\LB{      sprintf(reply, \S{}\"200 You have been deleted from the network.\!n\"\SE{});}}
\L{\LB{      reply\_len = strlen(reply);}}
\L{\LB{      write(newsockfd,reply,reply\_len);}}
\L{\LB{      debug(1,0,\S{}\"\%s deleted at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{}}
\L{\LB{    \C{}\/* if the address was not in the network, tell the client that *\/\CE{}}}
\L{\LB{   \K{else} \K{if} (retval == 1)\{}}
\L{\LB{      sprintf(reply, \S{}\"401 No such address, not deleted.\!n\"\SE{});}}
\L{\LB{      reply\_len = strlen(reply);}}
\L{\LB{      write(newsockfd,reply,reply\_len);}}
\L{\LB{      debug(1,0,\S{}\"No such address to delete as \%s at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{    }}
\L{\LB{    \C{}\/* for other errors *\/\CE{}}}
\L{\LB{    \K{else} \{}}
\L{\LB{      debug(1,0,\S{}\"Couldn\'t delete host \%s from network at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* check for list requests *\/\CE{}}}
\L{\LB{  \K{else} \K{if} ((strncmp(buf,\S{}\"list\"\SE{},4)) == 0)\{}}
\L{\LB{}}
\L{\LB{    \C{}\/* print the list out to this connection *\/\CE{}}}
\L{\LB{    \K{if} ((list(newsockfd)) == 0)\{}}
\L{\LB{      debug(1,0,\S{}\"\%s requested a listing at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* check for help requests *\/\CE{}}}
\L{\LB{  \K{else} \K{if} ((strncmp(buf,\S{}\"help\"\SE{},4)) == 0)\{}}
\L{\LB{}}
\L{\LB{    \C{}\/* reply to the client *\/\CE{}}}
\L{\LB{    sprintf(reply,\S{}\"100 Possible commands are:\!n\!t join [\<points\>]\!n\!t dele\!n\!t list\!n\!t since \<time\>\!n\!t help\!n\"\SE{});}}
\L{\LB{    reply\_len = strlen(reply);}}
\L{\LB{    write(newsockfd,reply,reply\_len);}}
\L{\LB{    debug(1,0,\S{}\"Help request from \%s at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* check for since requests *\/\CE{}}}
\L{\LB{  \K{else} \K{if} ((strncmp(buf,\S{}\"since\"\SE{},5)) == 0) \{}}
\L{\LB{    \C{}\/* get the time argument *\/\CE{}}}
\L{\LB{    \K{int} *stimePtr = malloc(\K{sizeof}(\K{int}));}}
\L{\LB{    \K{char} s[6];}}
\L{\LB{    \K{if} (sscanf(buf,\S{}\"\%s \%d\"\SE{},s,stimePtr) == 2) \{}}
\L{\LB{    }}
\L{\LB{      \C{}\/* print the since information out to this connection *\/\CE{}}}
\L{\LB{      \K{if} ((since(newsockfd,*stimePtr)) == 0) \{}}
\L{\LB{}\Tab{8}{debug(1,0,\S{}\"Since \%d request from \%s at \%d.\!n\"\SE{},*stimePtr,caddr\_new,(\K{int}) ntime);}}
\L{\LB{      \}}}
\L{\LB{    \}}}
\L{\LB{    }}
\L{\LB{    \C{}\/* for other errors *\/\CE{}}}
\L{\LB{    \K{else} \{}}
\L{\LB{      sprintf(reply, \S{}\"400 Invalid since request.\!n\"\SE{});}}
\L{\LB{      reply\_len = strlen(reply);}}
\L{\LB{      write(newsockfd,reply,reply\_len);}}
\L{\LB{      debug(1,0,\S{}\"Invalid since request from \%s at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{    \}}}
\L{\LB{  \}}}
\L{\LB{}}
\L{\LB{  \C{}\/* otherwise, we have an unknown request *\/\CE{}}}
\L{\LB{  \K{else} \{}}
\L{\LB{    \C{}\/* reply to the client *\/\CE{}}}
\L{\LB{    sprintf(reply, \S{}\"400 Unknown request.\!n\"\SE{});}}
\L{\LB{    reply\_len = strlen(reply);}}
\L{\LB{    write(newsockfd,reply,reply\_len);}}
\L{\LB{    debug(1,0,\S{}\"Unknown request from \%s at \%d.\!n\"\SE{},caddr\_new,(\K{int}) ntime);}}
\L{\LB{  \}}}
\L{\LB{  \K{return}(0);}}
\L{\LB{\}}}
\L{\LB{}}
\L{\LB{}}
\L{\LB{\C{}\/* dump and exit on a signal *\/\CE{}}}
\L{\LB{\K{int} myexit() \{}}
\L{\LB{  debug(1,0,\S{}\"exiting.\!n\"\SE{});}}
\L{\LB{  \K{if} ((dump()) != 0) \{}}
\L{\LB{    debug(1,0,\S{}\"Error in dumping network status, data may be lost.\!n\"\SE{});}}
\L{\LB{  \}}}
\L{\LB{  exit(0);}}
\L{\LB{\}}}
