Actual source code: send.c

  2: #include <petscsys.h>

  4: #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
  5: /* Some systems have inconsistent include files that use but do not
  6:    ensure that the following definitions are made */
  7: typedef unsigned char   u_char;
  8: typedef unsigned short  u_short;
  9: typedef unsigned short  ushort;
 10: typedef unsigned int    u_int;
 11: typedef unsigned long   u_long;
 12: #endif

 14: #include <errno.h>
 15: #if defined(PETSC_HAVE_STDLIB_H)
 16: #include <stdlib.h>
 17: #endif
 18: #include <sys/types.h>
 19: #include <ctype.h>
 20: #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
 21: #include <machine/endian.h>
 22: #endif
 23: #if defined(PETSC_HAVE_UNISTD_H)
 24: #include <unistd.h>
 25: #endif
 26: #if defined(PETSC_HAVE_SYS_SOCKET_H)
 27: #include <sys/socket.h>
 28: #endif
 29: #if defined(PETSC_HAVE_SYS_WAIT_H)
 30: #include <sys/wait.h>
 31: #endif
 32: #if defined(PETSC_HAVE_NETINET_IN_H)
 33: #include <netinet/in.h>
 34: #endif
 35: #if defined(PETSC_HAVE_NETDB_H)
 36: #include <netdb.h>
 37: #endif
 38: #if defined(PETSC_HAVE_FCNTL_H)
 39: #include <fcntl.h>
 40: #endif
 41: #if defined(PETSC_HAVE_IO_H)
 42: #include <io.h>
 43: #endif
 44: #if defined(PETSC_HAVE_WINSOCK2_H)
 45: #include <Winsock2.h>
 46: #endif
 47: #include <sys/stat.h>
 48: #include <../src/sys/viewer/impls/socket/socket.h>

 51: #if defined(PETSC_NEED_CLOSE_PROTO)
 53: #endif
 54: #if defined(PETSC_NEED_SOCKET_PROTO)
 56: #endif
 57: #if defined(PETSC_NEED_SLEEP_PROTO)
 59: #endif
 60: #if defined(PETSC_NEED_CONNECT_PROTO)
 62: #endif

 65: /*--------------------------------------------------------------*/
 68: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
 69: {
 70:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
 71:   PetscErrorCode     ierr;

 74:   if (vmatlab->port) {
 75: #if defined(PETSC_HAVE_CLOSESOCKET)
 76:     closesocket(vmatlab->port);
 77: #else
 78:     close(vmatlab->port);
 79: #endif
 80:     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
 81:   }
 82:   PetscFree(vmatlab);
 83:   return(0);
 84: }

 86: /*--------------------------------------------------------------*/
 89: /*
 90:     PetscSocketOpen - handles connected to an open port where someone is waiting.

 92: .seealso:   PetscSocketListen(), PetscSocketEstablish()
 93: */
 94: PetscErrorCode  PetscOpenSocket(char *hostname,int portnum,int *t)
 95: {
 96:   struct sockaddr_in sa;
 97:   struct hostent     *hp;
 98:   int                s = 0;
 99:   PetscErrorCode     ierr;
100:   PetscBool          flg = PETSC_TRUE;

103:   if (!(hp=gethostbyname(hostname))) {
104:     perror("SEND: error gethostbyname: ");
105:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
106:   }
107:   PetscMemzero(&sa,sizeof(sa));
108:   PetscMemcpy(&sa.sin_addr,hp->h_addr,hp->h_length);

110:   sa.sin_family = hp->h_addrtype;
111:   sa.sin_port = htons((u_short) portnum);
112:   while (flg) {
113:     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
114:       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
115:     }
116:     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
117: #if defined(PETSC_HAVE_WSAGETLASTERROR)
118:       WSAGetLastError();
119:       if (ierr == WSAEADDRINUSE) {
120:         (*PetscErrorPrintf)("SEND: address is in use\n");
121:       } else if (ierr == WSAEALREADY) {
122:         (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
123:       } else if (ierr == WSAEISCONN) {
124:         (*PetscErrorPrintf)("SEND: socket already connected\n");
125:         Sleep((unsigned) 1);
126:       } else if (ierr == WSAECONNREFUSED) {
127:         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
128:         Sleep((unsigned) 1);
129:       } else {
130:         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
131:       }
132: #else
133:       if (errno == EADDRINUSE) {
134:         (*PetscErrorPrintf)("SEND: address is in use\n");
135:       } else if (errno == EALREADY) {
136:         (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
137:       } else if (errno == EISCONN) {
138:         (*PetscErrorPrintf)("SEND: socket already connected\n");
139:         sleep((unsigned) 1);
140:       } else if (errno == ECONNREFUSED) {
141:         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
142:         PetscInfo(0,"Connection refused in attaching socket, trying again");
143:         sleep((unsigned) 1);
144:       } else {
145:         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
146:       }
147: #endif
148:       flg = PETSC_TRUE;
149: #if defined(PETSC_HAVE_CLOSESOCKET)
150:       closesocket(s);
151: #else
152:       close(s);
153: #endif
154:     }
155:     else flg = PETSC_FALSE;
156:   }
157:   *t = s;
158:   return(0);
159: }

161: #define MAXHOSTNAME 100
164: /*
165:    PetscSocketEstablish - starts a listener on a socket

167: .seealso:   PetscSocketListen()
168: */
169: PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
170: {
171:   char               myname[MAXHOSTNAME+1];
172:   int                s;
173:   PetscErrorCode     ierr;
174:   struct sockaddr_in sa;
175:   struct hostent     *hp;
176:   int                optval = 1; /* Turn on the option */

179:   PetscGetHostName(myname,MAXHOSTNAME);

181:   PetscMemzero(&sa,sizeof(struct sockaddr_in));

183:   hp = gethostbyname(myname);
184:   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");

186:   sa.sin_family = hp->h_addrtype;
187:   sa.sin_port = htons((u_short)portnum);

189:   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
190:   setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&optval,sizeof(optval));

192:   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
193: #if defined(PETSC_HAVE_WSAGETLASTERROR)
194:     WSAGetLastError();
195:     if (ierr != WSAEADDRINUSE) {
196: #else
197:     if (errno != EADDRINUSE) {
198: #endif
199:       close(s);
200:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
201:     }
202:   }
203:   listen(s,0);
204:   *ss = s;
205:   return(0);
206: }

210: /*
211:    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()

213: .seealso:   PetscSocketEstablish()
214: */
215: PetscErrorCode PetscSocketListen(int listenport,int *t)
216: {
217:   struct sockaddr_in isa;
218: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
219:   size_t             i;
220: #else
221:   int                i;
222: #endif

225:   /* wait for someone to try to connect */
226:   i = sizeof(struct sockaddr_in);
227:   if ((*t = accept(listenport,(struct sockaddr *)&isa,(socklen_t *)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
228:   return(0);
229: }

233: /*@C
234:    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket
235:         based server.

237:    Collective on MPI_Comm

239:    Input Parameters:
240: +  comm - the MPI communicator
241: .  machine - the machine the server is running on,, use PETSC_NULL for the local machine, use "server" to passively wait for
242:              a connection from elsewhere
243: -  port - the port to connect to, use PETSC_DEFAULT for the default

245:    Output Parameter:
246: .  lab - a context to use when communicating with the server

248:    Level: intermediate

250:    Notes:
251:    Most users should employ the following commands to access the 
252:    MATLAB PetscViewers
253: $
254: $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
255: $    MatView(Mat matrix,PetscViewer viewer)
256: $
257: $                or
258: $
259: $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
260: $    VecView(Vec vector,PetscViewer viewer)

262:    Options Database Keys:
263:    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
264:    PETSC_VIEWER_SOCKET_() or if 
265:     PETSC_NULL is passed for machine or PETSC_DEFAULT is passed for port
266: $    -viewer_socket_machine <machine>
267: $    -viewer_socket_port <port>

269:    Environmental variables:
270: +   PETSC_VIEWER_SOCKET_PORT portnumber
271: -   PETSC_VIEWER_SOCKET_MACHINE machine name

273:      Currently the only socket client available is MATLAB. See 
274:      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.

276:    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
277:           use PetscViewerBinaryRead/Write/GetDescriptor().

279:    Concepts: MATLAB^sending data
280:    Concepts: sockets^sending data

282: .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
283:           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD, 
284:           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
285:           PetscBinaryViewerGetDescriptor()
286: @*/
287: PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
288: {

292:   PetscViewerCreate(comm,lab);
293:   PetscViewerSetType(*lab,PETSCVIEWERSOCKET);
294:   PetscViewerSocketSetConnection(*lab,machine,port);
295:   return(0);
296: }

300: PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v)
301: {
303:   PetscInt       def = -1;
304:   char           sdef[256];
305:   PetscBool      tflg;

308:   /*
309:        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
310:     are listed here for the GUI to display
311:   */
312:   PetscOptionsHead("Socket PetscViewer Options");
313:     PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);
314:     if (tflg) {
315:       PetscOptionsStringToInt(sdef,&def);
316:     } else {
317:       def = PETSCSOCKETDEFAULTPORT;
318:     }
319:     PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);

321:     PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);
322:     PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);
323:     if (!tflg) {
324:       PetscGetHostName(sdef,256);
325:     }
326:   PetscOptionsTail();
327:   return(0);
328: }

333: PetscErrorCode  PetscViewerCreate_Socket(PetscViewer v)
334: {
335:   PetscViewer_Socket *vmatlab;
336:   PetscErrorCode     ierr;

339:   PetscNewLog(v,PetscViewer_Socket,&vmatlab);
340:   vmatlab->port          = 0;
341:   v->data                = (void*)vmatlab;
342:   v->ops->destroy        = PetscViewerDestroy_Socket;
343:   v->ops->flush          = 0;
344:   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;

346:   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
347:   PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);
348:   return(0);
349: }

354: /*@C
355:       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket 
356:              viewer is to use

358:   Logically Collective on PetscViewer

360:   Input Parameters:
361: +   v - viewer to connect
362: .   machine - host to connect to, use PETSC_NULL for the local machine,use "server" to passively wait for
363:              a connection from elsewhere
364: -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default

366:     Level: advanced

368: .seealso: PetscViewerSocketOpen()
369: @*/
370: PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
371: {
372:   PetscErrorCode     ierr;
373:   PetscMPIInt        rank;
374:   char               mach[256];
375:   PetscBool          tflg;
376:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket *)v->data;

380:   if (port <= 0) {
381:     char portn[16];
382:     PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);
383:     if (tflg) {
384:       PetscInt pport;
385:       PetscOptionsStringToInt(portn,&pport);
386:       port = (int)pport;
387:     } else {
388:       port = PETSCSOCKETDEFAULTPORT;
389:     }
390:   }
391:   if (!machine) {
392:     PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);
393:     if (!tflg) {
394:       PetscGetHostName(mach,256);
395:     }
396:   } else {
397:     PetscStrncpy(mach,machine,256);
398:   }

400:   MPI_Comm_rank(((PetscObject)v)->comm,&rank);
401:   if (!rank) {
402:     PetscStrcmp(mach,"server",&tflg);
403:     if (tflg) {
404:       int listenport;
405:       PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);
406:       PetscSocketEstablish(port,&listenport);
407:       PetscSocketListen(listenport,&vmatlab->port);
408:       close(listenport);
409:     } else {
410:       PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);
411:       PetscOpenSocket(mach,port,&vmatlab->port);
412:     }
413:   }
414:   return(0);
415: }

417: /* ---------------------------------------------------------------------*/
418: /*
419:     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
420:   is attached to a communicator, in this case the attribute is a PetscViewer.
421: */
422: static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;


427: /*@C
428:      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.

430:      Collective on MPI_Comm

432:      Input Parameter:
433: .    comm - the MPI communicator to share the socket PetscViewer

435:      Level: intermediate

437:    Options Database Keys:
438:    For use with the default PETSC_VIEWER_SOCKET_WORLD or if 
439:     PETSC_NULL is passed for machine or PETSC_DEFAULT is passed for port
440: $    -viewer_socket_machine <machine>
441: $    -viewer_socket_port <port>

443:    Environmental variables:
444: +   PETSC_VIEWER_SOCKET_PORT portnumber
445: -   PETSC_VIEWER_SOCKET_MACHINE machine name

447:      Notes:
448:      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return 
449:      an error code.  The socket PetscViewer is usually used in the form
450: $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));

452:      Currently the only socket client available is MATLAB. See 
453:      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.

455:      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.

457:      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine. 

459: .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
460:           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
461:           PetscViewerBinaryWriteStringArray(), PetscBinaryViewerGetDescriptor(), PETSC_VIEWER_MATLAB_()
462: @*/
463: PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
464: {
466:   PetscBool      flg;
467:   PetscViewer    viewer;
468:   MPI_Comm       ncomm;

471:   PetscCommDuplicate(comm,&ncomm,PETSC_NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
472:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
473:     MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
474:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
475:   }
476:   MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void **)&viewer,(int*)&flg);
477:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
478:   if (!flg) { /* PetscViewer not yet created */
479:     PetscViewerSocketOpen(ncomm,0,0,&viewer);
480:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
481:     PetscObjectRegisterDestroy((PetscObject)viewer);
482:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
483:     MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
484:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
485:   }
486:   PetscCommDestroy(&ncomm);
487:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
488:   PetscFunctionReturn(viewer);
489: }

491: #if defined(PETSC_USE_SERVER)

493: #include <pthread.h>
494: #include <time.h>
495: #define PROTOCOL   "HTTP/1.1"
496: #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"

500: PetscErrorCode PetscWebSendHeader(FILE *f, int status, const char *title, const char *extra, const char *mime, int length)
501: {
502:   time_t now;
503:   char   timebuf[128];

506:   fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
507:   fprintf(f, "Server: %s\r\n", "petscserver/1.0");
508:   now = time(NULL);
509:   strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
510:   fprintf(f, "Date: %s\r\n", timebuf);
511:   if (extra) fprintf(f, "%s\r\n", extra);
512:   if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
513:   if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
514:   fprintf(f, "Connection: close\r\n");
515:   fprintf(f, "\r\n");
516:   return(0);
517: }

521: PetscErrorCode PetscWebSendFooter(FILE *fd)
522: {
524:   fprintf(fd, "</BODY></HTML>\r\n");
525:   return(0);
526: }

530: PetscErrorCode PetscWebSendError(FILE *f, int status, const char *title, const char *extra, const char *text)
531: {

535:   PetscWebSendHeader(f, status, title, extra, "text/html", -1);
536:   fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
537:   fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
538:   fprintf(f, "%s\r\n", text);
539:   PetscWebSendFooter(f);
540:   return(0);
541: }

543: #if defined(PETSC_HAVE_AMS)
546: PetscErrorCode PetscAMSDisplayList(FILE *fd)
547: {
548:   PetscErrorCode     ierr;
549:   char               host[256],**comm_list,**mem_list,**fld_list;
550:   AMS_Comm           ams;
551:   PetscInt           i = 0,j;
552:   AMS_Memory_type    mtype;
553:   AMS_Data_type      dtype;
554:   AMS_Shared_type    stype;
555:   AMS_Reduction_type rtype;
556:   AMS_Memory         memory;
557:   int                len;
558:   void               *addr;
559: 
560:   PetscGetHostName(host,256);
561:   AMS_Connect(host, -1, &comm_list);
562:   PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);
563:   if (!comm_list || !comm_list[0]) {
564:     fprintf(fd, "AMS Communicator not running</p>\r\n");
565:   } else {
566:     AMS_Comm_attach(comm_list[0],&ams);
567:     AMS_Comm_get_memory_list(ams,&mem_list);
568:     if (!mem_list[0]) {
569:       fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
570:     } else {
571:       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
572:       fprintf(fd,"<ul>\r\n");
573:       while (mem_list[i]) {
574:         fprintf(fd,"<li> %s</li>\r\n",mem_list[i]);
575:         AMS_Memory_attach(ams,mem_list[i],&memory,NULL);
576:         AMS_Memory_get_field_list(memory, &fld_list);
577:         j = 0;
578:         fprintf(fd,"<ul>\r\n");
579:         while (fld_list[j]) {
580:           fprintf(fd,"<li> %s",fld_list[j]);
581:           AMS_Memory_get_field_info(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype);
582:           if (len == 1) {
583:             if (dtype == AMS_INT)        fprintf(fd," %d",*(int*)addr);
584:             else if (dtype == AMS_STRING) fprintf(fd," %s",*(char**)addr);
585:           }
586:           fprintf(fd,"</li>\r\n");
587:           j++;
588:         }
589:         fprintf(fd,"</ul>\r\n");
590:         i++;
591:       }
592:       fprintf(fd,"</ul>\r\n");
593:     }
594:   }
595:   PetscWebSendFooter(fd);
596:   AMS_Disconnect();
597:   return(0);
598: }

602: PetscErrorCode PetscAMSDisplayTree(FILE *fd)
603: {
604:   PetscErrorCode     ierr;
605:   char               host[256],**comm_list,**mem_list,**fld_list;
606:   AMS_Comm           ams;
607:   PetscInt           i = 0,j;
608:   AMS_Memory_type    mtype;
609:   AMS_Data_type      dtype;
610:   AMS_Shared_type    stype;
611:   AMS_Reduction_type rtype;
612:   AMS_Memory         memory;
613:   int                len;
614:   void               *addr2,*addr3,*addr,*addr4;
615: 
616:   PetscGetHostName(host,256);
617:   AMS_Connect(host, -1, &comm_list);
618:   PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);
619:   if (!comm_list || !comm_list[0]) {
620:     fprintf(fd, "AMS Communicator not running</p>\r\n");
621:   } else {
622:     AMS_Comm_attach(comm_list[0],&ams);
623:     AMS_Comm_get_memory_list(ams,&mem_list);
624:     if (!mem_list[0]) {
625:       fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
626:     } else {
627:       PetscInt   Nlevels,*Level,*Levelcnt,*Idbylevel,*Column,*parentid,*Id,maxId = 0,maxCol = 0,*parentId,id,cnt,Nlevelcnt = 0;
628:       PetscBool  *mask;
629:       char       **classes,*clas,**subclasses,*sclas;

631:       /* get maximum number of objects */
632:       while (mem_list[i]) {
633:         AMS_Memory_attach(ams,mem_list[i],&memory,NULL);
634:         AMS_Memory_get_field_list(memory, &fld_list);
635:         AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);
636:         Id = (int*) addr2;
637:         maxId = PetscMax(maxId,*Id);
638:         i++;
639:       }
640:       maxId++;

642:       /* Gets everyone's parent ID and which nodes are masked */
643:       PetscMalloc4(maxId,PetscInt,&parentid,maxId,PetscBool ,&mask,maxId,char**,&classes,maxId,char**,&subclasses);
644:       PetscMemzero(classes,maxId*sizeof(char*));
645:       PetscMemzero(subclasses,maxId*sizeof(char*));
646:       for (i=0; i<maxId; i++) mask[i] = PETSC_TRUE;
647:       i = 0;
648:       while (mem_list[i]) {
649:         AMS_Memory_attach(ams,mem_list[i],&memory,NULL);
650:         AMS_Memory_get_field_list(memory, &fld_list);
651:         AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);
652:         Id = (int*) addr2;
653:         AMS_Memory_get_field_info(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype);
654:         parentId = (int*) addr3;
655:         AMS_Memory_get_field_info(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype);
656:         clas = *(char**)addr;
657:         AMS_Memory_get_field_info(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype);
658:         sclas = *(char**)addr4;
659:         parentid[*Id] = *parentId;
660:         mask[*Id]     = PETSC_FALSE;
661:         PetscStrallocpy(clas,classes+*Id);
662:         PetscStrallocpy(sclas,subclasses+*Id);
663:         i++;
664:       }

666:       /* if the parent is masked then relabel the parent as 0 since the true parent was deleted */
667:       for (i=0; i<maxId; i++) {
668:         if (!mask[i] && parentid[i] > 0 && mask[parentid[i]]) parentid[i] = 0;
669:       }

671:       PetscProcessTree(maxId,mask,parentid,&Nlevels,&Level,&Levelcnt,&Idbylevel,&Column);

673:       for (i=0; i<Nlevels; i++) {
674:         maxCol = PetscMax(maxCol,Levelcnt[i]);
675:       }
676:       for (i=0; i<Nlevels; i++) {
677:         Nlevelcnt = PetscMax(Nlevelcnt,Levelcnt[i]);
678:       }

680:       /* print all the top-level objects */
681:       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE>\r\n");
682:       fprintf(fd, "<canvas width=800 height=600 id=\"tree\"></canvas>\r\n");
683:       fprintf(fd, "<script type=\"text/javascript\">\r\n");
684:       fprintf(fd, "  function draw(){\r\n");
685:       fprintf(fd, "  var example = document.getElementById('tree');\r\n");
686:       fprintf(fd, "  var context = example.getContext('2d');\r\n");
687:       /* adjust font size based on how big a tree is printed */
688:       if (Nlevels > 5 || Nlevelcnt > 10) {
689:         fprintf(fd, "  context.font         = \"normal 12px sans-serif\";\r\n");
690:       } else {
691:         fprintf(fd, "  context.font         = \"normal 24px sans-serif\";\r\n");
692:       }
693:       fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
694:       fprintf(fd, "  context.textBaseline = \"top\";\r\n");
695:       fprintf(fd, "  var xspacep = 0;\r\n");
696:       fprintf(fd, "  var yspace = example.height/%d;\r\n",(Nlevels+1));
697:       /* estimate the height of a string as twice the width of a character */
698:       fprintf(fd, "  var wheight = context.measureText(\"K\");\r\n");
699:       fprintf(fd, "  var height = 1.6*wheight.width;\r\n");

701:       cnt = 0;
702:       for (i=0; i<Nlevels; i++) {
703:         fprintf(fd, "  var xspace = example.width/%d;\r\n",Levelcnt[i]+1);
704:         for (j=0; j<Levelcnt[i]; j++) {
705:           id   = Idbylevel[cnt++];
706:           clas  = classes[id];
707:           sclas = subclasses[id];
708:           fprintf(fd, "  var width = context.measureText(\"%s\");\r\n",clas);
709:           fprintf(fd, "  var swidth = context.measureText(\"%s\");\r\n",sclas);
710:           fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
711:           fprintf(fd, "  context.fillRect((%d)*xspace-width.width/2, %d*yspace-height/2, width.width, height);\r\n",j+1,i+1);
712:           fprintf(fd, "  context.fillRect((%d)*xspace-swidth.width/2, %d*yspace+height/2, swidth.width, height);\r\n",j+1,i+1);
713:           fprintf(fd, "  context.fillStyle = \"rgb(0,0,0)\";\r\n");
714:           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-width.width/2, %d*yspace-height/2);\r\n",clas,j+1,i+1);
715:           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-swidth.width/2, %d*yspace+height/2);\r\n",sclas,j+1,i+1);
716:           if (parentid[id]) {
717:             fprintf(fd, "  context.moveTo(%d*xspace,%d*yspace-height/2);\r\n",j+1,i+1);
718:             fprintf(fd, "  context.lineTo(%d*xspacep,%d*yspace+3*height/2);\r\n",Column[parentid[id]]+1,i);
719:             fprintf(fd, "  context.stroke();\r\n");
720:           }
721:         }
722:         fprintf(fd, "  xspacep = xspace;\r\n");
723:       }
724:       PetscFree(Level);
725:       PetscFree(Levelcnt);
726:       PetscFree(Idbylevel);
727:       PetscFree(Column);
728:       for (i=0; i<maxId; i++) {
729:         PetscFree(classes[i]);
730:         PetscFree(subclasses[i]);
731:       }
732:       PetscFree4(mask,parentid,classes,subclasses);

734:       AMS_Disconnect();
735:       fprintf(fd, "}\r\n");
736:       fprintf(fd, "</script>\r\n");
737:       fprintf(fd, "<body onload=\"draw();\">\r\n");
738:       fprintf(fd, "</body></html>\r\n");
739:     }
740:   }
741:   PetscWebSendFooter(fd);

743:   return(0);
744: }
745: #endif

747: #if defined(PETSC_HAVE_YAML)

750: /*
751:     Toy function that returns all the arguments it is passed
752: */
755: PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
756: {
758:   PetscInt       i;

760:   PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);
761:   for (i=0; i<argc; i++) {
762:     PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);
763:   }
764:   *argco = argc;
765:   PetscMalloc(argc*sizeof(char*),argso);
766:   for (i=0; i<argc; i++) {
767:     PetscStrallocpy(args[i],&(*argso)[i]);
768:   }
769:   return(0);
770: }

776: /*
777:       Connects to the local AMS and gets only the first communication name

779:    Input Parameters:
780: .     none

782:    Output Parameter:
783: .     oarg1 - the string name of the first communicator

785: */
786: PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
787: {
789:   char           **list = 0;

792:   AMS_Connect(0,-1,&list);
793:   if (ierr) {PetscInfo1(PETSC_NULL,"AMS_Connect() error %d\n",ierr);}
794:   else if (!list) {PetscInfo(PETSC_NULL,"AMS_Connect() list empty, not running AMS server\n");}
795:   *argco = 1;
796:   PetscMalloc(sizeof(char*),argso);
797:   if (list){
798:     PetscStrallocpy(list[0],&(*argso)[0]);
799:   } else {
800:     PetscStrallocpy("No AMS publisher running",&(*argso)[0]);
801:   }
802:   return(0);
803: }

809: /*
810:       Attaches to an AMS communicator

812:    Input Parameter:
813: .     arg1 - string name of the communicator

815:    Output Parameter:
816: .     oarg1 - the integer name of the communicator

818: */
819: PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
820: {
822:   AMS_Comm       comm = -1;

825:   AMS_Comm_attach(args[0],&comm);
826:   if (ierr) {PetscInfo1(PETSC_NULL,"AMS_Comm_attach() error %d\n",ierr);}
827:   *argco = 1;
828:   PetscMalloc(sizeof(char*),argso);
829:   PetscMalloc(3*sizeof(char*),&argso[0][0]);
830:   sprintf(argso[0][0],"%d",(int)comm);
831:   return(0);
832: }

838: /*
839:       Gets the list of memories on an AMS Comm

841:    Input Parameter:
842: .     arg1 - integer name of the communicator

844:    Output Parameter:
845: .     oarg1 - the list of names

847: */
848: PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
849: {
851:   char           **mem_list;
852:   AMS_Comm       comm;
853:   PetscInt       i,iargco = 0;

856:   sscanf(args[0],"%d",&comm);
857:   AMS_Comm_get_memory_list(comm,&mem_list);
858:   if (ierr) {
859:     PetscInfo1(PETSC_NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);
860:   } else {
861:     while (mem_list[iargco++]) ;
862:     iargco--;

864:     PetscMalloc((iargco)*sizeof(char*),argso);
865:     for (i=0; i<iargco; i++) {
866:       PetscStrallocpy(mem_list[i],(*argso)+i);
867:     }
868:   }
869:   *argco = iargco;
870:   return(0);
871: }

877: /*
878:       Attaches to an AMS memory in a communicator

880:    Input Parameter:
881: .     arg1 - communicator
882: .     arg2 - string name of the memory

884:    Output Parameter:
885: .     oarg1 - the integer name of the memory
886: .     oarg2 - the integer step of the memory

888: */
889: PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
890: {
892:   AMS_Comm       comm;
893:   AMS_Memory     mem;
894:   unsigned int   step;

897:   sscanf(args[0],"%d",&comm);
898:   AMS_Memory_attach(comm,args[1],&mem,&step);
899:   if (ierr) {PetscInfo1(PETSC_NULL,"AMS_Memory_attach() error %d\n",ierr);}
900:   *argco = 2;
901:   PetscMalloc(2*sizeof(char*),argso);
902:   PetscMalloc(3*sizeof(char*),&argso[0][0]);
903:   sprintf(argso[0][0],"%d",(int)mem);
904:   PetscMalloc(3*sizeof(char*),&argso[0][1]);
905:   sprintf(argso[0][1],"%d",(int)step);
906:   return(0);
907: }

913: /*
914:       Gets the list of fields on an AMS Memory

916:    Input Parameter:
917: .     arg1 - integer name of the memory

919:    Output Parameter:
920: .     oarg1 - the list of names

922: */
923: PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
924: {
926:   char           **field_list;
927:   AMS_Memory     mem;
928:   PetscInt       i,iargco = 0;

931:   sscanf(args[0],"%d",&mem);
932:   AMS_Memory_get_field_list(mem,&field_list);
933:   if (ierr) {
934:     PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_list() error %d\n",ierr);
935:   } else {
936:     while (field_list[iargco++]) ;
937:     iargco--;

939:     PetscMalloc((iargco)*sizeof(char*),argso);
940:     for (i=0; i<iargco; i++) {
941:       PetscStrallocpy(field_list[i],(*argso)+i);
942:     }
943:   }
944:   *argco = iargco;
945:   return(0);
946: }

949: const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
950: const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
951: const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
952: const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};

957: /*
958:       Gets information about a field

960:    Input Parameter:
961: .     arg1 - memory
962: .     arg2 - string name of the field

964:    Output Parameter:

966: */
967: PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
968: {
969:   PetscErrorCode     ierr;
970:   AMS_Memory         mem;
971:   void               *addr;
972:   int                len;
973:   AMS_Data_type      dtype;
974:   AMS_Memory_type    mtype;
975:   AMS_Shared_type    stype;
976:   AMS_Reduction_type rtype;
977:   PetscInt           i;

980:   sscanf(args[0],"%d",&mem);
981:   AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
982:   if (ierr) {PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_info() error %d\n",ierr);}
983:   *argco = 4 + len;
984:   PetscMalloc((*argco)*sizeof(char*),argso);
985:   PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);
986:   PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);
987:   PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);
988:   PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);
989:   for (i=0; i<len; i++) {
990:     if (dtype == AMS_STRING) {
991:       PetscStrallocpy(*(const char **)addr,&argso[0][4+i]);
992:     } else if (dtype == AMS_DOUBLE) {
993:       PetscMalloc(20*sizeof(char),&argso[0][4+i]);
994:       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
995:     } else if (dtype == AMS_INT) {
996:       PetscMalloc(10*sizeof(char),&argso[0][4+i]);
997:       sprintf(argso[0][4+i],"%d",*(int*)addr);
998:     } else if (dtype == AMS_BOOLEAN) {
999:       if (*(int*)addr) {
1000:         PetscStrallocpy("true",&argso[0][4+i]);
1001:       } else {
1002:         PetscStrallocpy("false",&argso[0][4+i]);
1003:       }
1004:     } else {
1005:       PetscStrallocpy("Not yet done",&argso[0][4+i]);
1006:     }
1007:   }
1008:   return(0);
1009: }

1012: #include "yaml.h"
1015: PetscErrorCode PetscProcessYAMLRPC(const char* request,char **result)
1016: {
1017:   yaml_parser_t  parser;
1018:   yaml_event_t   event;
1019:   int            done = 0;
1020:   int            count = 0;
1021:   size_t         len;
1023:   PetscBool      method,params,id;
1024:   char           *methodname,*idname,**args,**argso = 0;
1025:   PetscInt       argc = 0,argco,i;
1026:   PetscErrorCode (*fun)(PetscInt,char **,PetscInt*,char ***);

1029:   PetscMalloc(sizeof(char*),&args);
1030:   yaml_parser_initialize(&parser);
1031:   PetscStrlen(request,&len);
1032:   yaml_parser_set_input_string(&parser, (unsigned char *)request, len);

1034:   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1035:   while (!done) {
1036:     if (!yaml_parser_parse(&parser, &event)) {
1037:       PetscInfo(PETSC_NULL,"Found error in yaml/json\n");
1038:       break;
1039:     }
1040:     done = (event.type == YAML_STREAM_END_EVENT);
1041:     switch (event.type) {
1042:     case YAML_STREAM_START_EVENT:
1043:       PetscInfo(PETSC_NULL,"Stream start\n");
1044:       break;
1045:     case YAML_STREAM_END_EVENT:
1046:       PetscInfo(PETSC_NULL,"Stream end\n");
1047:       break;
1048:     case YAML_DOCUMENT_START_EVENT:
1049:       PetscInfo(PETSC_NULL,"Document start\n");
1050:       break;
1051:     case YAML_DOCUMENT_END_EVENT:
1052:       PetscInfo(PETSC_NULL,"Document end\n");
1053:       break;
1054:     case YAML_MAPPING_START_EVENT:
1055:       PetscInfo(PETSC_NULL,"Mapping start event\n");
1056:       break;
1057:     case YAML_MAPPING_END_EVENT:
1058:       PetscInfo(PETSC_NULL,"Mapping end event \n");
1059:       break;
1060:     case YAML_ALIAS_EVENT:
1061:       PetscInfo1(PETSC_NULL,"Alias event %s\n",event.data.alias.anchor);
1062:       break;
1063:     case YAML_SCALAR_EVENT:
1064:       PetscInfo1(PETSC_NULL,"Scalar event %s\n",event.data.scalar.value);
1065:       PetscStrcmp((char*)event.data.scalar.value,"method",&method);
1066:       PetscStrcmp((char*)event.data.scalar.value,"params",&params);
1067:       PetscStrcmp((char*)event.data.scalar.value,"id",&id);
1068:       if (method) {
1069:         yaml_event_delete(&event);
1070:         yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1071:         PetscInfo1(PETSC_NULL,"Method %s\n",event.data.scalar.value);
1072:         PetscStrallocpy((char*)event.data.scalar.value,&methodname);
1073:       } else if (id) {
1074:         yaml_event_delete(&event);
1075:         yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1076:         PetscInfo1(PETSC_NULL,"Id %s\n",event.data.scalar.value);
1077:         PetscStrallocpy((char*)event.data.scalar.value,&idname);
1078:       } else if (params) {
1079:         yaml_event_delete(&event);
1080:         yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1081:         yaml_event_delete(&event);
1082:         yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1083:         while (event.type != YAML_SEQUENCE_END_EVENT) {
1084:           PetscInfo1(PETSC_NULL,"  Parameter %s\n",event.data.scalar.value);
1085:           PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);
1086:           yaml_event_delete(&event);
1087:           yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1088:         }
1089:       } else { /* ignore all the other variables in the mapping */
1090:         yaml_event_delete(&event);
1091:         yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1092:       }
1093:       break;
1094:     case YAML_SEQUENCE_START_EVENT:
1095:       PetscInfo(PETSC_NULL,"Sequence start event \n");
1096:       break;
1097:     case YAML_SEQUENCE_END_EVENT:
1098:       PetscInfo(PETSC_NULL,"Sequence end event \n");
1099:       break;
1100:     default:
1101:       /* It couldn't really happen. */
1102:       break;
1103:     }

1105:     yaml_event_delete(&event);
1106:     count ++;
1107:   }
1108:   yaml_parser_delete(&parser);

1110:   PetscDLLibrarySym(PETSC_COMM_SELF,PETSC_NULL,PETSC_NULL,methodname,(void**)&fun);
1111:   if (fun) {
1112:     PetscInfo1(PETSC_NULL,"Located function %s and running it\n",methodname);
1113:     (*fun)(argc,args,&argco,&argso);
1114:   } else {
1115:     PetscInfo1(PETSC_NULL,"Did not locate function %s skipping it\n",methodname);
1116:   }

1118:   for (i=0; i<argc; i++) {
1119:     PetscFree(args[i]);
1120:   }
1121:   PetscFree(args);
1122:   PetscFree(methodname);

1124:   /* convert the result back to YAML; should use YAML encoder, does not handle zero return arguments */
1125:   PetscMalloc(1024,result);
1126:   PetscStrcpy(*result,"{\"error\": null, \"id\": \"");
1127:   PetscStrcat(*result,idname);
1128:   PetscStrcat(*result,"\", \"result\" : ");
1129:   if (argco > 1) {PetscStrcat(*result,"[");}
1130:   for (i=0; i<argco; i++) {
1131:     PetscStrcat(*result,"\"");
1132:     PetscStrcat(*result,argso[i]);
1133:     PetscStrcat(*result,"\"");
1134:     if (i < argco-1) {PetscStrcat(*result,",");}
1135:   }
1136:   if (argco > 1) {PetscStrcat(*result,"]");}
1137:   PetscStrcat(*result,"}");
1138:   PetscInfo1(PETSC_NULL,"YAML result of function %s\n",*result);

1140:   /* free work space */
1141:   PetscFree(idname);
1142:   for (i=0; i<argco; i++) {
1143:     PetscFree(argso[i]);
1144:   }
1145:   PetscFree(argso);
1146:   return(0);
1147: }
1148: #endif

1152: /*@C
1153:       PetscWebServeRequest - serves a single web request

1155:     Not collective 

1157:   Input Parameters:
1158: .   port - the port

1160:     Level: developer

1162: .seealso: PetscWebServe()
1163: @*/
1164: PetscErrorCode  PetscWebServeRequest(int port)
1165: {
1167:   FILE           *fd,*fdo;
1168:   char           buf[4096],fullpath[PETSC_MAX_PATH_LEN],truefullpath[PETSC_MAX_PATH_LEN];
1169:   char           *method, *path, *protocol,*result;
1170:   const char*    type;
1171:   PetscBool      flg;
1172:   PetscToken     tok;
1173:   PetscInt       cnt = 8;

1176:   fd = fdopen(port, "r+");

1178:   PetscInfo(PETSC_NULL,"Processing web request\n");
1179:   if (!fgets(buf, sizeof(buf), fd)) {
1180:     PetscInfo(PETSC_NULL,"Cannot read web request, giving up\n");
1181:     goto theend;
1182:   }
1183:   PetscInfo1(PETSC_NULL,"Processing web request %s",buf);

1185:   PetscTokenCreate(buf,' ',&tok);
1186:   PetscTokenFind(tok,&method);
1187:   PetscTokenFind(tok,&path);
1188:   PetscTokenFind(tok,&protocol);

1190:   if (!method || !path || !protocol) {
1191:     PetscInfo(PETSC_NULL,"Web request not well formatted, giving up\n");
1192:     goto theend;
1193:   }

1195:   PetscStrcmp(method,"GET",&flg);
1196:   if (!flg) {
1197: #if defined(PETSC_HAVE_YAML)
1198:     PetscStrcmp(method,"POST",&flg);
1199:     /*
1200:           Start to handle support for POSTs based on json-rpc
1201:     */
1202:     if (flg) {
1203:       int    len;
1204:       size_t elen;
1205:       char   *fnd;
1206:       while (cnt--) {
1207: 
1208:         if (!fgets(buf, sizeof(buf), fd)) {
1209:           PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");
1210:           goto theend;
1211:         }
1212:         PetscInfo1(PETSC_NULL,"POSTED data %s",buf);
1213:         PetscStrstr(buf,"Content-Type:",&fnd);
1214:         if (fnd) {
1215:           PetscStrstr(buf,"application/json-rpc",&fnd);
1216:           if (!fnd) {
1217:             PetscInfo(PETSC_NULL,"POST content is not json-rpc, skipping post\n");
1218:             goto theend;
1219:           }
1220:         }
1221:       }
1222:       if (!fgets(buf, sizeof(buf), fd)) {
1223:         PetscInfo(PETSC_NULL,"Cannot read POST length data, giving up\n");
1224:         goto theend;
1225:       }
1226:       PetscInfo1(PETSC_NULL,"POSTED length data %s",buf);
1227:       sscanf(buf,"Content-Length: %d\n",&len);
1228:       PetscInfo1(PETSC_NULL,"Length of POSTED data %d\n",len);
1229:       if (!fgets(buf, sizeof(buf), fd)) {
1230:         PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");
1231:         goto theend;
1232:       }
1233:       PetscInfo1(PETSC_NULL,"POSTED data %s",buf);
1234:       if (!fgets(buf, sizeof(buf), fd)) {
1235:         PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");
1236:         goto theend;
1237:       }
1238:       PetscInfo1(PETSC_NULL,"POSTED data %s",buf);
1239:       if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1240:         PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");
1241:         goto theend;
1242:       }
1243:       PetscInfo1(PETSC_NULL,"POSTED data %s\n",buf);
1244:       fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1245:       PetscProcessYAMLRPC(buf,&result);
1246:       PetscStrlen(result,&elen);
1247:       PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);
1248:       fprintf(fd, "%s",result);
1249:       goto theend;
1250:     } else {
1251: #endif
1252:       PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");
1253:       PetscInfo(PETSC_NULL,"Web request not a GET or POST, giving up\n");
1254: #if defined(PETSC_HAVE_YAML)
1255:     }
1256: #endif
1257:   } else {
1258:     fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */

1260:     PetscStrcmp(path,"/favicon.ico",&flg);
1261:     if (flg) {
1262:       /* should have cool PETSc icon */;
1263:       goto theend;
1264:     }
1265:     PetscStrcmp(path,"/",&flg);
1266:     if (flg) {
1267:       char        program[128];
1268:       PetscMPIInt size;
1269:       PetscViewer viewer;

1271:       MPI_Comm_size(PETSC_COMM_WORLD,&size);
1272:       PetscGetProgramName(program,128);
1273:       PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);
1274:       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
1275:       fprintf(fd, "<H4>Serving PETSc application code %s </H4>\r\n\n",program);
1276:       fprintf(fd, "Number of processes %d\r\n\n",size);
1277:       fprintf(fd, "<HR>\r\n");
1278:       PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);
1279:       PetscOptionsView(viewer);
1280:       PetscViewerDestroy(&viewer);
1281:       fprintf(fd, "<HR>\r\n");
1282: #if defined(PETSC_HAVE_AMS)
1283:       if (PetscAMSPublishAll) {
1284:         fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
1285:         fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
1286:       }
1287: #endif
1288:       fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
1289:       PetscWebSendFooter(fd);
1290:       goto theend;
1291:     }

1293: #if defined(PETSC_HAVE_AMS)
1294:     PetscStrcmp(path,"/ams-list",&flg);
1295:     if (flg) {
1296:       PetscAMSDisplayList(fd);
1297:       goto theend;
1298:     }
1299:     printf("path %s\n",path);
1300:     PetscStrcmp(path,"/ams-tree",&flg);
1301:     if (flg) {
1302:     printf("found path %s\n",path);
1303:       PetscAMSDisplayTree(fd);
1304:       goto theend;
1305:     }
1306: #endif
1307:     PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");
1308:     PetscStrcat(fullpath,path);
1309:     PetscInfo1(PETSC_NULL,"Checking for file %s\n",fullpath);
1310:     PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);
1311:     fdo  = fopen(truefullpath,"r");
1312:     if (fdo) {
1313:       PetscInt    length,index;
1314:       char        data[4096];
1315:       struct stat statbuf;
1316:       int         n;
1317:       const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};

1319:       PetscStrendswithwhich(fullpath,suffixes,&index);
1320:       type = mimes[index];
1321:       if (!stat(truefullpath, &statbuf)) length = -1;
1322:       else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
1323:       PetscWebSendHeader(fd, 200, "OK", NULL, type, length);
1324:       while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
1325:       fclose(fdo);
1326:       PetscInfo2(PETSC_NULL,"Sent file %s to browser using format %s\n",fullpath,type);
1327:       goto theend;
1328:     }
1329:     PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");
1330:   }
1331:   theend:
1332:   PetscTokenDestroy(tok);
1333:   fclose(fd);
1334:   PetscInfo(PETSC_NULL,"Finished processing request\n");

1336:   return(0);
1337: }

1341: /*@C
1342:       PetscWebServeWait - waits for requests on a thread

1344:     Not collective

1346:   Input Parameter:
1347: .   port - port to listen on

1349:     Level: developer

1351: .seealso: PetscViewerSocketOpen()
1352: @*/
1353: void  *PetscWebServeWait(int *port)
1354: {
1356:   int            iport,listenport,tport = *port;

1358:   PetscInfo1(PETSC_NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1359:   PetscFree(port);if (ierr) return 0;
1360:   PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1361:   while (1) {
1362:     PetscSocketListen(listenport,&iport);if (ierr) return 0;
1363:     PetscWebServeRequest(iport);if (ierr) return 0;
1364:     close(iport);
1365:   }
1366:   close(listenport);
1367:   return 0;
1368: }

1372: /*@C
1373:       PetscWebServe - start up the PETSc web server and respond to requests

1375:     Not collective - only does something on process zero of the communicator

1377:   Input Parameters:
1378: +   comm - the MPI communicator
1379: -   port - port to listen on

1381:   Options Database Key:
1382: .  -server <port> - start PETSc webserver (default port is 8080)

1384:    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1385:       If you are running PETSc on your local machine you can use http://localhost:8080

1387:       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.

1389:     Level: developer

1391: .seealso: PetscViewerSocketOpen()
1392: @*/
1393: PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1394: {
1396:   PetscMPIInt    rank;
1397:   pthread_t      thread;
1398:   int            *trueport;

1401:   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1402:   MPI_Comm_rank(comm,&rank);
1403:   if (rank) return(0);

1405:   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1406:   PetscMalloc(1*sizeof(int),&trueport); /* malloc this so it still exists in thread */
1407:   *trueport = port;
1408:   pthread_create(&thread, NULL, (void *(*)(void *))PetscWebServeWait, trueport);
1409:   return(0);
1410: }
1411: #endif