xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 5c6c1daec53e1d9ab0bec9db5309fd8fc7645b8d)
1 
2 #include <petscsys.h>
3 
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
13 
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/classes/viewer/impls/socket/socket.h>
49 
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
64 
65 /*--------------------------------------------------------------*/
66 #undef __FUNCT__
67 #define __FUNCT__ "PetscViewerDestroy_Socket"
68 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
69 {
70   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
71   PetscErrorCode     ierr;
72 
73   PetscFunctionBegin;
74   if (vmatlab->port) {
75 #if defined(PETSC_HAVE_CLOSESOCKET)
76     ierr = closesocket(vmatlab->port);
77 #else
78     ierr = close(vmatlab->port);
79 #endif
80     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
81   }
82   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
83   PetscFunctionReturn(0);
84 }
85 
86 /*--------------------------------------------------------------*/
87 #undef __FUNCT__
88 #define __FUNCT__ "PetscOpenSocket"
89 /*
90     PetscSocketOpen - handles connected to an open port where someone is waiting.
91 
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;
101 
102   PetscFunctionBegin;
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   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
108   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
109 
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       ierr = 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         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again");CHKERRQ(ierr);
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   PetscFunctionReturn(0);
159 }
160 
161 #define MAXHOSTNAME 100
162 #undef __FUNCT__
163 #define __FUNCT__ "PetscSocketEstablish"
164 /*
165    PetscSocketEstablish - starts a listener on a socket
166 
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 
177   PetscFunctionBegin;
178   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
179 
180   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
181 
182   hp = gethostbyname(myname);
183   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
184 
185   sa.sin_family = hp->h_addrtype;
186   sa.sin_port = htons((u_short)portnum);
187 
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     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&optval,sizeof(optval));CHKERRQ(ierr);
193   }
194 #endif
195 
196   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
197 #if defined(PETSC_HAVE_WSAGETLASTERROR)
198     ierr = 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 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "PetscSocketListen"
214 /*
215    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()
216 
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
227 
228   PetscFunctionBegin;
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   PetscFunctionReturn(0);
233 }
234 
235 #undef __FUNCT__
236 #define __FUNCT__ "PetscViewerSocketOpen"
237 /*@C
238    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket
239         based server.
240 
241    Collective on MPI_Comm
242 
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
248 
249    Output Parameter:
250 .  lab - a context to use when communicating with the server
251 
252    Level: intermediate
253 
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)
265 
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>
272 
273    Environmental variables:
274 +   PETSC_VIEWER_SOCKET_PORT portnumber
275 -   PETSC_VIEWER_SOCKET_MACHINE machine name
276 
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.
279 
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().
282 
283    Concepts: MATLAB^sending data
284    Concepts: sockets^sending data
285 
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 {
293   PetscErrorCode ierr;
294 
295   PetscFunctionBegin;
296   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
297   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
298   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
299   PetscFunctionReturn(0);
300 }
301 
302 #undef __FUNCT__
303 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
304 PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v)
305 {
306   PetscErrorCode ierr;
307   PetscInt       def = -1;
308   char           sdef[256];
309   PetscBool      tflg;
310 
311   PetscFunctionBegin;
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   ierr = PetscOptionsHead("Socket PetscViewer Options");CHKERRQ(ierr);
317     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
318     if (tflg) {
319       ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
320     } else {
321       def = PETSCSOCKETDEFAULTPORT;
322     }
323     ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
324 
325     ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
326     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
327     if (!tflg) {
328       ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
329     }
330   ierr = PetscOptionsTail();CHKERRQ(ierr);
331   PetscFunctionReturn(0);
332 }
333 
334 EXTERN_C_BEGIN
335 #undef __FUNCT__
336 #define __FUNCT__ "PetscViewerCreate_Socket"
337 PetscErrorCode  PetscViewerCreate_Socket(PetscViewer v)
338 {
339   PetscViewer_Socket *vmatlab;
340   PetscErrorCode     ierr;
341 
342   PetscFunctionBegin;
343   ierr                   = PetscNewLog(v,PetscViewer_Socket,&vmatlab);CHKERRQ(ierr);
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;
349 
350   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
351   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
352   PetscFunctionReturn(0);
353 }
354 EXTERN_C_END
355 
356 #undef __FUNCT__
357 #define __FUNCT__ "PetscViewerSocketSetConnection"
358 /*@C
359       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
360              viewer is to use
361 
362   Logically Collective on PetscViewer
363 
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
369 
370     Level: advanced
371 
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;
381 
382   PetscFunctionBegin;
383   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
384   if (port <= 0) {
385     char portn[16];
386     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
387     if (tflg) {
388       PetscInt pport;
389       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
390       port = (int)pport;
391     } else {
392       port = PETSCSOCKETDEFAULTPORT;
393     }
394   }
395   if (!machine) {
396     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
397     if (!tflg) {
398       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
399     }
400   } else {
401     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
402   }
403 
404   ierr = MPI_Comm_rank(((PetscObject)v)->comm,&rank);CHKERRQ(ierr);
405   if (!rank) {
406     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
407     if (tflg) {
408       int listenport;
409       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
410       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
411       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
412       close(listenport);
413     } else {
414       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
415       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
416     }
417   }
418   PetscFunctionReturn(0);
419 }
420 
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;
427 
428 
429 #undef __FUNCT__
430 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
431 /*@C
432      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
433 
434      Collective on MPI_Comm
435 
436      Input Parameter:
437 .    comm - the MPI communicator to share the socket PetscViewer
438 
439      Level: intermediate
440 
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>
446 
447    Environmental variables:
448 +   PETSC_VIEWER_SOCKET_PORT portnumber
449 -   PETSC_VIEWER_SOCKET_MACHINE machine name
450 
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));
455 
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.
458 
459      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
460 
461      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine.
462 
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 {
469   PetscErrorCode ierr;
470   PetscBool      flg;
471   PetscViewer    viewer;
472   MPI_Comm       ncomm;
473 
474   PetscFunctionBegin;
475   ierr = PetscCommDuplicate(comm,&ncomm,PETSC_NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
476   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
477     ierr = 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," ");PetscFunctionReturn(0);}
479   }
480   ierr = 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," ");PetscFunctionReturn(0);}
482   if (!flg) { /* PetscViewer not yet created */
483     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
484     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
485     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
486     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
487     ierr = 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," ");PetscFunctionReturn(0);}
489   }
490   ierr = PetscCommDestroy(&ncomm);
491   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
492   PetscFunctionReturn(viewer);
493 }
494 
495 #if defined(PETSC_USE_SERVER)
496 
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"
501 
502 #undef __FUNCT__
503 #define __FUNCT__ "PetscWebSendHeader"
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];
508 
509   PetscFunctionBegin;
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   PetscFunctionReturn(0);
521 }
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "PetscWebSendFooter"
525 PetscErrorCode PetscWebSendFooter(FILE *fd)
526 {
527   PetscFunctionBegin;
528   fprintf(fd, "</BODY></HTML>\r\n");
529   PetscFunctionReturn(0);
530 }
531 
532 #undef __FUNCT__
533 #define __FUNCT__ "PetscWebSendError"
534 PetscErrorCode PetscWebSendError(FILE *f, int status, const char *title, const char *extra, const char *text)
535 {
536   PetscErrorCode ierr;
537 
538   PetscFunctionBegin;
539   ierr = PetscWebSendHeader(f, status, title, extra, "text/html", -1);CHKERRQ(ierr);
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   ierr = PetscWebSendFooter(f);CHKERRQ(ierr);
544   PetscFunctionReturn(0);
545 }
546 
547 #if defined(PETSC_HAVE_AMS)
548 #undef __FUNCT__
549 #define __FUNCT__ "PetscAMSDisplayList"
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   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
565   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
566   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
567   if (!comm_list || !comm_list[0]) {
568     fprintf(fd, "AMS Communicator not running</p>\r\n");
569   } else {
570     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
571     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
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 	ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
580 	ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
581 	j = 0;
582 	fprintf(fd,"<ul>\r\n");
583 	while (fld_list[j]) {
584 	  fprintf(fd,"<li> %s",fld_list[j]);
585 	  ierr = AMS_Memory_get_field_info(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
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   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
600   ierr = AMS_Disconnect();CHKERRQ(ierr);
601   PetscFunctionReturn(0);
602 }
603 
604 #undef __FUNCT__
605 #define __FUNCT__ "PetscAMSDisplayTree"
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   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
621   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
622   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
623   if (!comm_list || !comm_list[0]) {
624     fprintf(fd, "AMS Communicator not running</p>\r\n");
625   } else {
626     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
627     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
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;
634 
635       /* get maximum number of objects */
636       while (mem_list[i]) {
637 	ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
638 	ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
639         ierr = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
640         Id = (int*) addr2;
641         maxId = PetscMax(maxId,*Id);
642 	i++;
643       }
644       maxId++;
645 
646       /* Gets everyone's parent ID and which nodes are masked */
647       ierr = PetscMalloc4(maxId,PetscInt,&parentid,maxId,PetscBool ,&mask,maxId,char**,&classes,maxId,char**,&subclasses);CHKERRQ(ierr);
648       ierr = PetscMemzero(classes,maxId*sizeof(char*));CHKERRQ(ierr);
649       ierr = PetscMemzero(subclasses,maxId*sizeof(char*));CHKERRQ(ierr);
650       for (i=0; i<maxId; i++) mask[i] = PETSC_TRUE;
651       i = 0;
652       while (mem_list[i]) {
653 	ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
654 	ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
655         ierr = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
656         Id = (int*) addr2;
657 	ierr = AMS_Memory_get_field_info(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
658 	parentId = (int*) addr3;
659 	ierr = AMS_Memory_get_field_info(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
660         clas = *(char**)addr;
661 	ierr = AMS_Memory_get_field_info(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
662         sclas = *(char**)addr4;
663         parentid[*Id] = *parentId;
664 	mask[*Id]     = PETSC_FALSE;
665         ierr = PetscStrallocpy(clas,classes+*Id);CHKERRQ(ierr);
666         ierr = PetscStrallocpy(sclas,subclasses+*Id);CHKERRQ(ierr);
667         i++;
668       }
669 
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       }
674 
675       ierr = PetscProcessTree(maxId,mask,parentid,&Nlevels,&Level,&Levelcnt,&Idbylevel,&Column);CHKERRQ(ierr);
676 
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       }
683 
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");
704 
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       ierr = PetscFree(Level);CHKERRQ(ierr);
729       ierr = PetscFree(Levelcnt);CHKERRQ(ierr);
730       ierr = PetscFree(Idbylevel);CHKERRQ(ierr);
731       ierr = PetscFree(Column);CHKERRQ(ierr);
732       for (i=0; i<maxId; i++) {
733         ierr = PetscFree(classes[i]);CHKERRQ(ierr);
734         ierr = PetscFree(subclasses[i]);CHKERRQ(ierr);
735       }
736       ierr = PetscFree4(mask,parentid,classes,subclasses);CHKERRQ(ierr);
737 
738       ierr = AMS_Disconnect();CHKERRQ(ierr);
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   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
746 
747   PetscFunctionReturn(0);
748 }
749 #endif
750 
751 #if defined(PETSC_HAVE_YAML)
752 
753 EXTERN_C_BEGIN
754 /*
755     Toy function that returns all the arguments it is passed
756 */
757 #undef __FUNCT__
758 #define __FUNCT__ "YAML_echo"
759 PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
760 {
761   PetscErrorCode ierr;
762   PetscInt       i;
763 
764   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
765   for (i=0; i<argc; i++) {
766     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
767   }
768   *argco = argc;
769   ierr = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
770   for (i=0; i<argc; i++) {
771     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
772   }
773   PetscFunctionReturn(0);
774 }
775 EXTERN_C_END
776 
777 EXTERN_C_BEGIN
778 #undef __FUNCT__
779 #define __FUNCT__ "YAML_AMS_Connect"
780 /*
781       Connects to the local AMS and gets only the first communication name
782 
783    Input Parameters:
784 .     none
785 
786    Output Parameter:
787 .     oarg1 - the string name of the first communicator
788 
789 */
790 PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
791 {
792   PetscErrorCode ierr;
793   char           **list = 0;
794 
795   PetscFunctionBegin;
796   ierr = AMS_Connect(0,-1,&list);
797   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);}
798   else if (!list) {ierr = PetscInfo(PETSC_NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);}
799   *argco = 1;
800   ierr = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
801   if (list){
802     ierr = PetscStrallocpy(list[0],&(*argso)[0]);CHKERRQ(ierr);
803   } else {
804     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
805   }
806   PetscFunctionReturn(0);
807 }
808 EXTERN_C_END
809 
810 EXTERN_C_BEGIN
811 #undef __FUNCT__
812 #define __FUNCT__ "YAML_AMS_Comm_attach"
813 /*
814       Attaches to an AMS communicator
815 
816    Input Parameter:
817 .     arg1 - string name of the communicator
818 
819    Output Parameter:
820 .     oarg1 - the integer name of the communicator
821 
822 */
823 PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
824 {
825   PetscErrorCode ierr;
826   AMS_Comm       comm = -1;
827 
828   PetscFunctionBegin;
829   ierr = AMS_Comm_attach(args[0],&comm);
830   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);}
831   *argco = 1;
832   ierr = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
833   ierr = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
834   sprintf(argso[0][0],"%d",(int)comm);
835   PetscFunctionReturn(0);
836 }
837 EXTERN_C_END
838 
839 EXTERN_C_BEGIN
840 #undef __FUNCT__
841 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
842 /*
843       Gets the list of memories on an AMS Comm
844 
845    Input Parameter:
846 .     arg1 - integer name of the communicator
847 
848    Output Parameter:
849 .     oarg1 - the list of names
850 
851 */
852 PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
853 {
854   PetscErrorCode ierr;
855   char           **mem_list;
856   AMS_Comm       comm;
857   PetscInt       i,iargco = 0;
858 
859   PetscFunctionBegin;
860   sscanf(args[0],"%d",&comm);
861   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
862   if (ierr) {
863     ierr = PetscInfo1(PETSC_NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
864   } else {
865     while (mem_list[iargco++]) ;
866     iargco--;
867 
868     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
869     for (i=0; i<iargco; i++) {
870       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
871     }
872   }
873   *argco = iargco;
874   PetscFunctionReturn(0);
875 }
876 EXTERN_C_END
877 
878 EXTERN_C_BEGIN
879 #undef __FUNCT__
880 #define __FUNCT__ "YAML_AMS_Memory_attach"
881 /*
882       Attaches to an AMS memory in a communicator
883 
884    Input Parameter:
885 .     arg1 - communicator
886 .     arg2 - string name of the memory
887 
888    Output Parameter:
889 .     oarg1 - the integer name of the memory
890 .     oarg2 - the integer step of the memory
891 
892 */
893 PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
894 {
895   PetscErrorCode ierr;
896   AMS_Comm       comm;
897   AMS_Memory     mem;
898   unsigned int   step;
899 
900   PetscFunctionBegin;
901   sscanf(args[0],"%d",&comm);
902   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
903   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
904   *argco = 2;
905   ierr = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
906   ierr = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
907   sprintf(argso[0][0],"%d",(int)mem);
908   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
909   sprintf(argso[0][1],"%d",(int)step);
910   PetscFunctionReturn(0);
911 }
912 EXTERN_C_END
913 
914 EXTERN_C_BEGIN
915 #undef __FUNCT__
916 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
917 /*
918       Gets the list of fields on an AMS Memory
919 
920    Input Parameter:
921 .     arg1 - integer name of the memory
922 
923    Output Parameter:
924 .     oarg1 - the list of names
925 
926 */
927 PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
928 {
929   PetscErrorCode ierr;
930   char           **field_list;
931   AMS_Memory     mem;
932   PetscInt       i,iargco = 0;
933 
934   PetscFunctionBegin;
935   sscanf(args[0],"%d",&mem);
936   ierr = AMS_Memory_get_field_list(mem,&field_list);
937   if (ierr) {
938     ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
939   } else {
940     while (field_list[iargco++]) ;
941     iargco--;
942 
943     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
944     for (i=0; i<iargco; i++) {
945       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
946     }
947   }
948   *argco = iargco;
949   PetscFunctionReturn(0);
950 }
951 EXTERN_C_END
952 
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};
957 
958 EXTERN_C_BEGIN
959 #undef __FUNCT__
960 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
961 /*
962       Gets information about a field
963 
964    Input Parameter:
965 .     arg1 - memory
966 .     arg2 - string name of the field
967 
968    Output Parameter:
969 
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;
982 
983   PetscFunctionBegin;
984   sscanf(args[0],"%d",&mem);
985   ierr = AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
986   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
987   *argco = 4 + len;
988   ierr = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
989   ierr = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
990   ierr = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
991   ierr = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
992   ierr = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
993   for (i=0; i<len; i++) {
994     if (dtype == AMS_STRING) {
995       ierr = PetscStrallocpy(*(const char **)addr,&argso[0][4+i]);CHKERRQ(ierr);
996     } else if (dtype == AMS_DOUBLE) {
997       ierr = PetscMalloc(20*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
998       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
999     } else if (dtype == AMS_INT) {
1000       ierr = PetscMalloc(10*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1001       sprintf(argso[0][4+i],"%d",*(int*)addr);
1002     } else if (dtype == AMS_BOOLEAN) {
1003       if (*(int*)addr) {
1004         ierr = PetscStrallocpy("true",&argso[0][4+i]);CHKERRQ(ierr);
1005       } else {
1006         ierr = PetscStrallocpy("false",&argso[0][4+i]);CHKERRQ(ierr);
1007       }
1008     } else {
1009       ierr = PetscStrallocpy("Not yet done",&argso[0][4+i]);CHKERRQ(ierr);
1010     }
1011   }
1012   PetscFunctionReturn(0);
1013 }
1014 EXTERN_C_END
1015 
1016 #include "yaml.h"
1017 #undef __FUNCT__
1018 #define __FUNCT__ "PetscProcessYAMLRPC"
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;
1026   PetscErrorCode ierr;
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 ***);
1031 
1032   PetscFunctionBegin;
1033   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1034   yaml_parser_initialize(&parser);
1035   PetscStrlen(request,&len);
1036   yaml_parser_set_input_string(&parser, (unsigned char *)request, len);
1037 
1038   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1039   while (!done) {
1040     if (!yaml_parser_parse(&parser, &event)) {
1041       ierr = PetscInfo(PETSC_NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1042       break;
1043     }
1044     done = (event.type == YAML_STREAM_END_EVENT);
1045     switch (event.type) {
1046     case YAML_STREAM_START_EVENT:
1047       ierr = PetscInfo(PETSC_NULL,"Stream start\n");CHKERRQ(ierr);
1048       break;
1049     case YAML_STREAM_END_EVENT:
1050       ierr = PetscInfo(PETSC_NULL,"Stream end\n");CHKERRQ(ierr);
1051       break;
1052     case YAML_DOCUMENT_START_EVENT:
1053       ierr = PetscInfo(PETSC_NULL,"Document start\n");CHKERRQ(ierr);
1054       break;
1055     case YAML_DOCUMENT_END_EVENT:
1056       ierr = PetscInfo(PETSC_NULL,"Document end\n");CHKERRQ(ierr);
1057       break;
1058     case YAML_MAPPING_START_EVENT:
1059       ierr = PetscInfo(PETSC_NULL,"Mapping start event\n");CHKERRQ(ierr);
1060       break;
1061     case YAML_MAPPING_END_EVENT:
1062       ierr = PetscInfo(PETSC_NULL,"Mapping end event \n");CHKERRQ(ierr);
1063       break;
1064     case YAML_ALIAS_EVENT:
1065       ierr = PetscInfo1(PETSC_NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1066       break;
1067     case YAML_SCALAR_EVENT:
1068       ierr = PetscInfo1(PETSC_NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1069       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1070       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1071       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1072       if (method) {
1073         yaml_event_delete(&event);
1074         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1075         ierr = PetscInfo1(PETSC_NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1076         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1077       } else if (id) {
1078         yaml_event_delete(&event);
1079         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1080         ierr = PetscInfo1(PETSC_NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1081         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1082       } else if (params) {
1083         yaml_event_delete(&event);
1084         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1085         yaml_event_delete(&event);
1086         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1087         while (event.type != YAML_SEQUENCE_END_EVENT) {
1088           ierr = PetscInfo1(PETSC_NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1089           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1090           yaml_event_delete(&event);
1091           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1092         }
1093       } else { /* ignore all the other variables in the mapping */
1094         yaml_event_delete(&event);
1095         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1096       }
1097       break;
1098     case YAML_SEQUENCE_START_EVENT:
1099       ierr = PetscInfo(PETSC_NULL,"Sequence start event \n");CHKERRQ(ierr);
1100       break;
1101     case YAML_SEQUENCE_END_EVENT:
1102       ierr = PetscInfo(PETSC_NULL,"Sequence end event \n");CHKERRQ(ierr);
1103       break;
1104     default:
1105       /* It couldn't really happen. */
1106       break;
1107     }
1108 
1109     yaml_event_delete(&event);
1110     count ++;
1111   }
1112   yaml_parser_delete(&parser);
1113 
1114   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,PETSC_NULL,PETSC_NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1115   if (fun) {
1116     ierr = PetscInfo1(PETSC_NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1117     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1118   } else {
1119     ierr = PetscInfo1(PETSC_NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1120   }
1121 
1122   for (i=0; i<argc; i++) {
1123     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1124   }
1125   ierr = PetscFree(args);CHKERRQ(ierr);
1126   ierr = PetscFree(methodname);CHKERRQ(ierr);
1127 
1128   /* convert the result back to YAML; should use YAML encoder, does not handle zero return arguments */
1129   ierr = PetscMalloc(1024,result);CHKERRQ(ierr);
1130   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1131   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1132   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1133   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1134   for (i=0; i<argco; i++) {
1135     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1136     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1137     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1138     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1139   }
1140   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1141   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1142   ierr = PetscInfo1(PETSC_NULL,"YAML result of function %s\n",*result);CHKERRQ(ierr);
1143 
1144   /* free work space */
1145   ierr = PetscFree(idname);CHKERRQ(ierr);
1146   for (i=0; i<argco; i++) {
1147     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1148   }
1149   ierr = PetscFree(argso);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 #endif
1153 
1154 #undef __FUNCT__
1155 #define __FUNCT__ "PetscWebServeRequest"
1156 /*@C
1157       PetscWebServeRequest - serves a single web request
1158 
1159     Not collective
1160 
1161   Input Parameters:
1162 .   port - the port
1163 
1164     Level: developer
1165 
1166 .seealso: PetscWebServe()
1167 @*/
1168 PetscErrorCode  PetscWebServeRequest(int port)
1169 {
1170   PetscErrorCode ierr;
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;
1178 
1179   PetscFunctionBegin;
1180   fd = fdopen(port, "r+");
1181 
1182   ierr = PetscInfo(PETSC_NULL,"Processing web request\n");CHKERRQ(ierr);
1183   if (!fgets(buf, sizeof(buf), fd)) {
1184     ierr = PetscInfo(PETSC_NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1185     goto theend;
1186   }
1187   ierr = PetscInfo1(PETSC_NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1188 
1189   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1190   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1191   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1192   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1193 
1194   if (!method || !path || !protocol) {
1195     ierr = PetscInfo(PETSC_NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1196     goto theend;
1197   }
1198 
1199   ierr = PetscStrcmp(method,"GET",&flg);
1200   if (!flg) {
1201 #if defined(PETSC_HAVE_YAML)
1202     ierr = 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           ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1214           goto theend;
1215         }
1216         ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1217         ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1218         if (fnd) {
1219           ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1220           if (!fnd) {
1221             ierr = PetscInfo(PETSC_NULL,"POST content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1222             goto theend;
1223           }
1224         }
1225       }
1226       if (!fgets(buf, sizeof(buf), fd)) {
1227         ierr = PetscInfo(PETSC_NULL,"Cannot read POST length data, giving up\n");CHKERRQ(ierr);
1228         goto theend;
1229       }
1230       ierr = PetscInfo1(PETSC_NULL,"POSTED length data %s",buf);CHKERRQ(ierr);
1231       sscanf(buf,"Content-Length: %d\n",&len);
1232       ierr = PetscInfo1(PETSC_NULL,"Length of POSTED data %d\n",len);CHKERRQ(ierr);
1233       if (!fgets(buf, sizeof(buf), fd)) {
1234         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1235         goto theend;
1236       }
1237       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1238       if (!fgets(buf, sizeof(buf), fd)) {
1239         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1240         goto theend;
1241       }
1242       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1243       if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1244         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1245         goto theend;
1246       }
1247       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s\n",buf);CHKERRQ(ierr);
1248       fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1249       ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1250       ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1251       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1252       fprintf(fd, "%s",result);
1253       goto theend;
1254     } else {
1255 #endif
1256       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1257       ierr = PetscInfo(PETSC_NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1258 #if defined(PETSC_HAVE_YAML)
1259     }
1260 #endif
1261   } else {
1262     fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1263 
1264     ierr = PetscStrcmp(path,"/favicon.ico",&flg);CHKERRQ(ierr);
1265     if (flg) {
1266       /* should have cool PETSc icon */;
1267       goto theend;
1268     }
1269     ierr = PetscStrcmp(path,"/",&flg);CHKERRQ(ierr);
1270     if (flg) {
1271       char        program[128];
1272       PetscMPIInt size;
1273       PetscViewer viewer;
1274 
1275       ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
1276       ierr = PetscGetProgramName(program,128);CHKERRQ(ierr);
1277       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
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       ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);CHKERRQ(ierr);
1283       ierr = PetscOptionsView(viewer);CHKERRQ(ierr);
1284       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
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       ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
1294       goto theend;
1295     }
1296 
1297 #if defined(PETSC_HAVE_AMS)
1298     ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
1299     if (flg) {
1300       ierr = PetscAMSDisplayList(fd);CHKERRQ(ierr);
1301       goto theend;
1302     }
1303     ierr = PetscInfo1(PETSC_NULL,"Browser path %s\n",path);
1304     ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
1305     if (flg) {
1306       ierr = PetscAMSDisplayTree(fd);CHKERRQ(ierr);
1307       goto theend;
1308     }
1309 #endif
1310     ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
1311     ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
1312     ierr = PetscInfo1(PETSC_NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
1313     ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
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"};
1321 
1322       ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
1323       type = mimes[index];
1324       if (!stat(truefullpath, &statbuf)) length = -1;
1325       else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
1326       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
1327       while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
1328       fclose(fdo);
1329       ierr = PetscInfo2(PETSC_NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
1330       goto theend;
1331     }
1332     ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
1333   }
1334   theend:
1335   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1336   fclose(fd);
1337   ierr = PetscInfo(PETSC_NULL,"Finished processing request\n");CHKERRQ(ierr);
1338 
1339   PetscFunctionReturn(0);
1340 }
1341 
1342 #undef __FUNCT__
1343 #define __FUNCT__ "PetscWebServeWait"
1344 /*@C
1345       PetscWebServeWait - waits for requests on a thread
1346 
1347     Not collective
1348 
1349   Input Parameter:
1350 .   port - port to listen on
1351 
1352     Level: developer
1353 
1354 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1355 @*/
1356 void  *PetscWebServeWait(int *port)
1357 {
1358   PetscErrorCode ierr;
1359   int            iport,listenport,tport = *port;
1360 
1361   ierr = PetscInfo1(PETSC_NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1362   ierr = PetscFree(port);if (ierr) return 0;
1363   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1364   while (1) {
1365     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1366     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1367     close(iport);
1368   }
1369   close(listenport);
1370   return 0;
1371 }
1372 
1373 #undef __FUNCT__
1374 #define __FUNCT__ "PetscWebServe"
1375 /*@C
1376       PetscWebServe - start up the PETSc web server and respond to requests
1377 
1378     Not collective - only does something on process zero of the communicator
1379 
1380   Input Parameters:
1381 +   comm - the MPI communicator
1382 -   port - port to listen on
1383 
1384   Options Database Key:
1385 +  -server <port> - start PETSc webserver (default port is 8080)
1386 -  -ams_publish_objects
1387 
1388 
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
1391 
1392       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1393 
1394       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1395 
1396     Level: developer
1397 
1398 .seealso: PetscViewerSocketOpen()
1399 @*/
1400 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1401 {
1402   PetscErrorCode ierr;
1403   PetscMPIInt    rank;
1404   pthread_t      thread;
1405   int            *trueport;
1406 
1407   PetscFunctionBegin;
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   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1410   if (rank) PetscFunctionReturn(0);
1411 
1412   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1413   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1414   *trueport = port;
1415   ierr = pthread_create(&thread, NULL, (void *(*)(void *))PetscWebServeWait, trueport);CHKERRQ(ierr);
1416   PetscFunctionReturn(0);
1417 }
1418 #endif
1419 
1420 
1421 
1422 
1423 
1424 
1425 
1426 
1427 
1428 
1429 
1430 
1431 
1432 
1433