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