Actual source code: send.c

petsc-3.3-p7 2013-05-11
  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>

 50: EXTERN_C_BEGIN
 51: #if defined(PETSC_NEED_CLOSE_PROTO)
 52: extern int close(int);
 53: #endif
 54: #if defined(PETSC_NEED_SOCKET_PROTO)
 55: extern int socket(int,int,int);
 56: #endif
 57: #if defined(PETSC_NEED_SLEEP_PROTO)
 58: extern int sleep(unsigned);
 59: #endif
 60: #if defined(PETSC_NEED_CONNECT_PROTO)
 61: extern int connect(int,struct sockaddr *,int);
 62: #endif
 63: EXTERN_C_END

 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_list[0],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;

178:   PetscGetHostName(myname,MAXHOSTNAME);

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

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

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

188:   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
189: #if defined(PETSC_HAVE_SO_REUSEADDR)
190:   {
191:     int optval = 1; /* Turn on the option */
192:     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&optval,sizeof(optval));
193:   }
194: #endif

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

214: /*
215:    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()

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

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

237: /*@C
238:    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket
239:         based server.

241:    Collective on MPI_Comm

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

249:    Output Parameter:
250: .  lab - a context to use when communicating with the server

252:    Level: intermediate

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

266:    Options Database Keys:
267:    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
268:    PETSC_VIEWER_SOCKET_() or if 
269:     PETSC_NULL is passed for machine or PETSC_DEFAULT is passed for port
270: $    -viewer_socket_machine <machine>
271: $    -viewer_socket_port <port>

273:    Environmental variables:
274: +   PETSC_VIEWER_SOCKET_PORT portnumber
275: -   PETSC_VIEWER_SOCKET_MACHINE machine name

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

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

283:    Concepts: MATLAB^sending data
284:    Concepts: sockets^sending data

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

296:   PetscViewerCreate(comm,lab);
297:   PetscViewerSetType(*lab,PETSCVIEWERSOCKET);
298:   PetscViewerSocketSetConnection(*lab,machine,port);
299:   return(0);
300: }

304: PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v)
305: {
307:   PetscInt       def = -1;
308:   char           sdef[256];
309:   PetscBool      tflg;

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

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

334: EXTERN_C_BEGIN
337: PetscErrorCode  PetscViewerCreate_Socket(PetscViewer v)
338: {
339:   PetscViewer_Socket *vmatlab;
340:   PetscErrorCode     ierr;

343:   PetscNewLog(v,PetscViewer_Socket,&vmatlab);
344:   vmatlab->port          = 0;
345:   v->data                = (void*)vmatlab;
346:   v->ops->destroy        = PetscViewerDestroy_Socket;
347:   v->ops->flush          = 0;
348:   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;

350:   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
351:   PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);
352:   return(0);
353: }
354: EXTERN_C_END

358: /*@C
359:       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket 
360:              viewer is to use

362:   Logically Collective on PetscViewer

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

370:     Level: advanced

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

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

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

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


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

434:      Collective on MPI_Comm

436:      Input Parameter:
437: .    comm - the MPI communicator to share the socket PetscViewer

439:      Level: intermediate

441:    Options Database Keys:
442:    For use with the default PETSC_VIEWER_SOCKET_WORLD or if 
443:     PETSC_NULL is passed for machine or PETSC_DEFAULT is passed for port
444: $    -viewer_socket_machine <machine>
445: $    -viewer_socket_port <port>

447:    Environmental variables:
448: +   PETSC_VIEWER_SOCKET_PORT portnumber
449: -   PETSC_VIEWER_SOCKET_MACHINE machine name

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

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

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

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

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

475:   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);}
476:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
477:     MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
478:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
479:   }
480:   MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void **)&viewer,(int*)&flg);
481:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
482:   if (!flg) { /* PetscViewer not yet created */
483:     PetscViewerSocketOpen(ncomm,0,0,&viewer);
484:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
485:     PetscObjectRegisterDestroy((PetscObject)viewer);
486:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
487:     MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
488:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
489:   }
490:   PetscCommDestroy(&ncomm);
491:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
492:   PetscFunctionReturn(viewer);
493: }

495: #if defined(PETSC_USE_SERVER)

497: #include <pthread.h>
498: #include <time.h>
499: #define PROTOCOL   "HTTP/1.1"
500: #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"

504: PetscErrorCode PetscWebSendHeader(FILE *f, int status, const char *title, const char *extra, const char *mime, int length)
505: {
506:   time_t now;
507:   char   timebuf[128];

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

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

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

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

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

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

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

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

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

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

677:       for (i=0; i<Nlevels; i++) {
678:         maxCol = PetscMax(maxCol,Levelcnt[i]);
679:       }
680:       for (i=0; i<Nlevels; i++) {
681:         Nlevelcnt = PetscMax(Nlevelcnt,Levelcnt[i]);
682:       }

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

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

738:       AMS_Disconnect();
739:       fprintf(fd, "}\r\n");
740:       fprintf(fd, "</script>\r\n");
741:       fprintf(fd, "<body onload=\"draw();\">\r\n");
742:       fprintf(fd, "</body></html>\r\n");
743:     }
744:   }
745:   PetscWebSendFooter(fd);

747:   return(0);
748: }
749: #endif

751: #if defined(PETSC_HAVE_YAML)

753: EXTERN_C_BEGIN
754: /*
755:     Toy function that returns all the arguments it is passed
756: */
759: PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
760: {
762:   PetscInt       i;

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

777: EXTERN_C_BEGIN
780: /*
781:       Connects to the local AMS and gets only the first communication name

783:    Input Parameters:
784: .     none

786:    Output Parameter:
787: .     oarg1 - the string name of the first communicator

789: */
790: PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
791: {
793:   char           **list = 0;

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

810: EXTERN_C_BEGIN
813: /*
814:       Attaches to an AMS communicator

816:    Input Parameter:
817: .     arg1 - string name of the communicator

819:    Output Parameter:
820: .     oarg1 - the integer name of the communicator

822: */
823: PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
824: {
826:   AMS_Comm       comm = -1;

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

839: EXTERN_C_BEGIN
842: /*
843:       Gets the list of memories on an AMS Comm

845:    Input Parameter:
846: .     arg1 - integer name of the communicator

848:    Output Parameter:
849: .     oarg1 - the list of names

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

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

868:     PetscMalloc((iargco)*sizeof(char*),argso);
869:     for (i=0; i<iargco; i++) {
870:       PetscStrallocpy(mem_list[i],(*argso)+i);
871:     }
872:   }
873:   *argco = iargco;
874:   return(0);
875: }
876: EXTERN_C_END

878: EXTERN_C_BEGIN
881: /*
882:       Attaches to an AMS memory in a communicator

884:    Input Parameter:
885: .     arg1 - communicator
886: .     arg2 - string name of the memory

888:    Output Parameter:
889: .     oarg1 - the integer name of the memory
890: .     oarg2 - the integer step of the memory

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

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

914: EXTERN_C_BEGIN
917: /*
918:       Gets the list of fields on an AMS Memory

920:    Input Parameter:
921: .     arg1 - integer name of the memory

923:    Output Parameter:
924: .     oarg1 - the list of names

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

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

943:     PetscMalloc((iargco)*sizeof(char*),argso);
944:     for (i=0; i<iargco; i++) {
945:       PetscStrallocpy(field_list[i],(*argso)+i);
946:     }
947:   }
948:   *argco = iargco;
949:   return(0);
950: }
951: EXTERN_C_END

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

958: EXTERN_C_BEGIN
961: /*
962:       Gets information about a field

964:    Input Parameter:
965: .     arg1 - memory
966: .     arg2 - string name of the field

968:    Output Parameter:

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

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

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

1033:   PetscMalloc(sizeof(char*),&args);
1034:   yaml_parser_initialize(&parser);
1035:   PetscStrlen(request,&len);
1036:   yaml_parser_set_input_string(&parser, (unsigned char *)request, len);

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

1109:     yaml_event_delete(&event);
1110:     count ++;
1111:   }
1112:   yaml_parser_delete(&parser);

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

1122:   for (i=0; i<argc; i++) {
1123:     PetscFree(args[i]);
1124:   }
1125:   PetscFree(args);
1126:   PetscFree(methodname);

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

1144:   /* free work space */
1145:   PetscFree(idname);
1146:   for (i=0; i<argco; i++) {
1147:     PetscFree(argso[i]);
1148:   }
1149:   PetscFree(argso);
1150:   return(0);
1151: }
1152: #endif

1156: /*@C
1157:       PetscWebServeRequest - serves a single web request

1159:     Not collective 

1161:   Input Parameters:
1162: .   port - the port

1164:     Level: developer

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

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

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

1189:   PetscTokenCreate(buf,' ',&tok);
1190:   PetscTokenFind(tok,&method);
1191:   PetscTokenFind(tok,&path);
1192:   PetscTokenFind(tok,&protocol);

1194:   if (!method || !path || !protocol) {
1195:     PetscInfo(PETSC_NULL,"Web request not well formatted, giving up\n");
1196:     goto theend;
1197:   }

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

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

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

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

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

1339:   return(0);
1340: }

1344: /*@C
1345:       PetscWebServeWait - waits for requests on a thread

1347:     Not collective

1349:   Input Parameter:
1350: .   port - port to listen on

1352:     Level: developer

1354: .seealso: PetscViewerSocketOpen(), PetscWebServe()
1355: @*/
1356: void  *PetscWebServeWait(int *port)
1357: {
1359:   int            iport,listenport,tport = *port;

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

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

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

1380:   Input Parameters:
1381: +   comm - the MPI communicator
1382: -   port - port to listen on

1384:   Options Database Key:
1385: +  -server <port> - start PETSc webserver (default port is 8080)
1386: -  -ams_publish_objects 


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

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

1394:       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.

1396:     Level: developer

1398: .seealso: PetscViewerSocketOpen()
1399: @*/
1400: PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1401: {
1403:   PetscMPIInt    rank;
1404:   pthread_t      thread;
1405:   int            *trueport;

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

1412:   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1413:   PetscMalloc(1*sizeof(int),&trueport); /* malloc this so it still exists in thread */
1414:   *trueport = port;
1415:   pthread_create(&thread, NULL, (void *(*)(void *))PetscWebServeWait, trueport);
1416:   return(0);
1417: }
1418: #endif