1 /* -----------------------------------------------------------------------------
2  * web.c
3  *
4  *     This file implements the web-server.
5  *
6  * Author(s) : David Beazley (beazley@cs.uchicago.edu)
7  *             Sotiria Lampoudi (slampoud@cs.uchicago.edu)
8  *             Mike Sliczniak (mzsliczn@midway.uchicago.edu)
9  *
10  * Copyright (C) 1999-2000.  The University of Chicago
11  * See the file LICENSE for information on usage and redistribution.
12  * ----------------------------------------------------------------------------- */
13 
14 static char cvsroot[] = "$Header: /home/pastacvs/cvs-rep/vermicelli/tot/src/SWILL-0.1/Source/SWILL/web.c,v 1.4 2005/01/28 12:24:34 dillema Exp $";
15 
16 #include "swillint.h"
17 
18 /*
19 #define __USE_MPI
20 #undef __USE_MPI
21 */
22 
23 #ifdef __USE_MPI
24 #include <mpi.h>
25 #endif
26 
27 /* Server info */
28 
29        int     SwillInit    = 0;
30 static int     SwillSocket  = -1;
31 static int     SwillPort    = 0;
32 static String *SwillTitle   = 0;
33 static String *SwillDocroot = 0;
34        int     SwillTimeout = SWILL_TIMEOUT;
35 
36 static FILE   *SwillFile    = 0;
37 
38 #ifdef __USE_MPI
39 static int _swill_mpi_rank, _swill_mpi_numprocs;
40 #endif
41 
42 /* Global variables containing information about the current request */
43 static Hash   *http_out_headers = 0;
44 static String *http_uri         = 0;
45 static String *http_response    = 0;
46 static Hash   *current_request  = 0;
47 
48 /* -----------------------------------------------------------------------------
49  * Utility functions for setting/getting headers and form vars
50  * ----------------------------------------------------------------------------- */
51 
swill_setheader(const char * header,const char * value)52 void swill_setheader(const char *header, const char *value) {
53   Setattr(http_out_headers,header,value);
54 }
55 
swill_setresponse(const char * value)56 void swill_setresponse(const char *value) {
57   if (http_response) Delete(http_response);
58   http_response = NewString(value);
59 }
60 
swill_getheader(const char * header)61 char *swill_getheader(const char *header) {
62   Hash *headers;
63   char temp[1024];
64   char *c;
65   strcpy(temp,header);
66   c = temp;
67   while (*c) {
68     *c = tolower(*c);
69     c++;
70   }
71   headers = Getattr(current_request,"headers");
72   if (headers) {
73     return GetChar(headers,temp);
74   } else {
75     return 0;
76   }
77 }
78 
swill_getvar(const char * name)79 char *swill_getvar(const char *name) {
80   Hash *query = Getattr(current_request,"query");
81   if (query) {
82     return GetChar(query,name);
83   }
84   return 0;
85 }
86 
swill_getint(const char * name)87 int swill_getint(const char *name) {
88   Hash *query = Getattr(current_request,"query");
89   if (query) {
90     return GetInt(query,name);
91   }
92   return 0;
93 }
94 
swill_getdouble(const char * name)95 double swill_getdouble(const char *name) {
96   Hash *query = Getattr(current_request,"query");
97   if (query) {
98     return GetDouble(query,name);
99   }
100   return 0;
101 }
102 
103 /* -----------------------------------------------------------------------------
104  * swill_init()
105  * ----------------------------------------------------------------------------- */
106 
107 int
swill_init(int port)108 swill_init(int port) {
109   struct sockaddr_storage servaddr;
110   struct sockaddr_in6 *sin6;
111   struct sockaddr_in *sin;
112   int flag = 1;
113   char hname[256];
114 
115   assert(!SwillInit);
116 
117   if (!SwillFile) {
118     SwillFile = tmpfile();
119     assert(SwillFile);
120   }
121 
122   SwillSocket = -1;
123   SwillPort = 0;
124 
125 #ifdef __USE_MPI
126   /*MPI_Init(&argc, &argv); */
127   /* we don't call MPI_Init(), we expect that the host code has done it for us.
128    *  --TL
129    */
130   MPI_Comm_size(MPI_COMM_WORLD,&_swill_mpi_numprocs);
131   MPI_Comm_rank(MPI_COMM_WORLD,&_swill_mpi_rank);
132 
133 #endif
134 
135   signal(SIGPIPE, SIG_IGN);
136 
137   DohEncoding("url",swill_url_encoder);
138   DohEncoding("pre",swill_pre_encoder);
139 
140 #ifdef __USE_MPI
141   if(_swill_mpi_rank == 0) {
142 #endif
143 
144     /* Open up the server socket */
145 #ifdef USE_INET6
146     SwillSocket = socket(AF_INET6, SOCK_STREAM, 0);
147 #else
148     SwillSocket = socket(AF_INET, SOCK_STREAM, 0);
149 #endif
150 
151     if (SwillSocket < 0) {
152       printf("swill_init: Can't create socket!\n");
153       /* Maybe some kind of MPI reduce here */
154       SwillInit = SwillPort = 0;
155       goto init_ret;
156       /*return 0; */
157     }
158 
159     /* Re-use the address if possible */
160     if (setsockopt(SwillSocket,SOL_SOCKET, SO_REUSEADDR,(char *)&flag,sizeof(int)) < 0) {
161       perror("setsockopt");
162     }
163 
164     /* Set the server address */
165     bzero(&servaddr, sizeof(servaddr));
166 #ifdef USE_INET6
167     sin6 = (struct sockaddr_in6 *) &servaddr;
168     sin6->sin6_len = sizeof (struct sockaddr_in6);
169     sin6->sin6_family = AF_INET6;
170     sin6->sin6_port = htons(port);
171     sin6->sin6_addr = in6addr_any;
172 #else
173     sin = (struct sockaddr_in *) &servaddr;
174     sin->sin_len = sizeof (struct sockaddr_in);
175     sin->sin_family = AF_INET;
176     sin->sin_port = htons(port);
177     sin->sin_addr.s_addr = htonl(INADDR_ANY);
178 #endif
179 
180     /* Bind the socket to the port */
181     if (bind(SwillSocket,
182              (struct sockaddr *) &servaddr,
183              servaddr.ss_len) < 0) {
184       printf("swill_init: Can't bind to port %d!\n", port);
185       perror("bind");
186       /* Maybe some kind of MPI reduce here */
187       SwillInit = SwillPort = 0;
188       goto init_ret;
189       /*      return 0; */
190     }
191 
192     /* Allow, at most, 5 outstanding network connections */
193     listen(SwillSocket, 5);
194 
195     /* Get port assigned to the socket */
196     {
197       struct  sockaddr_in  socketname;
198       int     inlen = sizeof(socketname);
199       if (getsockname(SwillSocket, (struct sockaddr *) &socketname,  &inlen) >= 0) {
200 	SwillPort = ntohs(socketname.sin_port);
201       }
202     }
203 #ifdef __USE_MPI
204   } else {
205     /* Need to place some initialization code here */
206   }
207 #endif
208   SwillTitle = NewString("SWILL");
209   SwillDocroot = 0;
210   SwillInit = 1;
211   swill_security_init();
212   swill_handle("info",SH(SwillListHandlers),0);
213 
214  init_ret:
215 #ifdef __USE_MPI
216   MPI_Bcast(&SwillInit, 1,MPI_INT, 0, MPI_COMM_WORLD);
217 #endif
218   return SwillPort;
219 }
220 
221 /* -----------------------------------------------------------------------------
222  * swill_close()
223  *
224  * Close the server
225  * ----------------------------------------------------------------------------- */
226 
227 void
swill_close()228 swill_close() {
229   if (!SwillInit) return;
230   if (SwillSocket > 0) {
231     close(SwillSocket);
232   }
233   fclose(SwillFile);
234   SwillFile = 0;
235   SwillSocket = 0;
236   Delete(SwillTitle);
237   Delete(SwillDocroot);
238   SwillTitle = 0;
239   SwillDocroot = 0;
240   SwillInit = 0;
241   swill_handler_reset();
242   swill_security_reset();
243 }
244 
245 /* -----------------------------------------------------------------------------
246  * swill_title()
247  *
248  * Set or return the server title.
249  * ----------------------------------------------------------------------------- */
250 
251 char *
swill_title(const char * title)252 swill_title(const char *title) {
253   if (!SwillInit) return 0;
254   if (title)
255     SwillTitle = NewString(title);
256   return Char(SwillTitle);
257 }
258 
259 /* -----------------------------------------------------------------------------
260  * swill_directory()
261  *
262  * Set the document root for serving arbitrary files.
263  * ----------------------------------------------------------------------------- */
264 
265 char *
swill_directory(const char * pathname)266 swill_directory(const char *pathname) {
267   if (!SwillInit) return 0;
268   if (pathname) {
269     if (SwillDocroot) Delete(SwillDocroot);
270     if (strlen(pathname)) {
271       SwillDocroot = NewString(pathname);
272     } else {
273       SwillDocroot = 0;
274     }
275   }
276   return SwillDocroot ? Char(SwillDocroot) : 0;
277 }
278 
279 /* -----------------------------------------------------------------------------
280  * swill_timeout()
281  *
282  * Send the timeout value.
283  * ----------------------------------------------------------------------------- */
284 
285 void
swill_timeout(int timeout)286 swill_timeout(int timeout) {
287   SwillTimeout =  timeout;
288 }
289 
290 /* -----------------------------------------------------------------------------
291  * check_filename()
292  *
293  * Checks a filename to see if it is legal or not.  Does not allow any
294  * path component to start with a '.'
295  * ----------------------------------------------------------------------------- */
296 
297 static int
check_filename(String * fn)298 check_filename(String *fn) {
299   int ch;
300   int state = 0;
301   Seek(fn,0,SEEK_SET);
302   while (1) {
303     ch = Getc(fn);
304     if (ch == EOF) return 1;
305     if ((ch == '.') && (state)) return 0;
306     if (ch == '.') state++;
307     else state = 0;
308   }
309 }
310 
311 /* -----------------------------------------------------------------------------
312  * swill_nbwrite()
313  *
314  * Non-blocking write to a socket
315  * ----------------------------------------------------------------------------- */
316 
317 static int
swill_nbwrite(int fd,char * buffer,int len)318 swill_nbwrite(int fd, char *buffer, int len) {
319   fd_set          wset;
320   struct timeval  tv;
321   int             nsent = 0;
322   int             retval;
323   int             n;
324 
325   FD_ZERO(&wset);
326   while (nsent < len) {
327     FD_SET(fd,&wset);
328     tv.tv_sec = SwillTimeout;
329     tv.tv_usec = 0;
330 
331     retval = select(fd+1,0,&wset,0,&tv);
332     if (retval <= 0) {
333       /* Timeout.  We're history. */
334       swill_logprintf("   Warning: write timeout!\n");
335       return nsent;
336     }
337     n = write(fd,buffer+nsent,len-nsent);
338     if (n < 0) {
339       if (errno != EWOULDBLOCK) {
340 	return nsent;
341       }
342       continue;
343     }
344     nsent += n;
345   }
346   return nsent;
347 }
348 
349 static int
swill_nbcopydata(FILE * in,int fd)350 swill_nbcopydata(FILE *in, int fd) {
351   char buffer[16384];
352   int nread;
353   int total = 0;
354   while (1) {
355     nread = Read(in,buffer,16384);
356     if (nread < 0) {
357       if (errno != EINTR) {
358 	return total;
359       }
360       continue;
361     }
362     if (nread == 0) break;
363     if (swill_nbwrite(fd,buffer,nread) != nread) {
364       return total;
365     }
366     total += nread;
367   }
368 }
369 
370 /* -----------------------------------------------------------------------------
371  * swill_dump_page()
372  *
373  * Dumps the raw page to the socket.
374  * ----------------------------------------------------------------------------- */
375 
376 static int
swill_dump_page(File * webpage,int fd)377 swill_dump_page(File *webpage, int fd) {
378   String *tmp;
379   String *key;
380   int     nbytes;
381   int     val;
382 
383   Seek(webpage, 0, SEEK_END);
384   nbytes = Tell(webpage);
385   Seek(webpage,0, SEEK_SET);
386 
387   /* Put the socket in non-blocking I/O mode */
388   val = fcntl(fd, F_GETFL, 0);
389   fcntl(fd, F_SETFL, val | O_NONBLOCK);
390 
391   tmp = NewStringf("HTTP/1.0 %s\n", http_response);
392 
393   if (swill_nbwrite(fd, Char(tmp), Len(tmp)) != Len(tmp)) {
394     goto send_error;
395   }
396   key = Firstkey(http_out_headers);
397   while (key) {
398     Clear(tmp);
399     Printf(tmp,"%s: %s\n", key, Getattr(http_out_headers,key));
400     if (swill_nbwrite(fd, Char(tmp), Len(tmp)) != Len(tmp)) {
401       goto send_error;
402     }
403     key = Nextkey(http_out_headers);
404   }
405   Clear(tmp);
406   if (nbytes) {
407     Printf(tmp,"Content-Length: %d\n", nbytes);
408   }
409   Printf(tmp,"Server: SWILL/%d.%d\n", SWILL_MAJOR_VERSION, SWILL_MINOR_VERSION);
410   Printf(tmp,"Connection: close\n");
411   Printf(tmp,"\n");
412   if (swill_nbwrite(fd, Char(tmp), Len(tmp)) != Len(tmp)) {
413     goto send_error;
414   }
415 
416   swill_nbcopydata(webpage,fd);
417 
418   /* Restore flags */
419   fcntl(fd, F_SETFL, val);
420   if (tmp) Delete(tmp);
421   return nbytes;
422  send_error:
423   if (tmp) Delete(tmp);
424   fcntl(fd, F_SETFL,val);
425   return 0;
426 }
427 
428 /* -----------------------------------------------------------------------------
429  * swill_serve_file()
430  *
431  * Serves a local file.  Returns -1 if unsuccessful.
432  * uri is the input URL, out is the output stream, and clientfd is the
433  * integer fd of the socket.
434  * ----------------------------------------------------------------------------- */
435 
436 static int
swill_serve_file(String * uri,File * out,int clientfd)437 swill_serve_file(String *uri, File *out, int clientfd) {
438   String *filename, *of;
439   char *cfilename;
440   FILE *f;
441   int   fileok = 0;
442   struct stat info;
443 
444   filename = NewString("");
445   Printf(filename,"%s/%s",SwillDocroot,uri);
446 
447   if (SwillDocroot) {
448     if (Strncmp(filename,SwillDocroot,Len(SwillDocroot)) == 0) {
449       String *tfilename = NewString(Char(filename)+Len(SwillDocroot));
450       fileok = check_filename(tfilename);
451       Delete(tfilename);
452     }
453   } else {
454     fileok = check_filename(filename);
455   }
456 
457   if (fileok) {
458     /* Get some statistics about the file */
459   filetry:
460     cfilename = (char *) Data(filename);
461     if (lstat(cfilename,&info) < 0) {
462       SwillFileNotFound(out,0);
463       Delete(filename);
464       return -1;
465     }
466     if (S_ISDIR(info.st_mode)) {
467       /* Hmmm. Appears to be a directory.  If the directory does not have a trailing "/"
468          We need to redirect the browser */
469       if (cfilename[strlen(cfilename)-1] != '/') {
470 	swill_setresponse("301 Moved Permanently");
471 	of = NewString("");
472 	Printf(of,"http://%s/%s/", swill_getheader("host"), uri);
473 	swill_setheader("location",(char *) of);
474 	swill_setheader("Content-Type","text/html");
475 	Printf(out,"<h1>Moved permanently</h1>\n");
476 	Delete(filename);
477 	return -1;
478       }
479       Printf(filename,"%s",SWILL_DEFAULT);
480       goto filetry;
481     }
482     f = fopen((char *)Data(filename),"r");
483     if (!f) {
484       SwillFileNotFound(out,0);
485       Delete(filename);
486       return -1;
487     }
488     swill_setheader("Content-Type", swill_guess_mimetype(Char(filename)));
489     SetInt(http_out_headers,"Content-Length",info.st_size);
490 
491     /* Dump web-page so far */
492     swill_dump_page(out,clientfd);
493 
494     {
495       int val = fcntl(clientfd, F_GETFL,0);
496       fcntl(clientfd, F_SETFL, val | O_NONBLOCK);
497       swill_nbcopydata(f,clientfd);
498       fcntl(clientfd, F_SETFL, val);
499     }
500     fclose(f);
501     Delete(filename);
502     return 0;
503   } else {
504     SwillFileNotFound(out,0);
505     Delete(filename);
506     return -1;
507   }
508 }
509 
510 /* -----------------------------------------------------------------------------
511  * swill_serve_one()
512  *
513  * This function handles a raw http-request on a single processor. This is the
514  * entry point to the server on a multiprocessor application.  Tasks performed
515  * at this stage include:
516  *
517  *     -  Serving of simple files or directories
518  *     -  User authentication
519  *     -  Error messages for invalid web pages.
520  *     -  Redirection.
521  *
522  * If the request was an error or applicable to a single processor, NULL is
523  * returned.
524  *
525  * Otherwise, an output object is returned and some global variables are set.
526  * The caller can use this to figure out how to call the handling function.
527  *
528  * P.S. This function is a big mess...
529  * ----------------------------------------------------------------------------- */
530 
531 static FILE *
swill_serve_one(struct sockaddr * clientaddr,int clientfd)532 swill_serve_one(struct sockaddr *clientaddr, int clientfd)
533 {
534   Hash         *handler;
535   SwillHandler whandle;
536   FILE        *out = 0;
537   String      *excess;
538   String      *requeststring;
539   Hash        *request;
540   String      *method;
541   String      *peerip;
542   char 	      addr[INET6_ADDRSTRLEN];
543 
544   /* Compute the peer IP address */
545   if (clientaddr->sa_family == AF_INET) {
546     struct sockaddr_in *sin_p = (struct sockaddr_in *) clientaddr;
547     peerip = NewString(inet_ntop(sin_p->sin_family, (void *) &sin_p->sin_addr,
548                        addr,sizeof(addr)));
549   }
550 #ifdef USE_INET6
551   if (clientaddr->sa_family == AF_INET6) {
552     struct sockaddr_in6 *sin6_p = (struct sockaddr_in6 *) clientaddr;
553     peerip = NewString(inet_ntop(sin6_p->sin6_family, (void *) &sin6_p->sin6_addr,
554                        addr,sizeof(addr)));
555   }
556 #endif
557 
558   /* Implement IP filtering here */
559   if (!swill_check_ip(peerip)) {
560     Delete(peerip);
561     return 0;
562   }
563 
564   swill_logprintf("%-64s ", peerip);
565 
566   /* Read the raw HTTP request */
567   if (!swill_read_rawrequest(clientfd, &requeststring, &excess)) {
568     /* Bad request. Too big, malformed, etc. */
569     Delete(peerip);
570     swill_logprintf("Bad request\n");
571     return 0;
572   }
573 
574   /* Try to parse into a request */
575   request = swill_parse_request_headers(requeststring);
576   if (!request) {
577     Delete(peerip);
578     Delete(excess);
579     Delete(requeststring);
580     swill_logprintf("Malformed request\n");
581     return 0;
582   }
583 
584   /* If we made it this far, the initial HTTP request looks valid */
585   Delete(requeststring);
586 
587   method = Getattr(request,"method");
588 
589   /* If a logfile is available, print some information about the request */
590   {
591     time_t t;
592     struct tm *tms;
593     char ts[256];
594     t = time(NULL);
595     tms = localtime(&t);
596     strftime(ts,64,"[%d %b %y %H:%M:%S]", tms);
597     swill_logprintf("%s %s %s\n", ts, method, Getattr(request,"uri"));
598   }
599 
600   Setattr(request,"peername", peerip);
601   Delete(peerip);
602 
603   /* Handle query string data here */
604   if (Strcmp(method,"POST") == 0) {
605     int length;
606     String *posts;
607     Hash   *headers;
608     requeststring = Getattr(request,"request");
609     headers = Getattr(request,"headers");
610     Seek(requeststring, 0, SEEK_END);
611     Append(requeststring,excess);            /* Add excess data */
612     length = GetInt(headers,"content-length");
613     if (length > 0) {
614       posts = swill_read_post(clientfd,length,excess);
615       if (posts) {
616 	if (Len(posts) > Len(excess)) {
617 	  Append(requeststring, Char(posts) + Len(excess));
618 	}
619 	Delete(posts);
620       } else {
621 	Delete(excess);
622 	Delete(request);
623 	return 0;
624       }
625     }
626   }
627   Delete(excess);
628 
629   if (!swill_parse_request_data(request)) {
630     Delete(request);
631     return 0;
632   }
633 
634   /* Request has been parsed and all form variables are set */
635 
636   /* Set global variables */
637   http_uri        = Getattr(request,"uri");
638   current_request = request;
639 
640   /* Create output headers */
641 
642   http_out_headers = NewHash();
643   /*  Setattr(http_out_headers,"Cache-Control","no-cache"); */
644   Setattr(http_out_headers,"Expires","Sat, 1 Jan 2000 00:00:00 GMT");
645   Setattr(http_out_headers,"Pragma","nocache");
646   swill_setresponse("200 OK");
647 
648   /* Create an output object */
649   out = SwillFile;
650   ftruncate(fileno(out),0);
651   fseek(out,0, SEEK_SET);
652 
653   /* Check for user authorization here */
654   if (!swill_checkuser()) {
655     SwillAuthenticate(out,0);
656     Setattr(http_out_headers,"WWW-Authenticate","Basic");
657     goto handled_request;
658   }
659 
660   /* Check if method is valid */
661   if (!(Strcmp(method,"GET") == 0) && !(Strcmp(method,"POST") == 0)) {
662       SwillUnsupported(out,0);
663       goto handled_request;
664   }
665 
666   /* See if there is a handler function registered for this URI */
667   handler = swill_handler_lookup(http_uri);
668   if (handler) {
669 
670     /* A user handler was registered.  If it is the special "info" handler or a file, we just run it here.
671        Otherwise, we will return to the caller */
672 
673     /* Set default mime-type of return page */
674 
675     swill_setheader("Content-Type", GetChar(handler,"mimetype"));
676     whandle = (SwillHandler) Data(Getattr(handler,"handler"));
677 
678     if (whandle) {
679       /* Only serve the handler if its the special info page */
680       if (Cmp(http_uri,"info") == 0) {
681 	(*whandle)(out,Data(Getattr(handler,"clientdata")));
682 	goto handled_request;
683       }
684 
685       /* We actually got a valid request for something that we will
686 	 return to the user.  In this case, we simply return the output object */
687 
688       return out;
689     } else {
690       /* No callback function.  A simple file */
691       FILE *f;
692       char *filename;
693       filename = Data(Getattr(handler,"filename"));
694       f = fopen(filename,"r");
695       if (!f) {
696 	SwillFileNotFound(out,0);
697 	goto handled_request;
698       } else {
699 	/* Find out the length */
700 	struct stat info;
701 	fstat(fileno(f),&info);
702 	SetInt(http_out_headers,"Content-Length",info.st_size);
703 	swill_dump_page(out,clientfd);
704 	{
705 	  int val = fcntl(clientfd, F_GETFL,0);
706 	  fcntl(clientfd, F_SETFL, val | O_NONBLOCK);
707 	  swill_nbcopydata(f,clientfd);
708 	  fcntl(clientfd, F_SETFL, val);
709 	}
710 	fclose(f);
711 	out = 0;
712 	goto handled_request;
713       }
714     }
715   }
716 
717   /* No handler registered.  Maybe we can pull something out of a directory of files */
718 
719   /* See if a document root has been set */
720   if (!SwillDocroot) {
721     SwillFileNotFound(out,0);
722     goto handled_request;
723   }
724   if (swill_serve_file(http_uri,out,clientfd) >= 0) {
725     out = 0;
726   }
727 
728 /* This code is called when the request has been handled by this function */
729 
730 handled_request:
731 
732   if (out) {
733     /* Dump the web-page out.  We handled it on a single processor */
734     fflush(out);
735     swill_dump_page(out,clientfd);
736   }
737 
738   /* Cleanup */
739   Delete(current_request);
740   Delete(http_out_headers);
741   return 0;
742 }
743 
744 /* -----------------------------------------------------------------------------
745  * swill_serve()
746  * ----------------------------------------------------------------------------- */
747 
748 
749 #ifndef __USE_MPI
750 int
swill_serve()751 swill_serve() {
752   struct sockaddr_storage clientaddr;
753   int clientfd, len = sizeof(clientaddr);
754   int oldstdout;
755 
756   FILE *out = 0;
757   if (!SwillInit) {
758     return 0;
759   }
760 
761   /* Wait for a connection */
762   /* This is where that DoS prevention code should go !! */
763   clientfd = accept(SwillSocket, (struct sockaddr *) &clientaddr, &len);
764   if (clientfd < 0) return 0;
765 
766   /* Go process request */
767 
768   out = swill_serve_one((struct sockaddr *)&clientaddr,clientfd);
769   if (!out) {
770     /* swill_serve_one() took care of everything.  Goodbye */
771     close(clientfd);
772     return 1;
773   } else {
774     SwillHandler  whandle;
775     Hash         *handler;
776     File         *of;
777 
778     handler = swill_handler_lookup(http_uri);
779     assert(handler);   /* we're hosed if this is broken */
780 
781     whandle = (SwillHandler) Data(Getattr(handler,"handler"));
782     assert(whandle);
783 
784     /* Note : the stdout flag is set to capture stdout */
785     if (Getattr(handler,"stdout")) {
786       /* This is a very sneaky horrible trick.  We swap in a new file descriptor for stdout. */
787       fflush(stdout);
788       oldstdout = dup(1);       /* Duplicate the file descriptor for stdout */
789       /* Now dup2 the output stream onto stdout */
790       dup2(fileno(out),1);
791     }
792 
793     /* Call the handler */
794     (*whandle)(out,Data(Getattr(handler,"clientdata")));
795 
796     if (Getattr(handler,"stdout")) {
797       /* Restore the old stdout file descriptor */
798       fflush(stdout);
799       dup2(oldstdout,1);
800       close(oldstdout);
801     }
802     fflush(out);
803     /* Dump the web-page here */
804     swill_dump_page(out,clientfd);
805 
806     /* Delete the other fields */
807     Delete(current_request);
808     Delete(http_out_headers);
809   }
810   close(clientfd);
811   return 1;
812 }
813 
814 #elif defined __USE_MPI
815 
816 /* MPI version */
817 
818 int
swill_serve()819 swill_serve() {
820   struct sockaddr_in clientaddr;
821   int clientfd, len = sizeof(clientaddr);
822   int oldstdout;
823 
824   FILE *out = 0;
825 
826   String *request = 0;
827   int request_len = 0;
828   char *tmp_request = 0;
829 
830   if (!SwillInit) {
831     return 0;
832   }
833 
834   if ( _swill_mpi_rank == 0){
835     /* Wait for a connection */
836     /* This is where that DoS prevention code should go !! */
837     clientfd = accept(SwillSocket, (struct sockaddr *) &clientaddr, &len);
838 
839     if (clientfd < 0){
840       request = 0;
841       goto bcast_serve;
842     }
843 
844     out = swill_serve_one((struct sockaddr *)&clientaddr,clientfd);
845     if (!out) {
846       close(clientfd);
847       request = 0;
848       goto bcast_serve;
849     } else {
850       /* Need to regenerate a request to send to other nodes */
851       request = Getattr(current_request,"request");
852       request_len = Len(request);
853       tmp_request = Char(request);
854     }
855   } /* whether NULL or not, we have a request string. --TL */
856 
857  bcast_serve:
858   MPI_Bcast(&request_len, 1, MPI_INT, 0, MPI_COMM_WORLD);
859   if( request_len){
860     if(_swill_mpi_rank){
861       tmp_request = (char *)malloc(sizeof(char) * request_len+1);
862     }
863 
864     MPI_Bcast(tmp_request, request_len+1, MPI_CHAR, 0, MPI_COMM_WORLD);
865 
866     if(_swill_mpi_rank){
867       request = NewString(tmp_request);
868     }
869     free(tmp_request);
870 
871     /* now build up the information you need to execute this;
872      * this obviates the need for setting the parameters accessible to node0,
873      * since it is easier for everyone to recompute them. --TL
874      */
875 
876     /* This function builds the needed data structures from
877        the received request string */
878 
879     if(_swill_mpi_rank){
880       current_request = swill_parse_request(request);
881     }
882     http_out_headers = NewHash();
883     http_uri         = Getattr(current_request,"uri");
884     /* We need to call the handler here */
885     {
886       FILE *out;
887       String *tmp_merged_out;
888       SwillHandler  whandle;
889       Hash   *handler;
890       int    out_size = 0;
891       int    tmp_out_size = 0;
892       char   *tmp_out = 0;
893       String *tmp_out_string = 0;
894       int    i = 0;
895       MPI_Status status;
896       String *outs;
897 
898       handler = swill_handler_lookup(http_uri);
899       assert(handler);   /* we're hosed if this is broken */
900 
901       whandle = (SwillHandler) Data(Getattr(handler,"handler"));
902       assert(whandle);
903 
904       /* Create an output object */
905       out = SwillFile;
906       ftruncate(fileno(out),0);
907       fseek(out,0, SEEK_SET);
908 
909       swill_setheader("Content-Type", GetChar(handler,"mimetype"));
910       swill_setresponse("200 OK");
911 
912       /* Note : the stdout flag is set to capture stdout */
913       if (Getattr(handler,"stdout")) {
914 	/* This is a very sneaky horrible trick.  We swap in a new file descriptor for stdout. */
915 	fflush(stdout);
916 	oldstdout = dup(1);       /* Duplicate the file descriptor for stdout */
917 	/* Now dup2 the output stream onto stdout */
918 	dup2(fileno(out),1);
919       }
920 
921       (*whandle)(out,Data(Getattr(handler,"clientdata")));
922 
923       if (Getattr(handler,"stdout")) {
924 	/* Restore the old stdout file descriptor */
925 	fflush(stdout);
926 	dup2(oldstdout,1);
927 	close(oldstdout);
928       }
929       fflush(out);
930       out_size = Tell(out);
931 
932       /* do fd initialization */
933       if( _swill_mpi_rank == 0){
934         tmp_out_string = NewString("");
935         /* first dump master */
936 	Seek(out, 0, SEEK_SET);
937 	Copyto(out, tmp_out_string);
938       }
939 
940       for(i = 1; i < _swill_mpi_numprocs; i ++){
941 
942         if( _swill_mpi_rank == i ){
943 
944           MPI_Send(&out_size, 1, MPI_INT, 0, i , MPI_COMM_WORLD);
945 	  outs = NewString("");
946 	  Seek(out, 0, SEEK_SET);
947 	  Copyto(out, outs);
948           MPI_Send(Char(outs), out_size, MPI_CHAR, 0, i + 1024, MPI_COMM_WORLD);
949 	  Delete(outs);
950 
951         } else if(_swill_mpi_rank == 0){
952 
953           MPI_Recv(&tmp_out_size, 1, MPI_INT, i, i, MPI_COMM_WORLD, &status);
954           tmp_out = (char*) malloc(sizeof(char)*tmp_out_size);
955           MPI_Recv(tmp_out, tmp_out_size, MPI_CHAR, i, i + 1024,
956                    MPI_COMM_WORLD, &status);
957 	  Write(tmp_out_string, tmp_out, tmp_out_size);
958 	}
959       }
960       if( _swill_mpi_rank == 0){
961         swill_dump_page(tmp_out_string, clientfd);
962 	Delete(tmp_out_string);
963         close(clientfd);
964       }
965     }
966     if(!_swill_mpi_rank == 0)
967       Delete(request);
968 
969     Delete(current_request);
970     http_out_headers = 0;
971     return 0;
972   }
973   else {
974     /* probably just served a file
975      * could also be one of a number of problems,
976      * what the heck! return 0
977      */
978     return 0;
979   }
980   /* everyone return 0? --TL */
981   return 0;
982 }
983 
984 #endif
985 
986 /* -----------------------------------------------------------------------------
987  * swill_poll()
988  *
989  * See if there are any pending connections and handle them if so. Otherwise
990  * return.
991  * ----------------------------------------------------------------------------- */
992 /* non MPI version */
993 
994 #ifndef __USE_MPI
995 
swill_poll()996 int swill_poll() {
997   fd_set  rset;
998   struct  timeval  tv;
999   int     ret;
1000 
1001   if (!SwillInit) return 0;
1002 
1003   tv.tv_sec = 0;
1004   tv.tv_usec = 0;
1005 
1006   FD_ZERO(&rset);
1007   FD_SET(SwillSocket,&rset);
1008   ret = select(SwillSocket+1,&rset,0,0,&tv);
1009   if (ret <= 0) {
1010     return 0;
1011   }
1012   if (FD_ISSET(SwillSocket,&rset)) {
1013     return swill_serve();
1014   } else {
1015     return 0;
1016   }
1017 }
1018 
1019 #endif
1020 
1021 #ifdef __USE_MPI
1022 
1023 /* MPI version of swill_poll() */
1024 
swill_poll()1025 int swill_poll() {
1026   int serve_flag;
1027   fd_set  rset;
1028   struct  timeval  tv;
1029   int     ret;
1030 
1031   /* we use swill_poll() to reach some agreement as to whether we need to do
1032    * something. swill_serve() will actually do the work. --TL
1033    */
1034   if (!SwillInit) return 0;
1035 
1036   if(_swill_mpi_rank == 0 ){
1037     /* master */
1038     if (SwillSocket < 0) {
1039       serve_flag = 0;
1040       goto bcast_poll;
1041     }
1042 
1043     tv.tv_sec = 0;
1044     tv.tv_usec = 0;
1045 
1046     FD_ZERO(&rset);
1047     FD_SET(SwillSocket,&rset);
1048     ret = select(SwillSocket+1,&rset,0,0,&tv);
1049     if (ret <= 0) {
1050       serve_flag = 0;
1051       goto bcast_poll;
1052     }
1053     if (FD_ISSET(SwillSocket,&rset)) {
1054       serve_flag = 1;
1055     } else {
1056       serve_flag = 0;
1057     }
1058   }
1059  bcast_poll:
1060   /* rank independent: broadcast decision and act on it. --TL */
1061   MPI_Bcast(&serve_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
1062   if( serve_flag ){
1063     return swill_serve();
1064   }
1065   return 0;
1066 }
1067 #endif
1068 
swill_netscape(const char * url)1069 void swill_netscape(const char *url) {
1070   char buffer[2048];
1071   sprintf(buffer,"netscape -remote 'openURL(http://localhost:%d/%s)'", SwillPort, url);
1072   system(buffer);
1073 }
1074