xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision b0250c70e4345ebd57129b1d4ec5b75c4c83ee38)
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 #include <sys/types.h>
16 #include <ctype.h>
17 #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
18 #include <machine/endian.h>
19 #endif
20 #if defined(PETSC_HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #if defined(PETSC_HAVE_SYS_SOCKET_H)
24 #include <sys/socket.h>
25 #endif
26 #if defined(PETSC_HAVE_SYS_WAIT_H)
27 #include <sys/wait.h>
28 #endif
29 #if defined(PETSC_HAVE_NETINET_IN_H)
30 #include <netinet/in.h>
31 #endif
32 #if defined(PETSC_HAVE_NETDB_H)
33 #include <netdb.h>
34 #endif
35 #if defined(PETSC_HAVE_FCNTL_H)
36 #include <fcntl.h>
37 #endif
38 #if defined(PETSC_HAVE_IO_H)
39 #include <io.h>
40 #endif
41 #if defined(PETSC_HAVE_WINSOCK2_H)
42 #include <Winsock2.h>
43 #endif
44 #include <sys/stat.h>
45 #include <../src/sys/classes/viewer/impls/socket/socket.h>
46 
47 EXTERN_C_BEGIN
48 #if defined(PETSC_NEED_CLOSE_PROTO)
49 extern int close(int);
50 #endif
51 #if defined(PETSC_NEED_SOCKET_PROTO)
52 extern int socket(int,int,int);
53 #endif
54 #if defined(PETSC_NEED_SLEEP_PROTO)
55 extern int sleep(unsigned);
56 #endif
57 #if defined(PETSC_NEED_CONNECT_PROTO)
58 extern int connect(int,struct sockaddr*,int);
59 #endif
60 EXTERN_C_END
61 
62 /*--------------------------------------------------------------*/
63 #undef __FUNCT__
64 #define __FUNCT__ "PetscViewerDestroy_Socket"
65 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
66 {
67   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
68   PetscErrorCode     ierr;
69 
70   PetscFunctionBegin;
71   if (vmatlab->port) {
72 #if defined(PETSC_HAVE_CLOSESOCKET)
73     ierr = closesocket(vmatlab->port);
74 #else
75     ierr = close(vmatlab->port);
76 #endif
77     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
78   }
79   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
80   PetscFunctionReturn(0);
81 }
82 
83 /*--------------------------------------------------------------*/
84 #undef __FUNCT__
85 #define __FUNCT__ "PetscOpenSocket"
86 /*
87     PetscSocketOpen - handles connected to an open port where someone is waiting.
88 
89 .seealso:   PetscSocketListen(), PetscSocketEstablish()
90 */
91 PetscErrorCode  PetscOpenSocket(char *hostname,int portnum,int *t)
92 {
93   struct sockaddr_in sa;
94   struct hostent     *hp;
95   int                s = 0;
96   PetscErrorCode     ierr;
97   PetscBool          flg = PETSC_TRUE;
98 
99   PetscFunctionBegin;
100   if (!(hp=gethostbyname(hostname))) {
101     perror("SEND: error gethostbyname: ");
102     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
103   }
104   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
105   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
106 
107   sa.sin_family = hp->h_addrtype;
108   sa.sin_port   = htons((u_short) portnum);
109   while (flg) {
110     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
111       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
112     }
113     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
114 #if defined(PETSC_HAVE_WSAGETLASTERROR)
115       ierr = WSAGetLastError();
116       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
117       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
118       else if (ierr == WSAEISCONN) {
119         (*PetscErrorPrintf)("SEND: socket already connected\n");
120         Sleep((unsigned) 1);
121       } else if (ierr == WSAECONNREFUSED) {
122         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
123         Sleep((unsigned) 1);
124       } else {
125         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
126       }
127 #else
128       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
129       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
130       else if (errno == EISCONN) {
131         (*PetscErrorPrintf)("SEND: socket already connected\n");
132         sleep((unsigned) 1);
133       } else if (errno == ECONNREFUSED) {
134         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
135         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again");CHKERRQ(ierr);
136         sleep((unsigned) 1);
137       } else {
138         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
139       }
140 #endif
141       flg = PETSC_TRUE;
142 #if defined(PETSC_HAVE_CLOSESOCKET)
143       closesocket(s);
144 #else
145       close(s);
146 #endif
147     } else flg = PETSC_FALSE;
148   }
149   *t = s;
150   PetscFunctionReturn(0);
151 }
152 
153 #define MAXHOSTNAME 100
154 #undef __FUNCT__
155 #define __FUNCT__ "PetscSocketEstablish"
156 /*
157    PetscSocketEstablish - starts a listener on a socket
158 
159 .seealso:   PetscSocketListen()
160 */
161 PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
162 {
163   char               myname[MAXHOSTNAME+1];
164   int                s;
165   PetscErrorCode     ierr;
166   struct sockaddr_in sa;
167   struct hostent     *hp;
168 
169   PetscFunctionBegin;
170   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
171 
172   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
173 
174   hp = gethostbyname(myname);
175   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
176 
177   sa.sin_family = hp->h_addrtype;
178   sa.sin_port   = htons((u_short)portnum);
179 
180   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
181 #if defined(PETSC_HAVE_SO_REUSEADDR)
182   {
183     int optval = 1; /* Turn on the option */
184     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
185   }
186 #endif
187 
188   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
189 #if defined(PETSC_HAVE_WSAGETLASTERROR)
190     ierr = WSAGetLastError();
191     if (ierr != WSAEADDRINUSE) {
192 #else
193     if (errno != EADDRINUSE) {
194 #endif
195       close(s);
196       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
197     }
198   }
199   listen(s,0);
200   *ss = s;
201   return(0);
202 }
203 
204 #undef __FUNCT__
205 #define __FUNCT__ "PetscSocketListen"
206 /*
207    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()
208 
209 .seealso:   PetscSocketEstablish()
210 */
211 PetscErrorCode PetscSocketListen(int listenport,int *t)
212 {
213   struct sockaddr_in isa;
214 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
215   size_t             i;
216 #else
217   int                i;
218 #endif
219 
220   PetscFunctionBegin;
221   /* wait for someone to try to connect */
222   i = sizeof(struct sockaddr_in);
223   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "PetscViewerSocketOpen"
229 /*@C
230    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket
231         based server.
232 
233    Collective on MPI_Comm
234 
235    Input Parameters:
236 +  comm - the MPI communicator
237 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
238              a connection from elsewhere
239 -  port - the port to connect to, use PETSC_DEFAULT for the default
240 
241    Output Parameter:
242 .  lab - a context to use when communicating with the server
243 
244    Level: intermediate
245 
246    Notes:
247    Most users should employ the following commands to access the
248    MATLAB PetscViewers
249 $
250 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
251 $    MatView(Mat matrix,PetscViewer viewer)
252 $
253 $                or
254 $
255 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
256 $    VecView(Vec vector,PetscViewer viewer)
257 
258    Options Database Keys:
259    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
260    PETSC_VIEWER_SOCKET_() or if
261     NULL is passed for machine or PETSC_DEFAULT is passed for port
262 $    -viewer_socket_machine <machine>
263 $    -viewer_socket_port <port>
264 
265    Environmental variables:
266 +   PETSC_VIEWER_SOCKET_PORT portnumber
267 -   PETSC_VIEWER_SOCKET_MACHINE machine name
268 
269      Currently the only socket client available is MATLAB. See
270      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
271 
272    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
273           use PetscViewerBinaryRead/Write/GetDescriptor().
274 
275    Concepts: MATLAB^sending data
276    Concepts: sockets^sending data
277 
278 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
279           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
280           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
281           PetscBinaryViewerGetDescriptor()
282 @*/
283 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
284 {
285   PetscErrorCode ierr;
286 
287   PetscFunctionBegin;
288   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
289   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
290   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
291   PetscFunctionReturn(0);
292 }
293 
294 #undef __FUNCT__
295 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
296 PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v)
297 {
298   PetscErrorCode ierr;
299   PetscInt       def = -1;
300   char           sdef[256];
301   PetscBool      tflg;
302 
303   PetscFunctionBegin;
304   /*
305        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
306     are listed here for the GUI to display
307   */
308   ierr = PetscOptionsHead("Socket PetscViewer Options");CHKERRQ(ierr);
309   ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
310   if (tflg) {
311     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
312   } else def = PETSCSOCKETDEFAULTPORT;
313   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
314 
315   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
316   ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
317   if (!tflg) {
318     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
319   }
320   ierr = PetscOptionsTail();CHKERRQ(ierr);
321   PetscFunctionReturn(0);
322 }
323 
324 EXTERN_C_BEGIN
325 #undef __FUNCT__
326 #define __FUNCT__ "PetscViewerCreate_Socket"
327 PetscErrorCode  PetscViewerCreate_Socket(PetscViewer v)
328 {
329   PetscViewer_Socket *vmatlab;
330   PetscErrorCode     ierr;
331 
332   PetscFunctionBegin;
333   ierr                   = PetscNewLog(v,PetscViewer_Socket,&vmatlab);CHKERRQ(ierr);
334   vmatlab->port          = 0;
335   v->data                = (void*)vmatlab;
336   v->ops->destroy        = PetscViewerDestroy_Socket;
337   v->ops->flush          = 0;
338   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
339 
340   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
341   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
342   PetscFunctionReturn(0);
343 }
344 EXTERN_C_END
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "PetscViewerSocketSetConnection"
348 /*@C
349       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
350              viewer is to use
351 
352   Logically Collective on PetscViewer
353 
354   Input Parameters:
355 +   v - viewer to connect
356 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
357              a connection from elsewhere
358 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
359 
360     Level: advanced
361 
362 .seealso: PetscViewerSocketOpen()
363 @*/
364 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
365 {
366   PetscErrorCode     ierr;
367   PetscMPIInt        rank;
368   char               mach[256];
369   PetscBool          tflg;
370   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
371 
372   PetscFunctionBegin;
373   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
374   if (port <= 0) {
375     char portn[16];
376     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
377     if (tflg) {
378       PetscInt pport;
379       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
380       port = (int)pport;
381     } else port = PETSCSOCKETDEFAULTPORT;
382   }
383   if (!machine) {
384     ierr = PetscOptionsGetenv(((PetscObject)v)->comm,"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
385     if (!tflg) {
386       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
387     }
388   } else {
389     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
390   }
391 
392   ierr = MPI_Comm_rank(((PetscObject)v)->comm,&rank);CHKERRQ(ierr);
393   if (!rank) {
394     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
395     if (tflg) {
396       int listenport;
397       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
398       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
399       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
400       close(listenport);
401     } else {
402       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
403       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
404     }
405   }
406   PetscFunctionReturn(0);
407 }
408 
409 /* ---------------------------------------------------------------------*/
410 /*
411     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
412   is attached to a communicator, in this case the attribute is a PetscViewer.
413 */
414 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
415 
416 
417 #undef __FUNCT__
418 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
419 /*@C
420      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
421 
422      Collective on MPI_Comm
423 
424      Input Parameter:
425 .    comm - the MPI communicator to share the socket PetscViewer
426 
427      Level: intermediate
428 
429    Options Database Keys:
430    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
431     NULL is passed for machine or PETSC_DEFAULT is passed for port
432 $    -viewer_socket_machine <machine>
433 $    -viewer_socket_port <port>
434 
435    Environmental variables:
436 +   PETSC_VIEWER_SOCKET_PORT portnumber
437 -   PETSC_VIEWER_SOCKET_MACHINE machine name
438 
439      Notes:
440      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
441      an error code.  The socket PetscViewer is usually used in the form
442 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
443 
444      Currently the only socket client available is MATLAB. See
445      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
446 
447      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
448 
449      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine.
450 
451 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
452           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
453           PetscViewerBinaryWriteStringArray(), PetscBinaryViewerGetDescriptor(), PETSC_VIEWER_MATLAB_()
454 @*/
455 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
456 {
457   PetscErrorCode ierr;
458   PetscBool      flg;
459   PetscViewer    viewer;
460   MPI_Comm       ncomm;
461 
462   PetscFunctionBegin;
463   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
464   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
465     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
466     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
467   }
468   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
469   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
470   if (!flg) { /* PetscViewer not yet created */
471     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
472     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
473     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
474     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
475     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
476     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
477   }
478   ierr = PetscCommDestroy(&ncomm);
479   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
480   PetscFunctionReturn(viewer);
481 }
482 
483 #if defined(PETSC_USE_SERVER)
484 
485 #include <pthread.h>
486 #include <time.h>
487 #define PROTOCOL   "HTTP/1.1"
488 #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
489 
490 #undef __FUNCT__
491 #define __FUNCT__ "PetscWebSendHeader"
492 PetscErrorCode PetscWebSendHeader(FILE *f, int status, const char *title, const char *extra, const char *mime, int length)
493 {
494   time_t now;
495   char   timebuf[128];
496 
497   PetscFunctionBegin;
498   fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
499   fprintf(f, "Server: %s\r\n", "petscserver/1.0");
500   now = time(NULL);
501   strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
502   fprintf(f, "Date: %s\r\n", timebuf);
503   if (extra) fprintf(f, "%s\r\n", extra);
504   if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
505   if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
506   fprintf(f, "Connection: close\r\n");
507   fprintf(f, "\r\n");
508   PetscFunctionReturn(0);
509 }
510 
511 #undef __FUNCT__
512 #define __FUNCT__ "PetscWebSendFooter"
513 PetscErrorCode PetscWebSendFooter(FILE *fd)
514 {
515   PetscFunctionBegin;
516   fprintf(fd, "</BODY></HTML>\r\n");
517   PetscFunctionReturn(0);
518 }
519 
520 #undef __FUNCT__
521 #define __FUNCT__ "PetscWebSendError"
522 PetscErrorCode PetscWebSendError(FILE *f, int status, const char *title, const char *extra, const char *text)
523 {
524   PetscErrorCode ierr;
525 
526   PetscFunctionBegin;
527   ierr = PetscWebSendHeader(f, status, title, extra, "text/html", -1);CHKERRQ(ierr);
528   fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
529   fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
530   fprintf(f, "%s\r\n", text);
531   ierr = PetscWebSendFooter(f);CHKERRQ(ierr);
532   PetscFunctionReturn(0);
533 }
534 
535 #if defined(PETSC_HAVE_AMS)
536 #undef __FUNCT__
537 #define __FUNCT__ "PetscAMSDisplayList"
538 PetscErrorCode PetscAMSDisplayList(FILE *fd)
539 {
540   PetscErrorCode     ierr;
541   char               host[256],**comm_list,**mem_list,**fld_list;
542   AMS_Comm           ams;
543   PetscInt           i = 0,j;
544   AMS_Memory_type    mtype;
545   AMS_Data_type      dtype;
546   AMS_Shared_type    stype;
547   AMS_Reduction_type rtype;
548   AMS_Memory         memory;
549   int                len;
550   void               *addr;
551 
552   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
553   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
554   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
555   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
556   else {
557     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
558     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
559     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
560     else {
561       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
562       fprintf(fd,"<ul>\r\n");
563       while (mem_list[i]) {
564         fprintf(fd,"<li> %s</li>\r\n",mem_list[i]);
565         ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
566         ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
567         j    = 0;
568         fprintf(fd,"<ul>\r\n");
569         while (fld_list[j]) {
570           fprintf(fd,"<li> %s",fld_list[j]);
571           ierr = AMS_Memory_get_field_info(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
572           if (len == 1) {
573             if (dtype == AMS_INT)         fprintf(fd," %d",*(int*)addr);
574             else if (dtype == AMS_STRING) fprintf(fd," %s",*(char**)addr);
575           }
576           fprintf(fd,"</li>\r\n");
577           j++;
578         }
579         fprintf(fd,"</ul>\r\n");
580         i++;
581       }
582       fprintf(fd,"</ul>\r\n");
583     }
584   }
585   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
586   ierr = AMS_Disconnect();CHKERRQ(ierr);
587   PetscFunctionReturn(0);
588 }
589 
590 #undef __FUNCT__
591 #define __FUNCT__ "PetscAMSDisplayTree"
592 PetscErrorCode PetscAMSDisplayTree(FILE *fd)
593 {
594   PetscErrorCode     ierr;
595   char               host[256],**comm_list,**mem_list,**fld_list;
596   AMS_Comm           ams;
597   PetscInt           i = 0,j;
598   AMS_Memory_type    mtype;
599   AMS_Data_type      dtype;
600   AMS_Shared_type    stype;
601   AMS_Reduction_type rtype;
602   AMS_Memory         memory;
603   int                len;
604   void               *addr2,*addr3,*addr,*addr4;
605 
606   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
607   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
608   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
609   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
610   else {
611     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
612     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
613     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
614     else {
615       PetscInt  Nlevels,*Level,*Levelcnt,*Idbylevel,*Column,*parentid,*Id,maxId = 0,maxCol = 0,*parentId,id,cnt,Nlevelcnt = 0;
616       PetscBool *mask;
617       char      **classes,*clas,**subclasses,*sclas;
618 
619       /* get maximum number of objects */
620       while (mem_list[i]) {
621         ierr  = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
622         ierr  = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
623         ierr  = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
624         Id    = (int*) addr2;
625         maxId = PetscMax(maxId,*Id);
626         i++;
627       }
628       maxId++;
629 
630       /* Gets everyone's parent ID and which nodes are masked */
631       ierr = PetscMalloc4(maxId,PetscInt,&parentid,maxId,PetscBool,&mask,maxId,char**,&classes,maxId,char**,&subclasses);CHKERRQ(ierr);
632       ierr = PetscMemzero(classes,maxId*sizeof(char*));CHKERRQ(ierr);
633       ierr = PetscMemzero(subclasses,maxId*sizeof(char*));CHKERRQ(ierr);
634       for (i=0; i<maxId; i++) mask[i] = PETSC_TRUE;
635       i = 0;
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         ierr          = AMS_Memory_get_field_info(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
642         parentId      = (int*) addr3;
643         ierr          = AMS_Memory_get_field_info(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
644         clas          = *(char**)addr;
645         ierr          = AMS_Memory_get_field_info(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
646         sclas         = *(char**)addr4;
647         parentid[*Id] = *parentId;
648         mask[*Id]     = PETSC_FALSE;
649 
650         ierr = PetscStrallocpy(clas,classes+*Id);CHKERRQ(ierr);
651         ierr = PetscStrallocpy(sclas,subclasses+*Id);CHKERRQ(ierr);
652         i++;
653       }
654 
655       /* if the parent is masked then relabel the parent as 0 since the true parent was deleted */
656       for (i=0; i<maxId; i++) {
657         if (!mask[i] && parentid[i] > 0 && mask[parentid[i]]) parentid[i] = 0;
658       }
659 
660       ierr = PetscProcessTree(maxId,mask,parentid,&Nlevels,&Level,&Levelcnt,&Idbylevel,&Column);CHKERRQ(ierr);
661 
662       for (i=0; i<Nlevels; i++) maxCol    = PetscMax(maxCol,Levelcnt[i]);
663       for (i=0; i<Nlevels; i++) Nlevelcnt = PetscMax(Nlevelcnt,Levelcnt[i]);
664 
665       /* print all the top-level objects */
666       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE>\r\n");
667       fprintf(fd, "<canvas width=800 height=600 id=\"tree\"></canvas>\r\n");
668       fprintf(fd, "<script type=\"text/javascript\">\r\n");
669       fprintf(fd, "  function draw() {\r\n");
670       fprintf(fd, "  var example = document.getElementById('tree');\r\n");
671       fprintf(fd, "  var context = example.getContext('2d');\r\n");
672       /* adjust font size based on how big a tree is printed */
673       if (Nlevels > 5 || Nlevelcnt > 10) fprintf(fd, "  context.font         = \"normal 12px sans-serif\";\r\n");
674       else                               fprintf(fd, "  context.font         = \"normal 24px sans-serif\";\r\n");
675       fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
676       fprintf(fd, "  context.textBaseline = \"top\";\r\n");
677       fprintf(fd, "  var xspacep = 0;\r\n");
678       fprintf(fd, "  var yspace = example.height/%d;\r\n",(Nlevels+1));
679       /* estimate the height of a string as twice the width of a character */
680       fprintf(fd, "  var wheight = context.measureText(\"K\");\r\n");
681       fprintf(fd, "  var height = 1.6*wheight.width;\r\n");
682 
683       cnt = 0;
684       for (i=0; i<Nlevels; i++) {
685         fprintf(fd, "  var xspace = example.width/%d;\r\n",Levelcnt[i]+1);
686         for (j=0; j<Levelcnt[i]; j++) {
687           id    = Idbylevel[cnt++];
688           clas  = classes[id];
689           sclas = subclasses[id];
690           fprintf(fd, "  var width = context.measureText(\"%s\");\r\n",clas);
691           fprintf(fd, "  var swidth = context.measureText(\"%s\");\r\n",sclas);
692           fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
693           fprintf(fd, "  context.fillRect((%d)*xspace-width.width/2, %d*yspace-height/2, width.width, height);\r\n",j+1,i+1);
694           fprintf(fd, "  context.fillRect((%d)*xspace-swidth.width/2, %d*yspace+height/2, swidth.width, height);\r\n",j+1,i+1);
695           fprintf(fd, "  context.fillStyle = \"rgb(0,0,0)\";\r\n");
696           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-width.width/2, %d*yspace-height/2);\r\n",clas,j+1,i+1);
697           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-swidth.width/2, %d*yspace+height/2);\r\n",sclas,j+1,i+1);
698           if (parentid[id]) {
699             fprintf(fd, "  context.moveTo(%d*xspace,%d*yspace-height/2);\r\n",j+1,i+1);
700             fprintf(fd, "  context.lineTo(%d*xspacep,%d*yspace+3*height/2);\r\n",Column[parentid[id]]+1,i);
701             fprintf(fd, "  context.stroke();\r\n");
702           }
703         }
704         fprintf(fd, "  xspacep = xspace;\r\n");
705       }
706       ierr = PetscFree(Level);CHKERRQ(ierr);
707       ierr = PetscFree(Levelcnt);CHKERRQ(ierr);
708       ierr = PetscFree(Idbylevel);CHKERRQ(ierr);
709       ierr = PetscFree(Column);CHKERRQ(ierr);
710       for (i=0; i<maxId; i++) {
711         ierr = PetscFree(classes[i]);CHKERRQ(ierr);
712         ierr = PetscFree(subclasses[i]);CHKERRQ(ierr);
713       }
714       ierr = PetscFree4(mask,parentid,classes,subclasses);CHKERRQ(ierr);
715 
716       ierr = AMS_Disconnect();CHKERRQ(ierr);
717       fprintf(fd, "}\r\n");
718       fprintf(fd, "</script>\r\n");
719       fprintf(fd, "<body onload=\"draw();\">\r\n");
720       fprintf(fd, "</body></html>\r\n");
721     }
722   }
723   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
724   PetscFunctionReturn(0);
725 }
726 #endif
727 
728 #if defined(PETSC_HAVE_YAML)
729 
730 EXTERN_C_BEGIN
731 /*
732     Toy function that returns all the arguments it is passed
733 */
734 #undef __FUNCT__
735 #define __FUNCT__ "YAML_echo"
736 PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
737 {
738   PetscErrorCode ierr;
739   PetscInt       i;
740 
741   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
742   for (i=0; i<argc; i++) {
743     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
744   }
745   *argco = argc;
746   ierr   = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
747   for (i=0; i<argc; i++) {
748     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
749   }
750   PetscFunctionReturn(0);
751 }
752 EXTERN_C_END
753 
754 EXTERN_C_BEGIN
755 #undef __FUNCT__
756 #define __FUNCT__ "YAML_AMS_Connect"
757 /*
758       Connects to the local AMS and gets only the first communication name
759 
760    Input Parameters:
761 .     none
762 
763    Output Parameter:
764 .     oarg1 - the string name of the first communicator
765 
766 */
767 PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
768 {
769   PetscErrorCode ierr;
770   char           **list = 0;
771 
772   PetscFunctionBegin;
773   ierr = AMS_Connect(0,-1,&list);
774   if (ierr) {
775     ierr = PetscInfo1(NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);
776   } else if (!list) {
777     ierr = PetscInfo(NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);
778   }
779   *argco = 1;
780   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
781   if (list) {
782     ierr = PetscStrallocpy(list[0],&(*argso)[0]);CHKERRQ(ierr);
783   } else {
784     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
785   }
786   PetscFunctionReturn(0);
787 }
788 EXTERN_C_END
789 
790 EXTERN_C_BEGIN
791 #undef __FUNCT__
792 #define __FUNCT__ "YAML_AMS_Comm_attach"
793 /*
794       Attaches to an AMS communicator
795 
796    Input Parameter:
797 .     arg1 - string name of the communicator
798 
799    Output Parameter:
800 .     oarg1 - the integer name of the communicator
801 
802 */
803 PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
804 {
805   PetscErrorCode ierr;
806   AMS_Comm       comm = -1;
807 
808   PetscFunctionBegin;
809   ierr = AMS_Comm_attach(args[0],&comm);
810   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);}
811   *argco = 1;
812   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
813   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
814   sprintf(argso[0][0],"%d",(int)comm);
815   PetscFunctionReturn(0);
816 }
817 EXTERN_C_END
818 
819 EXTERN_C_BEGIN
820 #undef __FUNCT__
821 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
822 /*
823       Gets the list of memories on an AMS Comm
824 
825    Input Parameter:
826 .     arg1 - integer name of the communicator
827 
828    Output Parameter:
829 .     oarg1 - the list of names
830 
831 */
832 PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
833 {
834   PetscErrorCode ierr;
835   char           **mem_list;
836   AMS_Comm       comm;
837   PetscInt       i,iargco = 0;
838 
839   PetscFunctionBegin;
840   sscanf(args[0],"%d",&comm);
841   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
842   if (ierr) {
843     ierr = PetscInfo1(NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
844   } else {
845     while (mem_list[iargco++]) ;
846     iargco--;
847 
848     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
849     for (i=0; i<iargco; i++) {
850       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
851     }
852   }
853   *argco = iargco;
854   PetscFunctionReturn(0);
855 }
856 EXTERN_C_END
857 
858 EXTERN_C_BEGIN
859 #undef __FUNCT__
860 #define __FUNCT__ "YAML_AMS_Memory_attach"
861 /*
862       Attaches to an AMS memory in a communicator
863 
864    Input Parameter:
865 .     arg1 - communicator
866 .     arg2 - string name of the memory
867 
868    Output Parameter:
869 .     oarg1 - the integer name of the memory
870 .     oarg2 - the integer step of the memory
871 
872 */
873 PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
874 {
875   PetscErrorCode ierr;
876   AMS_Comm       comm;
877   AMS_Memory     mem;
878   unsigned int   step;
879 
880   PetscFunctionBegin;
881   sscanf(args[0],"%d",&comm);
882   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
883   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
884   *argco = 2;
885   ierr   = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
886   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
887   sprintf(argso[0][0],"%d",(int)mem);
888   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
889   sprintf(argso[0][1],"%d",(int)step);
890   PetscFunctionReturn(0);
891 }
892 EXTERN_C_END
893 
894 EXTERN_C_BEGIN
895 #undef __FUNCT__
896 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
897 /*
898       Gets the list of fields on an AMS Memory
899 
900    Input Parameter:
901 .     arg1 - integer name of the memory
902 
903    Output Parameter:
904 .     oarg1 - the list of names
905 
906 */
907 PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
908 {
909   PetscErrorCode ierr;
910   char           **field_list;
911   AMS_Memory     mem;
912   PetscInt       i,iargco = 0;
913 
914   PetscFunctionBegin;
915   sscanf(args[0],"%d",&mem);
916   ierr = AMS_Memory_get_field_list(mem,&field_list);
917   if (ierr) {
918     ierr = PetscInfo1(NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
919   } else {
920     while (field_list[iargco++]) ;
921     iargco--;
922 
923     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
924     for (i=0; i<iargco; i++) {
925       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
926     }
927   }
928   *argco = iargco;
929   PetscFunctionReturn(0);
930 }
931 EXTERN_C_END
932 
933 const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
934 const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
935 const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
936 const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};
937 
938 EXTERN_C_BEGIN
939 #undef __FUNCT__
940 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
941 /*
942       Gets information about a field
943 
944    Input Parameter:
945 .     arg1 - memory
946 .     arg2 - string name of the field
947 
948    Output Parameter:
949 
950 */
951 PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
952 {
953   PetscErrorCode     ierr;
954   AMS_Memory         mem;
955   void               *addr;
956   int                len;
957   AMS_Data_type      dtype;
958   AMS_Memory_type    mtype;
959   AMS_Shared_type    stype;
960   AMS_Reduction_type rtype;
961   PetscInt           i;
962 
963   PetscFunctionBegin;
964   sscanf(args[0],"%d",&mem);
965   ierr = AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
966   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
967   *argco = 4 + len;
968   ierr   = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
969   ierr   = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
970   ierr   = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
971   ierr   = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
972   ierr   = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
973   for (i=0; i<len; i++) {
974     if (dtype == AMS_STRING) {
975       ierr = PetscStrallocpy(*(const char**)addr,&argso[0][4+i]);CHKERRQ(ierr);
976     } else if (dtype == AMS_DOUBLE) {
977       ierr = PetscMalloc(20*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
978       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
979     } else if (dtype == AMS_INT) {
980       ierr = PetscMalloc(10*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
981       sprintf(argso[0][4+i],"%d",*(int*)addr);
982     } else if (dtype == AMS_BOOLEAN) {
983       if (*(int*)addr) {
984         ierr = PetscStrallocpy("true",&argso[0][4+i]);CHKERRQ(ierr);
985       } else {
986         ierr = PetscStrallocpy("false",&argso[0][4+i]);CHKERRQ(ierr);
987       }
988     } else {
989       ierr = PetscStrallocpy("Not yet done",&argso[0][4+i]);CHKERRQ(ierr);
990     }
991   }
992   PetscFunctionReturn(0);
993 }
994 EXTERN_C_END
995 
996 #include "yaml.h"
997 #undef __FUNCT__
998 #define __FUNCT__ "PetscProcessYAMLRPC"
999 PetscErrorCode PetscProcessYAMLRPC(const char *request,char **result)
1000 {
1001   yaml_parser_t  parser;
1002   yaml_event_t   event;
1003   int            done  = 0;
1004   int            count = 0;
1005   size_t         len;
1006   PetscErrorCode ierr;
1007   PetscBool      method,params,id;
1008   char           *methodname,*idname,**args,**argso = 0;
1009   PetscInt       argc = 0,argco,i;
1010   PetscErrorCode (*fun)(PetscInt,char**,PetscInt*,char***);
1011 
1012   PetscFunctionBegin;
1013   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1014   yaml_parser_initialize(&parser);
1015   PetscStrlen(request,&len);
1016   yaml_parser_set_input_string(&parser, (unsigned char*)request, len);
1017 
1018   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1019   while (!done) {
1020     if (!yaml_parser_parse(&parser, &event)) {
1021       ierr = PetscInfo(NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1022       break;
1023     }
1024     done = (event.type == YAML_STREAM_END_EVENT);
1025     switch (event.type) {
1026     case YAML_STREAM_START_EVENT:
1027       ierr = PetscInfo(NULL,"Stream start\n");CHKERRQ(ierr);
1028       break;
1029     case YAML_STREAM_END_EVENT:
1030       ierr = PetscInfo(NULL,"Stream end\n");CHKERRQ(ierr);
1031       break;
1032     case YAML_DOCUMENT_START_EVENT:
1033       ierr = PetscInfo(NULL,"Document start\n");CHKERRQ(ierr);
1034       break;
1035     case YAML_DOCUMENT_END_EVENT:
1036       ierr = PetscInfo(NULL,"Document end\n");CHKERRQ(ierr);
1037       break;
1038     case YAML_MAPPING_START_EVENT:
1039       ierr = PetscInfo(NULL,"Mapping start event\n");CHKERRQ(ierr);
1040       break;
1041     case YAML_MAPPING_END_EVENT:
1042       ierr = PetscInfo(NULL,"Mapping end event \n");CHKERRQ(ierr);
1043       break;
1044     case YAML_ALIAS_EVENT:
1045       ierr = PetscInfo1(NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1046       break;
1047     case YAML_SCALAR_EVENT:
1048       ierr = PetscInfo1(NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1049       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1050       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1051       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1052       if (method) {
1053         yaml_event_delete(&event);
1054         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1055         ierr = PetscInfo1(NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1056         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1057       } else if (id) {
1058         yaml_event_delete(&event);
1059         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1060         ierr = PetscInfo1(NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1061         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1062       } else if (params) {
1063         yaml_event_delete(&event);
1064         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1065         yaml_event_delete(&event);
1066         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1067         while (event.type != YAML_SEQUENCE_END_EVENT) {
1068           ierr = PetscInfo1(NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1069           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1070           yaml_event_delete(&event);
1071           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1072         }
1073       } else { /* ignore all the other variables in the mapping */
1074         yaml_event_delete(&event);
1075         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1076       }
1077       break;
1078     case YAML_SEQUENCE_START_EVENT:
1079       ierr = PetscInfo(NULL,"Sequence start event \n");CHKERRQ(ierr);
1080       break;
1081     case YAML_SEQUENCE_END_EVENT:
1082       ierr = PetscInfo(NULL,"Sequence end event \n");CHKERRQ(ierr);
1083       break;
1084     default:
1085       /* It couldn't really happen. */
1086       break;
1087     }
1088 
1089     yaml_event_delete(&event);
1090     count++;
1091   }
1092   yaml_parser_delete(&parser);
1093 
1094   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,NULL,NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1095   if (fun) {
1096     ierr = PetscInfo1(NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1097     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1098   } else {
1099     ierr = PetscInfo1(NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1100   }
1101 
1102   for (i=0; i<argc; i++) {
1103     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1104   }
1105   ierr = PetscFree(args);CHKERRQ(ierr);
1106   ierr = PetscFree(methodname);CHKERRQ(ierr);
1107 
1108   /* convert the result back to YAML; should use YAML encoder, does not handle zero return arguments */
1109   ierr = PetscMalloc(1024,result);CHKERRQ(ierr);
1110   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1111   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1112   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1113   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1114   for (i=0; i<argco; i++) {
1115     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1116     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1117     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1118     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1119   }
1120   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1121   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1122   ierr = PetscInfo1(NULL,"YAML result of function %s\n",*result);CHKERRQ(ierr);
1123 
1124   /* free work space */
1125   ierr = PetscFree(idname);CHKERRQ(ierr);
1126   for (i=0; i<argco; i++) {
1127     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1128   }
1129   ierr = PetscFree(argso);CHKERRQ(ierr);
1130   PetscFunctionReturn(0);
1131 }
1132 #endif
1133 
1134 #undef __FUNCT__
1135 #define __FUNCT__ "PetscWebServeRequest"
1136 /*@C
1137       PetscWebServeRequest - serves a single web request
1138 
1139     Not collective
1140 
1141   Input Parameters:
1142 .   port - the port
1143 
1144     Level: developer
1145 
1146 .seealso: PetscWebServe()
1147 @*/
1148 PetscErrorCode  PetscWebServeRequest(int port)
1149 {
1150   PetscErrorCode ierr;
1151   FILE           *fd,*fdo;
1152   char           buf[4096],fullpath[PETSC_MAX_PATH_LEN],truefullpath[PETSC_MAX_PATH_LEN];
1153   char           *method, *path, *protocol,*result;
1154   const char     *type;
1155   PetscBool      flg;
1156   PetscToken     tok;
1157   PetscInt       cnt = 8;
1158 
1159   PetscFunctionBegin;
1160   fd = fdopen(port, "r+");
1161 
1162   ierr = PetscInfo(NULL,"Processing web request\n");CHKERRQ(ierr);
1163   if (!fgets(buf, sizeof(buf), fd)) {
1164     ierr = PetscInfo(NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1165     goto theend;
1166   }
1167   ierr = PetscInfo1(NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1168 
1169   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1170   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1171   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1172   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1173 
1174   if (!method || !path || !protocol) {
1175     ierr = PetscInfo(NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1176     goto theend;
1177   }
1178 
1179   ierr = PetscStrcmp(method,"GET",&flg);
1180   if (!flg) {
1181 #if defined(PETSC_HAVE_YAML)
1182     ierr = PetscStrcmp(method,"POST",&flg);
1183     /*
1184           Start to handle support for POSTs based on json-rpc
1185     */
1186     if (flg) {
1187       int    len;
1188       size_t elen;
1189       char   *fnd;
1190       while (cnt--) {
1191 
1192         if (!fgets(buf, sizeof(buf), fd)) {
1193           ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1194           goto theend;
1195         }
1196         ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1197         ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1198         if (fnd) {
1199           ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1200           if (!fnd) {
1201             ierr = PetscInfo(NULL,"POST content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1202             goto theend;
1203           }
1204         }
1205       }
1206       if (!fgets(buf, sizeof(buf), fd)) {
1207         ierr = PetscInfo(NULL,"Cannot read POST length data, giving up\n");CHKERRQ(ierr);
1208         goto theend;
1209       }
1210       ierr = PetscInfo1(NULL,"POSTED length data %s",buf);CHKERRQ(ierr);
1211       sscanf(buf,"Content-Length: %d\n",&len);
1212       ierr = PetscInfo1(NULL,"Length of POSTED data %d\n",len);CHKERRQ(ierr);
1213       if (!fgets(buf, sizeof(buf), fd)) {
1214         ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1215         goto theend;
1216       }
1217       ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1218       if (!fgets(buf, sizeof(buf), fd)) {
1219         ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1220         goto theend;
1221       }
1222       ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1223       if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1224         ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1225         goto theend;
1226       }
1227       ierr = PetscInfo1(NULL,"POSTED data %s\n",buf);CHKERRQ(ierr);
1228       fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1229       ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1230       ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1231       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1232       fprintf(fd, "%s",result);
1233       goto theend;
1234     } else {
1235 #endif
1236       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1237       ierr = PetscInfo(NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1238 #if defined(PETSC_HAVE_YAML)
1239     }
1240 #endif
1241   } else {
1242     fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1243 
1244     ierr = PetscStrcmp(path,"/favicon.ico",&flg);CHKERRQ(ierr);
1245     if (flg) {
1246       /* should have cool PETSc icon */;
1247       goto theend;
1248     }
1249     ierr = PetscStrcmp(path,"/",&flg);CHKERRQ(ierr);
1250     if (flg) {
1251       char        program[128];
1252       PetscMPIInt size;
1253       PetscViewer viewer;
1254 
1255       ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
1256       ierr = PetscGetProgramName(program,128);CHKERRQ(ierr);
1257       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
1258       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
1259       fprintf(fd, "<H4>Serving PETSc application code %s </H4>\r\n\n",program);
1260       fprintf(fd, "Number of processes %d\r\n\n",size);
1261       fprintf(fd, "<HR>\r\n");
1262       ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);CHKERRQ(ierr);
1263       ierr = PetscOptionsView(viewer);CHKERRQ(ierr);
1264       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1265       fprintf(fd, "<HR>\r\n");
1266 #if defined(PETSC_HAVE_AMS)
1267       if (PetscAMSPublishAll) {
1268         fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
1269         fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
1270       }
1271 #endif
1272       fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
1273       ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
1274       goto theend;
1275     }
1276 
1277 #if defined(PETSC_HAVE_AMS)
1278     ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
1279     if (flg) {
1280       ierr = PetscAMSDisplayList(fd);CHKERRQ(ierr);
1281       goto theend;
1282     }
1283     ierr = PetscInfo1(NULL,"Browser path %s\n",path);
1284     ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
1285     if (flg) {
1286       ierr = PetscAMSDisplayTree(fd);CHKERRQ(ierr);
1287       goto theend;
1288     }
1289 #endif
1290     ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
1291     ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
1292     ierr = PetscInfo1(NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
1293     ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
1294     fdo  = fopen(truefullpath,"r");
1295     if (fdo) {
1296       PetscInt    length,index;
1297       char        data[4096];
1298       struct stat statbuf;
1299       int         n;
1300       const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};
1301 
1302       ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
1303       type = mimes[index];
1304       if (!stat(truefullpath, &statbuf)) length = -1;
1305       else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
1306       ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
1307       while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
1308       fclose(fdo);
1309       ierr = PetscInfo2(NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
1310       goto theend;
1311     }
1312     ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
1313   }
1314 theend:
1315   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1316   fclose(fd);
1317   ierr = PetscInfo(NULL,"Finished processing request\n");CHKERRQ(ierr);
1318   PetscFunctionReturn(0);
1319 }
1320 
1321 #undef __FUNCT__
1322 #define __FUNCT__ "PetscWebServeWait"
1323 /*@C
1324       PetscWebServeWait - waits for requests on a thread
1325 
1326     Not collective
1327 
1328   Input Parameter:
1329 .   port - port to listen on
1330 
1331     Level: developer
1332 
1333 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1334 @*/
1335 void *PetscWebServeWait(int *port)
1336 {
1337   PetscErrorCode ierr;
1338   int            iport,listenport,tport = *port;
1339 
1340   ierr = PetscInfo1(NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1341   ierr = PetscFree(port);if (ierr) return 0;
1342   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1343   while (1) {
1344     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1345     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1346     close(iport);
1347   }
1348   close(listenport);
1349   return 0;
1350 }
1351 
1352 #undef __FUNCT__
1353 #define __FUNCT__ "PetscWebServe"
1354 /*@C
1355       PetscWebServe - start up the PETSc web server and respond to requests
1356 
1357     Not collective - only does something on process zero of the communicator
1358 
1359   Input Parameters:
1360 +   comm - the MPI communicator
1361 -   port - port to listen on
1362 
1363   Options Database Key:
1364 +  -server <port> - start PETSc webserver (default port is 8080)
1365 -  -ams_publish_objects
1366 
1367 
1368    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1369       If you are running PETSc on your local machine you can use http://localhost:8080
1370 
1371       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1372 
1373       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1374 
1375     Level: developer
1376 
1377 .seealso: PetscViewerSocketOpen()
1378 @*/
1379 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1380 {
1381   PetscErrorCode ierr;
1382   PetscMPIInt    rank;
1383   pthread_t      thread;
1384   int            *trueport;
1385 
1386   PetscFunctionBegin;
1387   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1388   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1389   if (rank) PetscFunctionReturn(0);
1390 
1391   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1392   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1393   *trueport = port;
1394   ierr = pthread_create(&thread, NULL, (void *(*)(void*))PetscWebServeWait, trueport);CHKERRQ(ierr);
1395   PetscFunctionReturn(0);
1396 }
1397 #endif
1398 
1399 
1400 
1401 
1402 
1403 
1404 
1405 
1406 
1407 
1408 
1409 
1410 
1411 
1412