xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 009bbdc485cd9ad46be9940d3549e2dde9cdc322)
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   PetscFunctionReturn(0);
747 }
748 #endif
749 
750 #if defined(PETSC_HAVE_YAML)
751 
752 EXTERN_C_BEGIN
753 /*
754     Toy function that returns all the arguments it is passed
755 */
756 #undef __FUNCT__
757 #define __FUNCT__ "YAML_echo"
758 PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
759 {
760   PetscErrorCode ierr;
761   PetscInt       i;
762 
763   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
764   for (i=0; i<argc; i++) {
765     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
766   }
767   *argco = argc;
768   ierr = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
769   for (i=0; i<argc; i++) {
770     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
771   }
772   PetscFunctionReturn(0);
773 }
774 EXTERN_C_END
775 
776 EXTERN_C_BEGIN
777 #undef __FUNCT__
778 #define __FUNCT__ "YAML_AMS_Connect"
779 /*
780       Connects to the local AMS and gets only the first communication name
781 
782    Input Parameters:
783 .     none
784 
785    Output Parameter:
786 .     oarg1 - the string name of the first communicator
787 
788 */
789 PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
790 {
791   PetscErrorCode ierr;
792   char           **list = 0;
793 
794   PetscFunctionBegin;
795   ierr = AMS_Connect(0,-1,&list);
796   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);}
797   else if (!list) {ierr = PetscInfo(PETSC_NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);}
798   *argco = 1;
799   ierr = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
800   if (list) {
801     ierr = PetscStrallocpy(list[0],&(*argso)[0]);CHKERRQ(ierr);
802   } else {
803     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
804   }
805   PetscFunctionReturn(0);
806 }
807 EXTERN_C_END
808 
809 EXTERN_C_BEGIN
810 #undef __FUNCT__
811 #define __FUNCT__ "YAML_AMS_Comm_attach"
812 /*
813       Attaches to an AMS communicator
814 
815    Input Parameter:
816 .     arg1 - string name of the communicator
817 
818    Output Parameter:
819 .     oarg1 - the integer name of the communicator
820 
821 */
822 PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
823 {
824   PetscErrorCode ierr;
825   AMS_Comm       comm = -1;
826 
827   PetscFunctionBegin;
828   ierr = AMS_Comm_attach(args[0],&comm);
829   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);}
830   *argco = 1;
831   ierr = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
832   ierr = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
833   sprintf(argso[0][0],"%d",(int)comm);
834   PetscFunctionReturn(0);
835 }
836 EXTERN_C_END
837 
838 EXTERN_C_BEGIN
839 #undef __FUNCT__
840 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
841 /*
842       Gets the list of memories on an AMS Comm
843 
844    Input Parameter:
845 .     arg1 - integer name of the communicator
846 
847    Output Parameter:
848 .     oarg1 - the list of names
849 
850 */
851 PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
852 {
853   PetscErrorCode ierr;
854   char           **mem_list;
855   AMS_Comm       comm;
856   PetscInt       i,iargco = 0;
857 
858   PetscFunctionBegin;
859   sscanf(args[0],"%d",&comm);
860   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
861   if (ierr) {
862     ierr = PetscInfo1(PETSC_NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
863   } else {
864     while (mem_list[iargco++]) ;
865     iargco--;
866 
867     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
868     for (i=0; i<iargco; i++) {
869       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
870     }
871   }
872   *argco = iargco;
873   PetscFunctionReturn(0);
874 }
875 EXTERN_C_END
876 
877 EXTERN_C_BEGIN
878 #undef __FUNCT__
879 #define __FUNCT__ "YAML_AMS_Memory_attach"
880 /*
881       Attaches to an AMS memory in a communicator
882 
883    Input Parameter:
884 .     arg1 - communicator
885 .     arg2 - string name of the memory
886 
887    Output Parameter:
888 .     oarg1 - the integer name of the memory
889 .     oarg2 - the integer step of the memory
890 
891 */
892 PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
893 {
894   PetscErrorCode ierr;
895   AMS_Comm       comm;
896   AMS_Memory     mem;
897   unsigned int   step;
898 
899   PetscFunctionBegin;
900   sscanf(args[0],"%d",&comm);
901   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
902   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
903   *argco = 2;
904   ierr = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
905   ierr = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
906   sprintf(argso[0][0],"%d",(int)mem);
907   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
908   sprintf(argso[0][1],"%d",(int)step);
909   PetscFunctionReturn(0);
910 }
911 EXTERN_C_END
912 
913 EXTERN_C_BEGIN
914 #undef __FUNCT__
915 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
916 /*
917       Gets the list of fields on an AMS Memory
918 
919    Input Parameter:
920 .     arg1 - integer name of the memory
921 
922    Output Parameter:
923 .     oarg1 - the list of names
924 
925 */
926 PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
927 {
928   PetscErrorCode ierr;
929   char           **field_list;
930   AMS_Memory     mem;
931   PetscInt       i,iargco = 0;
932 
933   PetscFunctionBegin;
934   sscanf(args[0],"%d",&mem);
935   ierr = AMS_Memory_get_field_list(mem,&field_list);
936   if (ierr) {
937     ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
938   } else {
939     while (field_list[iargco++]) ;
940     iargco--;
941 
942     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
943     for (i=0; i<iargco; i++) {
944       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
945     }
946   }
947   *argco = iargco;
948   PetscFunctionReturn(0);
949 }
950 EXTERN_C_END
951 
952 const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
953 const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
954 const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
955 const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};
956 
957 EXTERN_C_BEGIN
958 #undef __FUNCT__
959 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
960 /*
961       Gets information about a field
962 
963    Input Parameter:
964 .     arg1 - memory
965 .     arg2 - string name of the field
966 
967    Output Parameter:
968 
969 */
970 PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
971 {
972   PetscErrorCode     ierr;
973   AMS_Memory         mem;
974   void               *addr;
975   int                len;
976   AMS_Data_type      dtype;
977   AMS_Memory_type    mtype;
978   AMS_Shared_type    stype;
979   AMS_Reduction_type rtype;
980   PetscInt           i;
981 
982   PetscFunctionBegin;
983   sscanf(args[0],"%d",&mem);
984   ierr = AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
985   if (ierr) {ierr = PetscInfo1(PETSC_NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
986   *argco = 4 + len;
987   ierr = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
988   ierr = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
989   ierr = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
990   ierr = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
991   ierr = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
992   for (i=0; i<len; i++) {
993     if (dtype == AMS_STRING) {
994       ierr = PetscStrallocpy(*(const char **)addr,&argso[0][4+i]);CHKERRQ(ierr);
995     } else if (dtype == AMS_DOUBLE) {
996       ierr = PetscMalloc(20*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
997       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
998     } else if (dtype == AMS_INT) {
999       ierr = PetscMalloc(10*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1000       sprintf(argso[0][4+i],"%d",*(int*)addr);
1001     } else if (dtype == AMS_BOOLEAN) {
1002       if (*(int*)addr) {
1003         ierr = PetscStrallocpy("true",&argso[0][4+i]);CHKERRQ(ierr);
1004       } else {
1005         ierr = PetscStrallocpy("false",&argso[0][4+i]);CHKERRQ(ierr);
1006       }
1007     } else {
1008       ierr = PetscStrallocpy("Not yet done",&argso[0][4+i]);CHKERRQ(ierr);
1009     }
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 EXTERN_C_END
1014 
1015 #include "yaml.h"
1016 #undef __FUNCT__
1017 #define __FUNCT__ "PetscProcessYAMLRPC"
1018 PetscErrorCode PetscProcessYAMLRPC(const char* request,char **result)
1019 {
1020   yaml_parser_t  parser;
1021   yaml_event_t   event;
1022   int            done = 0;
1023   int            count = 0;
1024   size_t         len;
1025   PetscErrorCode ierr;
1026   PetscBool      method,params,id;
1027   char           *methodname,*idname,**args,**argso = 0;
1028   PetscInt       argc = 0,argco,i;
1029   PetscErrorCode (*fun)(PetscInt,char **,PetscInt*,char ***);
1030 
1031   PetscFunctionBegin;
1032   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1033   yaml_parser_initialize(&parser);
1034   PetscStrlen(request,&len);
1035   yaml_parser_set_input_string(&parser, (unsigned char *)request, len);
1036 
1037   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1038   while (!done) {
1039     if (!yaml_parser_parse(&parser, &event)) {
1040       ierr = PetscInfo(PETSC_NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1041       break;
1042     }
1043     done = (event.type == YAML_STREAM_END_EVENT);
1044     switch (event.type) {
1045     case YAML_STREAM_START_EVENT:
1046       ierr = PetscInfo(PETSC_NULL,"Stream start\n");CHKERRQ(ierr);
1047       break;
1048     case YAML_STREAM_END_EVENT:
1049       ierr = PetscInfo(PETSC_NULL,"Stream end\n");CHKERRQ(ierr);
1050       break;
1051     case YAML_DOCUMENT_START_EVENT:
1052       ierr = PetscInfo(PETSC_NULL,"Document start\n");CHKERRQ(ierr);
1053       break;
1054     case YAML_DOCUMENT_END_EVENT:
1055       ierr = PetscInfo(PETSC_NULL,"Document end\n");CHKERRQ(ierr);
1056       break;
1057     case YAML_MAPPING_START_EVENT:
1058       ierr = PetscInfo(PETSC_NULL,"Mapping start event\n");CHKERRQ(ierr);
1059       break;
1060     case YAML_MAPPING_END_EVENT:
1061       ierr = PetscInfo(PETSC_NULL,"Mapping end event \n");CHKERRQ(ierr);
1062       break;
1063     case YAML_ALIAS_EVENT:
1064       ierr = PetscInfo1(PETSC_NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1065       break;
1066     case YAML_SCALAR_EVENT:
1067       ierr = PetscInfo1(PETSC_NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1068       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1069       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1070       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1071       if (method) {
1072         yaml_event_delete(&event);
1073         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1074         ierr = PetscInfo1(PETSC_NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1075         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1076       } else if (id) {
1077         yaml_event_delete(&event);
1078         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1079         ierr = PetscInfo1(PETSC_NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1080         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1081       } else if (params) {
1082         yaml_event_delete(&event);
1083         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1084         yaml_event_delete(&event);
1085         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1086         while (event.type != YAML_SEQUENCE_END_EVENT) {
1087           ierr = PetscInfo1(PETSC_NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1088           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1089           yaml_event_delete(&event);
1090           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1091         }
1092       } else { /* ignore all the other variables in the mapping */
1093         yaml_event_delete(&event);
1094         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1095       }
1096       break;
1097     case YAML_SEQUENCE_START_EVENT:
1098       ierr = PetscInfo(PETSC_NULL,"Sequence start event \n");CHKERRQ(ierr);
1099       break;
1100     case YAML_SEQUENCE_END_EVENT:
1101       ierr = PetscInfo(PETSC_NULL,"Sequence end event \n");CHKERRQ(ierr);
1102       break;
1103     default:
1104       /* It couldn't really happen. */
1105       break;
1106     }
1107 
1108     yaml_event_delete(&event);
1109     count ++;
1110   }
1111   yaml_parser_delete(&parser);
1112 
1113   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,PETSC_NULL,PETSC_NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1114   if (fun) {
1115     ierr = PetscInfo1(PETSC_NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1116     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1117   } else {
1118     ierr = PetscInfo1(PETSC_NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1119   }
1120 
1121   for (i=0; i<argc; i++) {
1122     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1123   }
1124   ierr = PetscFree(args);CHKERRQ(ierr);
1125   ierr = PetscFree(methodname);CHKERRQ(ierr);
1126 
1127   /* convert the result back to YAML; should use YAML encoder, does not handle zero return arguments */
1128   ierr = PetscMalloc(1024,result);CHKERRQ(ierr);
1129   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1130   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1131   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1132   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1133   for (i=0; i<argco; i++) {
1134     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1135     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1136     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1137     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1138   }
1139   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1140   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1141   ierr = PetscInfo1(PETSC_NULL,"YAML result of function %s\n",*result);CHKERRQ(ierr);
1142 
1143   /* free work space */
1144   ierr = PetscFree(idname);CHKERRQ(ierr);
1145   for (i=0; i<argco; i++) {
1146     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1147   }
1148   ierr = PetscFree(argso);CHKERRQ(ierr);
1149   PetscFunctionReturn(0);
1150 }
1151 #endif
1152 
1153 #undef __FUNCT__
1154 #define __FUNCT__ "PetscWebServeRequest"
1155 /*@C
1156       PetscWebServeRequest - serves a single web request
1157 
1158     Not collective
1159 
1160   Input Parameters:
1161 .   port - the port
1162 
1163     Level: developer
1164 
1165 .seealso: PetscWebServe()
1166 @*/
1167 PetscErrorCode  PetscWebServeRequest(int port)
1168 {
1169   PetscErrorCode ierr;
1170   FILE           *fd,*fdo;
1171   char           buf[4096],fullpath[PETSC_MAX_PATH_LEN],truefullpath[PETSC_MAX_PATH_LEN];
1172   char           *method, *path, *protocol,*result;
1173   const char*    type;
1174   PetscBool      flg;
1175   PetscToken     tok;
1176   PetscInt       cnt = 8;
1177 
1178   PetscFunctionBegin;
1179   fd = fdopen(port, "r+");
1180 
1181   ierr = PetscInfo(PETSC_NULL,"Processing web request\n");CHKERRQ(ierr);
1182   if (!fgets(buf, sizeof(buf), fd)) {
1183     ierr = PetscInfo(PETSC_NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1184     goto theend;
1185   }
1186   ierr = PetscInfo1(PETSC_NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1187 
1188   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1189   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1190   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1191   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1192 
1193   if (!method || !path || !protocol) {
1194     ierr = PetscInfo(PETSC_NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1195     goto theend;
1196   }
1197 
1198   ierr = PetscStrcmp(method,"GET",&flg);
1199   if (!flg) {
1200 #if defined(PETSC_HAVE_YAML)
1201     ierr = PetscStrcmp(method,"POST",&flg);
1202     /*
1203           Start to handle support for POSTs based on json-rpc
1204     */
1205     if (flg) {
1206       int    len;
1207       size_t elen;
1208       char   *fnd;
1209       while (cnt--) {
1210 
1211         if (!fgets(buf, sizeof(buf), fd)) {
1212           ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1213           goto theend;
1214         }
1215         ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1216         ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1217         if (fnd) {
1218           ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1219           if (!fnd) {
1220             ierr = PetscInfo(PETSC_NULL,"POST content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1221             goto theend;
1222           }
1223         }
1224       }
1225       if (!fgets(buf, sizeof(buf), fd)) {
1226         ierr = PetscInfo(PETSC_NULL,"Cannot read POST length data, giving up\n");CHKERRQ(ierr);
1227         goto theend;
1228       }
1229       ierr = PetscInfo1(PETSC_NULL,"POSTED length data %s",buf);CHKERRQ(ierr);
1230       sscanf(buf,"Content-Length: %d\n",&len);
1231       ierr = PetscInfo1(PETSC_NULL,"Length of POSTED data %d\n",len);CHKERRQ(ierr);
1232       if (!fgets(buf, sizeof(buf), fd)) {
1233         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1234         goto theend;
1235       }
1236       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1237       if (!fgets(buf, sizeof(buf), fd)) {
1238         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1239         goto theend;
1240       }
1241       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1242       if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1243         ierr = PetscInfo(PETSC_NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1244         goto theend;
1245       }
1246       ierr = PetscInfo1(PETSC_NULL,"POSTED data %s\n",buf);CHKERRQ(ierr);
1247       fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1248       ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1249       ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1250       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1251       fprintf(fd, "%s",result);
1252       goto theend;
1253     } else {
1254 #endif
1255       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1256       ierr = PetscInfo(PETSC_NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1257 #if defined(PETSC_HAVE_YAML)
1258     }
1259 #endif
1260   } else {
1261     fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1262 
1263     ierr = PetscStrcmp(path,"/favicon.ico",&flg);CHKERRQ(ierr);
1264     if (flg) {
1265       /* should have cool PETSc icon */;
1266       goto theend;
1267     }
1268     ierr = PetscStrcmp(path,"/",&flg);CHKERRQ(ierr);
1269     if (flg) {
1270       char        program[128];
1271       PetscMPIInt size;
1272       PetscViewer viewer;
1273 
1274       ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
1275       ierr = PetscGetProgramName(program,128);CHKERRQ(ierr);
1276       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
1277       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
1278       fprintf(fd, "<H4>Serving PETSc application code %s </H4>\r\n\n",program);
1279       fprintf(fd, "Number of processes %d\r\n\n",size);
1280       fprintf(fd, "<HR>\r\n");
1281       ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);CHKERRQ(ierr);
1282       ierr = PetscOptionsView(viewer);CHKERRQ(ierr);
1283       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1284       fprintf(fd, "<HR>\r\n");
1285 #if defined(PETSC_HAVE_AMS)
1286       if (PetscAMSPublishAll) {
1287         fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
1288         fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
1289       }
1290 #endif
1291       fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
1292       ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
1293       goto theend;
1294     }
1295 
1296 #if defined(PETSC_HAVE_AMS)
1297     ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
1298     if (flg) {
1299       ierr = PetscAMSDisplayList(fd);CHKERRQ(ierr);
1300       goto theend;
1301     }
1302     ierr = PetscInfo1(PETSC_NULL,"Browser path %s\n",path);
1303     ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
1304     if (flg) {
1305       ierr = PetscAMSDisplayTree(fd);CHKERRQ(ierr);
1306       goto theend;
1307     }
1308 #endif
1309     ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
1310     ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
1311     ierr = PetscInfo1(PETSC_NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
1312     ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
1313     fdo  = fopen(truefullpath,"r");
1314     if (fdo) {
1315       PetscInt    length,index;
1316       char        data[4096];
1317       struct stat statbuf;
1318       int         n;
1319       const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};
1320 
1321       ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
1322       type = mimes[index];
1323       if (!stat(truefullpath, &statbuf)) length = -1;
1324       else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
1325       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
1326       while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
1327       fclose(fdo);
1328       ierr = PetscInfo2(PETSC_NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
1329       goto theend;
1330     }
1331     ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
1332   }
1333   theend:
1334   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1335   fclose(fd);
1336   ierr = PetscInfo(PETSC_NULL,"Finished processing request\n");CHKERRQ(ierr);
1337   PetscFunctionReturn(0);
1338 }
1339 
1340 #undef __FUNCT__
1341 #define __FUNCT__ "PetscWebServeWait"
1342 /*@C
1343       PetscWebServeWait - waits for requests on a thread
1344 
1345     Not collective
1346 
1347   Input Parameter:
1348 .   port - port to listen on
1349 
1350     Level: developer
1351 
1352 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1353 @*/
1354 void  *PetscWebServeWait(int *port)
1355 {
1356   PetscErrorCode ierr;
1357   int            iport,listenport,tport = *port;
1358 
1359   ierr = PetscInfo1(PETSC_NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1360   ierr = PetscFree(port);if (ierr) return 0;
1361   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1362   while (1) {
1363     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1364     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1365     close(iport);
1366   }
1367   close(listenport);
1368   return 0;
1369 }
1370 
1371 #undef __FUNCT__
1372 #define __FUNCT__ "PetscWebServe"
1373 /*@C
1374       PetscWebServe - start up the PETSc web server and respond to requests
1375 
1376     Not collective - only does something on process zero of the communicator
1377 
1378   Input Parameters:
1379 +   comm - the MPI communicator
1380 -   port - port to listen on
1381 
1382   Options Database Key:
1383 +  -server <port> - start PETSc webserver (default port is 8080)
1384 -  -ams_publish_objects
1385 
1386 
1387    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1388       If you are running PETSc on your local machine you can use http://localhost:8080
1389 
1390       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1391 
1392       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1393 
1394     Level: developer
1395 
1396 .seealso: PetscViewerSocketOpen()
1397 @*/
1398 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1399 {
1400   PetscErrorCode ierr;
1401   PetscMPIInt    rank;
1402   pthread_t      thread;
1403   int            *trueport;
1404 
1405   PetscFunctionBegin;
1406   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1407   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1408   if (rank) PetscFunctionReturn(0);
1409 
1410   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1411   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1412   *trueport = port;
1413   ierr = pthread_create(&thread, NULL, (void *(*)(void *))PetscWebServeWait, trueport);CHKERRQ(ierr);
1414   PetscFunctionReturn(0);
1415 }
1416 #endif
1417 
1418 
1419 
1420 
1421 
1422 
1423 
1424 
1425 
1426 
1427 
1428 
1429 
1430 
1431