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