xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision f05ece33fd483fcf0ae47f3ecf85fefd993a83b6)
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 /*
482       Implements a crude webserver allowing the snooping on running application codes.
483 
484      Developer Notes: Most of this code, including the webserver, perhaps, belongs properly in the AMS with perhaps a few hooks
485       for application/libraries like PETSc to interact with it.
486 */
487 #include <pthread.h>
488 #include <time.h>
489 #define PROTOCOL   "HTTP/1.1"
490 #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
491 
492 #undef __FUNCT__
493 #define __FUNCT__ "PetscWebSendHeader"
494 PetscErrorCode PetscWebSendHeader(FILE *f, int status, const char *title, const char *extra, const char *mime, int length)
495 {
496   time_t now;
497   char   timebuf[128];
498 
499   PetscFunctionBegin;
500   fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
501   fprintf(f, "Server: %s\r\n", "petscserver/1.0");
502   now = time(NULL);
503   strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
504   fprintf(f, "Date: %s\r\n", timebuf);
505   if (extra) fprintf(f, "%s\r\n", extra);
506   if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
507   if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
508   fprintf(f, "Connection: close\r\n");
509   fprintf(f, "\r\n");
510   PetscFunctionReturn(0);
511 }
512 
513 #undef __FUNCT__
514 #define __FUNCT__ "PetscWebSendFooter"
515 PetscErrorCode PetscWebSendFooter(FILE *fd)
516 {
517   PetscFunctionBegin;
518   fprintf(fd, "</BODY></HTML>\r\n");
519   PetscFunctionReturn(0);
520 }
521 
522 #undef __FUNCT__
523 #define __FUNCT__ "PetscWebSendError"
524 PetscErrorCode PetscWebSendError(FILE *f, int status, const char *title, const char *extra, const char *text)
525 {
526   PetscErrorCode ierr;
527 
528   PetscFunctionBegin;
529   ierr = PetscWebSendHeader(f, status, title, extra, "text/html", -1);CHKERRQ(ierr);
530   fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
531   fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
532   fprintf(f, "%s\r\n", text);
533   ierr = PetscWebSendFooter(f);CHKERRQ(ierr);
534   PetscFunctionReturn(0);
535 }
536 
537 #if defined(PETSC_HAVE_AMS)
538 #include <petscviewerams.h>
539 #undef __FUNCT__
540 #define __FUNCT__ "PetscAMSObjectsDisplayList"
541 /*
542     Displays all the PETSc objects published with AMS in a simple HTML list
543 
544     Does NOT use Javascript or JSON-RPC
545 */
546 static PetscErrorCode PetscAMSObjectsDisplayList(FILE *fd)
547 {
548   PetscErrorCode     ierr;
549   char               host[256],**comm_list,**mem_list,**fld_list;
550   AMS_Comm           ams;
551   PetscInt           i = 0,j;
552   AMS_Memory_type    mtype;
553   AMS_Data_type      dtype;
554   AMS_Shared_type    stype;
555   AMS_Reduction_type rtype;
556   AMS_Memory         memory;
557   int                len;
558   void               *addr;
559 
560   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
561   PetscStackCallAMS(AMS_Connect,(host, -1, &comm_list));
562   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
563   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
564   else {
565     PetscStackCallAMS(AMS_Comm_attach,(comm_list[0],&ams));
566     PetscStackCallAMS(AMS_Comm_get_memory_list,(ams,&mem_list));
567     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
568     else {
569       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
570       fprintf(fd,"<ul>\r\n");
571       while (mem_list[i]) {
572         fprintf(fd,"<li> %s</li>\r\n",mem_list[i]);
573         PetscStackCallAMS(AMS_Memory_attach,(ams,mem_list[i],&memory,NULL));
574         PetscStackCallAMS(AMS_Memory_get_field_list,(memory, &fld_list));
575         j    = 0;
576         fprintf(fd,"<ul>\r\n");
577         while (fld_list[j]) {
578           fprintf(fd,"<li> %s",fld_list[j]);
579           PetscStackCallAMS(AMS_Memory_get_field_info,(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype));
580           if (len == 1) {
581             if (dtype == AMS_INT)         fprintf(fd," %d",*(int*)addr);
582             else if (dtype == AMS_STRING) fprintf(fd," %s",*(char**)addr);
583           }
584           fprintf(fd,"</li>\r\n");
585           j++;
586         }
587         fprintf(fd,"</ul>\r\n");
588         i++;
589       }
590       fprintf(fd,"</ul>\r\n");
591     }
592   }
593   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
594   PetscStackCallAMS(AMS_Disconnect,());
595   PetscFunctionReturn(0);
596 }
597 
598 #undef __FUNCT__
599 #define __FUNCT__ "PetscAMSObjectsDisplayTree"
600 /*
601     Displays all the PETSc objects published with AMS in very crude HTML 5 graphics
602 
603     Does NOT use Javascript or JSON-RPC
604 */
605 static PetscErrorCode PetscAMSObjectsDisplayTree(FILE *fd)
606 {
607   PetscErrorCode     ierr;
608   char               host[256],**comm_list,**mem_list,**fld_list;
609   AMS_Comm           ams;
610   PetscInt           i = 0,j;
611   AMS_Memory_type    mtype;
612   AMS_Data_type      dtype;
613   AMS_Shared_type    stype;
614   AMS_Reduction_type rtype;
615   AMS_Memory         memory;
616   int                len;
617   void               *addr2,*addr3,*addr,*addr4;
618 
619   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
620   PetscStackCallAMS(AMS_Connect,(host, -1, &comm_list));
621   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
622   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
623   else {
624     PetscStackCallAMS(AMS_Comm_attach,(comm_list[0],&ams));
625     PetscStackCallAMS(AMS_Comm_get_memory_list,(ams,&mem_list));
626     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
627     else {
628       PetscInt  Nlevels,*Level,*Levelcnt,*Idbylevel,*Column,*parentid,*Id,maxId = 0,maxCol = 0,*parentId,id,cnt,Nlevelcnt = 0;
629       PetscBool *mask;
630       char      **classes,*clas,**subclasses,*sclas;
631 
632       /* get maximum number of objects */
633       while (mem_list[i]) {
634         PetscStackCallAMS(AMS_Memory_attach,(ams,mem_list[i],&memory,NULL));
635         PetscStackCallAMS(AMS_Memory_get_field_list,(memory, &fld_list));
636         PetscStackCallAMS(AMS_Memory_get_field_info,(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype));
637         Id    = (int*) addr2;
638         maxId = PetscMax(maxId,*Id);
639         i++;
640       }
641       maxId++;
642 
643       /* Gets everyone's parent ID and which nodes are masked */
644       ierr = PetscMalloc4(maxId,PetscInt,&parentid,maxId,PetscBool,&mask,maxId,char**,&classes,maxId,char**,&subclasses);CHKERRQ(ierr);
645       ierr = PetscMemzero(classes,maxId*sizeof(char*));CHKERRQ(ierr);
646       ierr = PetscMemzero(subclasses,maxId*sizeof(char*));CHKERRQ(ierr);
647       for (i=0; i<maxId; i++) mask[i] = PETSC_TRUE;
648       i = 0;
649       while (mem_list[i]) {
650         PetscStackCallAMS(AMS_Memory_attach,(ams,mem_list[i],&memory,NULL));
651         PetscStackCallAMS(AMS_Memory_get_field_list,(memory, &fld_list));
652         PetscStackCallAMS(AMS_Memory_get_field_info,(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype));
653         Id            = (int*) addr2;
654         PetscStackCallAMS(AMS_Memory_get_field_info,(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype));
655         parentId      = (int*) addr3;
656         PetscStackCallAMS(AMS_Memory_get_field_info,(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype));
657         clas          = *(char**)addr;
658         PetscStackCallAMS(AMS_Memory_get_field_info,(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype));
659         sclas         = *(char**)addr4;
660         parentid[*Id] = *parentId;
661         mask[*Id]     = PETSC_FALSE;
662 
663         ierr = PetscStrallocpy(clas,classes+*Id);CHKERRQ(ierr);
664         ierr = PetscStrallocpy(sclas,subclasses+*Id);CHKERRQ(ierr);
665         i++;
666       }
667 
668       /* if the parent is masked then relabel the parent as 0 since the true parent was deleted */
669       for (i=0; i<maxId; i++) {
670         if (!mask[i] && parentid[i] > 0 && mask[parentid[i]]) parentid[i] = 0;
671       }
672 
673       ierr = PetscProcessTree(maxId,mask,parentid,&Nlevels,&Level,&Levelcnt,&Idbylevel,&Column);CHKERRQ(ierr);
674 
675       for (i=0; i<Nlevels; i++) maxCol    = PetscMax(maxCol,Levelcnt[i]);
676       for (i=0; i<Nlevels; i++) Nlevelcnt = PetscMax(Nlevelcnt,Levelcnt[i]);
677 
678       /* print all the top-level objects */
679       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE>\r\n");
680       fprintf(fd, "<canvas width=800 height=600 id=\"tree\"></canvas>\r\n");
681       fprintf(fd, "<script type=\"text/javascript\">\r\n");
682       fprintf(fd, "  function draw() {\r\n");
683       fprintf(fd, "  var example = document.getElementById('tree');\r\n");
684       fprintf(fd, "  var context = example.getContext('2d');\r\n");
685       /* adjust font size based on how big a tree is printed */
686       if (Nlevels > 5 || Nlevelcnt > 10) fprintf(fd, "  context.font         = \"normal 12px sans-serif\";\r\n");
687       else                               fprintf(fd, "  context.font         = \"normal 24px sans-serif\";\r\n");
688       fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
689       fprintf(fd, "  context.textBaseline = \"top\";\r\n");
690       fprintf(fd, "  var xspacep = 0;\r\n");
691       fprintf(fd, "  var yspace = example.height/%d;\r\n",(Nlevels+1));
692       /* estimate the height of a string as twice the width of a character */
693       fprintf(fd, "  var wheight = context.measureText(\"K\");\r\n");
694       fprintf(fd, "  var height = 1.6*wheight.width;\r\n");
695 
696       cnt = 0;
697       for (i=0; i<Nlevels; i++) {
698         fprintf(fd, "  var xspace = example.width/%d;\r\n",Levelcnt[i]+1);
699         for (j=0; j<Levelcnt[i]; j++) {
700           id    = Idbylevel[cnt++];
701           clas  = classes[id];
702           sclas = subclasses[id];
703           fprintf(fd, "  var width = context.measureText(\"%s\");\r\n",clas);
704           fprintf(fd, "  var swidth = context.measureText(\"%s\");\r\n",sclas);
705           fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
706           fprintf(fd, "  context.fillRect((%d)*xspace-width.width/2, %d*yspace-height/2, width.width, height);\r\n",j+1,i+1);
707           fprintf(fd, "  context.fillRect((%d)*xspace-swidth.width/2, %d*yspace+height/2, swidth.width, height);\r\n",j+1,i+1);
708           fprintf(fd, "  context.fillStyle = \"rgb(0,0,0)\";\r\n");
709           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-width.width/2, %d*yspace-height/2);\r\n",clas,j+1,i+1);
710           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-swidth.width/2, %d*yspace+height/2);\r\n",sclas,j+1,i+1);
711           if (parentid[id]) {
712             fprintf(fd, "  context.moveTo(%d*xspace,%d*yspace-height/2);\r\n",j+1,i+1);
713             fprintf(fd, "  context.lineTo(%d*xspacep,%d*yspace+3*height/2);\r\n",Column[parentid[id]]+1,i);
714             fprintf(fd, "  context.stroke();\r\n");
715           }
716         }
717         fprintf(fd, "  xspacep = xspace;\r\n");
718       }
719       ierr = PetscFree(Level);CHKERRQ(ierr);
720       ierr = PetscFree(Levelcnt);CHKERRQ(ierr);
721       ierr = PetscFree(Idbylevel);CHKERRQ(ierr);
722       ierr = PetscFree(Column);CHKERRQ(ierr);
723       for (i=0; i<maxId; i++) {
724         ierr = PetscFree(classes[i]);CHKERRQ(ierr);
725         ierr = PetscFree(subclasses[i]);CHKERRQ(ierr);
726       }
727       ierr = PetscFree4(mask,parentid,classes,subclasses);CHKERRQ(ierr);
728 
729       PetscStackCallAMS(AMS_Disconnect,());
730       fprintf(fd, "}\r\n");
731       fprintf(fd, "</script>\r\n");
732       fprintf(fd, "<body onload=\"draw();\">\r\n");
733       fprintf(fd, "</body></html>\r\n");
734     }
735   }
736   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
737   PetscFunctionReturn(0);
738 }
739 #endif
740 
741 #undef __FUNCT__
742 #define __FUNCT__ "PetscWebServeRequestGet"
743 /*@C
744       PetscWebServeRequestGet - serves a single web Get request
745 
746     Not collective
747 
748   Input Parameters:
749 +   port - the network file to read and write from
750 -   path - the command from the server
751 
752     Level: developer
753 
754 .seealso: PetscWebServe()
755 @*/
756 static PetscErrorCode  PetscWebServeRequestGet(FILE *fd,const char path[])
757 {
758   PetscErrorCode ierr;
759   FILE           *fdo;
760   char           fullpath[PETSC_MAX_PATH_LEN],truefullpath[PETSC_MAX_PATH_LEN],*qmark;
761   const char     *type;
762   PetscBool      flg;
763 
764   PetscFunctionBegin;
765   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
766 
767   ierr = PetscStrcmp(path,"/favicon.ico",&flg);CHKERRQ(ierr);
768   if (flg) {
769     /* should have cool PETSc icon */;
770     PetscFunctionReturn(0);
771   }
772   ierr = PetscStrcmp(path,"/",&flg);CHKERRQ(ierr);
773   if (flg) {
774     char        program[128];
775     PetscMPIInt size;
776     PetscViewer viewer;
777 
778     ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
779     ierr = PetscGetProgramName(program,128);CHKERRQ(ierr);
780     ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
781     fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
782     fprintf(fd, "<H4>Serving PETSc application code %s </H4>\r\n\n",program);
783     fprintf(fd, "Number of processes %d\r\n\n",size);
784     fprintf(fd, "<HR>\r\n");
785     ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);CHKERRQ(ierr);
786     ierr = PetscOptionsView(viewer);CHKERRQ(ierr);
787     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
788     fprintf(fd, "<HR>\r\n");
789 #if defined(PETSC_HAVE_AMS)
790     fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
791     fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
792     fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
793 #endif
794     ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
795     PetscFunctionReturn(0);
796   }
797 
798 #if defined(PETSC_HAVE_AMS)
799   ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
800   if (flg) {
801     ierr = PetscAMSObjectsDisplayList(fd);CHKERRQ(ierr);
802     PetscFunctionReturn(0);
803   }
804   ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
805   if (flg) {
806     ierr = PetscAMSObjectsDisplayTree(fd);CHKERRQ(ierr);
807     PetscFunctionReturn(0);
808   }
809 #endif
810   ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
811   ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
812   ierr = PetscInfo1(NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
813   ierr = PetscStrstr(fullpath,"?",&qmark);CHKERRQ(ierr);
814   if (qmark) *qmark = 0;
815   ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
816   fdo  = fopen(truefullpath,"r");
817   if (fdo) {
818     PetscInt    length,index;
819     char        data[4096];
820     struct stat statbuf;
821     int         n;
822     const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};
823 
824     ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
825     type = mimes[index];
826     if (!stat(truefullpath, &statbuf)) length = -1;
827     else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
828     ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
829     while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
830     fclose(fdo);
831     ierr = PetscInfo2(NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
832     PetscFunctionReturn(0);
833   }
834   ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
835   PetscFunctionReturn(0);
836 }
837 
838 #if defined(PETSC_HAVE_YAML)
839 
840 /*
841     Toy YAML/JSON-RPC function that returns all the arguments it is passed
842 */
843 #undef __FUNCT__
844 #define __FUNCT__ "YAML_echo"
845 PETSC_UNUSED static PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
846 {
847   PetscErrorCode ierr;
848   PetscInt       i;
849 
850   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
851   for (i=0; i<argc; i++) {
852     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
853   }
854   *argco = argc;
855   ierr   = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
856   for (i=0; i<argc; i++) {
857     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
858   }
859   PetscFunctionReturn(0);
860 }
861 
862 /* -------------------------------------------------------------------------------------------
863      The following set of functions are wrapper functions for AMS functions that
864 
865     1)  convert from string arguments to appropriate AMS arguments (int, double, char*, etc)
866     2)  call the AMS function
867     3)  convert from the AMS result arguments to string arguments
868 
869     Developers Note: Rather than having PetscProcessYAMLRPC() convert the YAML/JSON representation of the params to an array of strings
870        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
871        Similarly these routines could put their result directly back into YAML/JSON rather than putting them into an array of strings
872        returning that and having PetscProcessYAMLRPC() put them into the YAML/JSON.
873 */
874 
875 #undef __FUNCT__
876 #define __FUNCT__ "YAML_AMS_Utility_ArrayToString"
877 static PetscErrorCode YAML_AMS_Utility_ArrayToString(PetscInt n,void *addr,AMS_Data_type dtype,char **result)
878 {
879   PetscErrorCode ierr;
880 
881   PetscFunctionBegin;
882   if (n == 1) {
883     if (dtype == AMS_STRING) {
884       ierr = PetscStrallocpy(*(const char**)addr,result);CHKERRQ(ierr);
885     } else if (dtype == AMS_DOUBLE) {
886       ierr = PetscMalloc(20*sizeof(char),result);CHKERRQ(ierr);
887       sprintf(*result,"%18.16e",*(double*)addr);
888     } else if (dtype == AMS_INT) {
889       ierr = PetscMalloc(10*sizeof(char),result);CHKERRQ(ierr);
890       sprintf(*result,"%d",*(int*)addr);
891     } else if (dtype == AMS_BOOLEAN) {
892       if (*(PetscBool*)addr) {
893         ierr = PetscStrallocpy("true",result);CHKERRQ(ierr);
894       } else {
895         ierr = PetscStrallocpy("false",result);CHKERRQ(ierr);
896       }
897     } else {
898       ierr = PetscStrallocpy("Not yet done",result);CHKERRQ(ierr);
899     }
900   } else {
901     PetscInt i;
902     size_t   len = 0,lent;
903     char     buff[25],**array = (char**)addr;
904 
905     if (dtype == AMS_STRING) {
906       for (i=0; i<n; i++) {
907         ierr = PetscStrlen(array[i],&lent);CHKERRQ(ierr);
908         len += lent + 3;
909       }
910       ierr = PetscMalloc(len*sizeof(char),result);CHKERRQ(ierr);
911       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
912       for (i=0; i<n-1; i++) {
913         ierr = PetscStrcat(*result,array[i]);CHKERRQ(ierr);
914         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
915       }
916       ierr = PetscStrcat(*result,array[n-1]);CHKERRQ(ierr);
917       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
918     } else if (dtype == AMS_DOUBLE) {
919       ierr = PetscMalloc(30*n*sizeof(char),result);CHKERRQ(ierr);
920       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
921       for (i=0; i<n-1; i++) {
922         sprintf(buff,"%18.16e",*(double*)addr);
923         ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
924         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
925         addr = (void *) ((char *)addr + sizeof(PetscReal));
926       }
927       sprintf(buff,"%18.16e",*(double*)addr);
928       ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
929       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
930     } else if (dtype == AMS_INT) {
931       ierr = PetscMalloc(13*n*sizeof(char),result);CHKERRQ(ierr);
932       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
933       for (i=0; i<n-1; i++) {
934         sprintf(buff,"%d",*(int*)addr);
935         ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
936         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
937         addr = (void *) ((char *)addr + sizeof(PetscInt));
938       }
939       sprintf(buff,"%d",*(int*)addr);
940       ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
941       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
942     } else if (dtype == AMS_BOOLEAN) {
943       ierr = PetscMalloc(7*n*sizeof(char),result);CHKERRQ(ierr);
944       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
945       for (i=0; i<n-1; i++) {
946       ierr = PetscStrcat(*result,*(PetscBool*)addr ? "true" : "false");CHKERRQ(ierr);
947         addr = (void *) ((char *)addr + sizeof(int));
948       }
949       ierr = PetscStrcat(*result,*(PetscBool*)addr ? "true" : "false");CHKERRQ(ierr);
950       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
951     } else {
952       ierr = PetscStrallocpy("Not yet done",result);CHKERRQ(ierr);
953     }
954   }
955   PetscFunctionReturn(0);
956 }
957 
958 #undef __FUNCT__
959 #define __FUNCT__ "YAML_AMS_Connect"
960 /*
961       Connects to the local AMS and gets only the first communication name
962 
963    Input Parameters:
964 .     none
965 
966    Output Parameter:
967 .     oarg1 - the string name of the first communicator
968 
969 */
970 PETSC_EXTERN PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
971 {
972   PetscErrorCode ierr;
973   char           **list = 0;
974   PetscInt       n = 0;
975 
976   PetscFunctionBegin;
977   ierr = AMS_Connect(0,-1,&list);
978   if (ierr) {
979     ierr = PetscInfo1(NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);
980   } else if (!list) {
981     ierr = PetscInfo(NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);
982   }
983   *argco = 1;
984   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
985   if (list) {
986     while (list[n]) n++;
987     ierr = YAML_AMS_Utility_ArrayToString(n,list,AMS_STRING,&(*argso)[0]);CHKERRQ(ierr);
988   } else {
989     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
990   }
991   PetscFunctionReturn(0);
992 }
993 
994 #undef __FUNCT__
995 #define __FUNCT__ "YAML_AMS_Comm_attach"
996 /*
997       Attaches to an AMS communicator
998 
999    Input Parameter:
1000 .     arg1 - string name of the communicator
1001 
1002    Output Parameter:
1003 .     oarg1 - the integer name of the communicator
1004 
1005 */
1006 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1007 {
1008   PetscErrorCode ierr;
1009   AMS_Comm       comm = -1;
1010 
1011   PetscFunctionBegin;
1012   ierr = AMS_Comm_attach(args[0],&comm);
1013   if (ierr) {
1014     ierr = PetscInfo1(NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);
1015   }
1016   *argco = 1;
1017   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
1018   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
1019   sprintf(argso[0][0],"%d",(int)comm);
1020   PetscFunctionReturn(0);
1021 }
1022 
1023 #undef __FUNCT__
1024 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
1025 /*
1026       Gets the list of memories on an AMS Comm
1027 
1028    Input Parameter:
1029 .     arg1 - integer name of the communicator
1030 
1031    Output Parameter:
1032 .     oarg1 - the list of names
1033 
1034 */
1035 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1036 {
1037   PetscErrorCode ierr;
1038   char           **mem_list;
1039   AMS_Comm       comm;
1040   PetscInt       i,iargco = 0;
1041 
1042   PetscFunctionBegin;
1043   sscanf(args[0],"%d",&comm);
1044   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
1045   if (ierr) {
1046     ierr = PetscInfo1(NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
1047   } else {
1048     while (mem_list[iargco++]) ;
1049     iargco--;
1050 
1051     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
1052     for (i=0; i<iargco; i++) {
1053       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
1054     }
1055   }
1056   *argco = iargco;
1057   PetscFunctionReturn(0);
1058 }
1059 
1060 #undef __FUNCT__
1061 #define __FUNCT__ "YAML_AMS_Memory_attach"
1062 /*
1063       Attaches to an AMS memory in a communicator
1064 
1065    Input Parameter:
1066 .     arg1 - communicator
1067 .     arg2 - string name of the memory
1068 
1069    Output Parameter:
1070 .     oarg1 - the integer name of the memory
1071 .     oarg2 - the integer step of the memory
1072 
1073 */
1074 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1075 {
1076   PetscErrorCode ierr;
1077   AMS_Comm       comm;
1078   AMS_Memory     mem;
1079   unsigned int   step;
1080 
1081   PetscFunctionBegin;
1082   sscanf(args[0],"%d",&comm);
1083   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
1084   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
1085   *argco = 2;
1086   ierr   = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
1087   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
1088   sprintf(argso[0][0],"%d",(int)mem);
1089   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
1090   sprintf(argso[0][1],"%d",(int)step);
1091   PetscFunctionReturn(0);
1092 }
1093 
1094 #undef __FUNCT__
1095 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
1096 /*
1097       Gets the list of fields on an AMS Memory
1098 
1099    Input Parameter:
1100 .     arg1 - integer name of the memory
1101 
1102    Output Parameter:
1103 .     oarg1 - the list of names
1104 
1105 */
1106 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1107 {
1108   PetscErrorCode ierr;
1109   char           **field_list;
1110   AMS_Memory     mem;
1111   PetscInt       i,iargco = 0;
1112 
1113   PetscFunctionBegin;
1114   sscanf(args[0],"%d",&mem);
1115   ierr = AMS_Memory_get_field_list(mem,&field_list);
1116   if (ierr) {
1117     ierr = PetscInfo1(NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
1118   } else {
1119     while (field_list[iargco++]) ;
1120     iargco--;
1121 
1122     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
1123     for (i=0; i<iargco; i++) {
1124       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
1125     }
1126   }
1127   *argco = iargco;
1128   PetscFunctionReturn(0);
1129 }
1130 
1131 const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
1132 const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
1133 const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
1134 const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};
1135 
1136 
1137 #undef __FUNCT__
1138 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
1139 /*
1140       Gets information about a field
1141 
1142    Input Parameter:
1143 .     arg1 - memory
1144 .     arg2 - string name of the field
1145 
1146    Output Parameter:
1147 
1148 */
1149 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1150 {
1151   PetscErrorCode     ierr;
1152   AMS_Memory         mem;
1153   char               *addr;
1154   int                len;
1155   AMS_Data_type      dtype;
1156   AMS_Memory_type    mtype;
1157   AMS_Shared_type    stype;
1158   AMS_Reduction_type rtype;
1159 
1160   PetscFunctionBegin;
1161   sscanf(args[0],"%d",&mem);
1162   ierr = AMS_Memory_get_field_info(mem,args[1],(void**)&addr,&len,&dtype,&mtype,&stype,&rtype);
1163   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
1164   *argco = 5;
1165   ierr   = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
1166   ierr   = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
1167   ierr   = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
1168   ierr   = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
1169   ierr   = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
1170   ierr   = YAML_AMS_Utility_ArrayToString(len,addr,dtype,&argso[0][4]);CHKERRQ(ierr);
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 #include "yaml.h"
1175 #undef __FUNCT__
1176 #define __FUNCT__ "PetscProcessYAMLRPC"
1177 /*
1178      1) Parses a YAML/JSON-RPC function call generating a function name for an AMS wrapper function and the arguments to the function
1179      2) loads the function with dlsym(),
1180      3) calls the wrapper function with the arguments
1181      4) converts the result arguments back to YAML/JSON.
1182 */
1183 static PetscErrorCode PetscProcessYAMLRPC(const char *request,char **result)
1184 {
1185   yaml_parser_t  parser;
1186   yaml_event_t   event;
1187   int            done  = 0;
1188   int            count = 0;
1189   size_t         len;
1190   PetscErrorCode ierr;
1191   PetscBool      method,params,id;
1192   char           *methodname,*idname,**args,**argso = 0;
1193   PetscInt       argc = 0,argco,i;
1194   PetscErrorCode (*fun)(PetscInt,char**,PetscInt*,char***);
1195 
1196   PetscFunctionBegin;
1197   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1198   yaml_parser_initialize(&parser);
1199   PetscStrlen(request,&len);
1200   yaml_parser_set_input_string(&parser, (unsigned char*)request, len);
1201 
1202   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1203   while (!done) {
1204     if (!yaml_parser_parse(&parser, &event)) {
1205       ierr = PetscInfo(NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1206       break;
1207     }
1208     done = (event.type == YAML_STREAM_END_EVENT);
1209     switch (event.type) {
1210     case YAML_STREAM_START_EVENT:
1211       ierr = PetscInfo(NULL,"Stream start\n");CHKERRQ(ierr);
1212       break;
1213     case YAML_STREAM_END_EVENT:
1214       ierr = PetscInfo(NULL,"Stream end\n");CHKERRQ(ierr);
1215       break;
1216     case YAML_DOCUMENT_START_EVENT:
1217       ierr = PetscInfo(NULL,"Document start\n");CHKERRQ(ierr);
1218       break;
1219     case YAML_DOCUMENT_END_EVENT:
1220       ierr = PetscInfo(NULL,"Document end\n");CHKERRQ(ierr);
1221       break;
1222     case YAML_MAPPING_START_EVENT:
1223       ierr = PetscInfo(NULL,"Mapping start event\n");CHKERRQ(ierr);
1224       break;
1225     case YAML_MAPPING_END_EVENT:
1226       ierr = PetscInfo(NULL,"Mapping end event \n");CHKERRQ(ierr);
1227       break;
1228     case YAML_ALIAS_EVENT:
1229       ierr = PetscInfo1(NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1230       break;
1231     case YAML_SCALAR_EVENT:
1232       ierr = PetscInfo1(NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1233       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1234       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1235       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1236       if (method) {
1237         yaml_event_delete(&event);
1238         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1239         ierr = PetscInfo1(NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1240         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1241       } else if (id) {
1242         yaml_event_delete(&event);
1243         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1244         ierr = PetscInfo1(NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1245         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1246       } else if (params) {
1247         yaml_event_delete(&event);
1248         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1249         yaml_event_delete(&event);
1250         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1251         while (event.type != YAML_SEQUENCE_END_EVENT) {
1252           ierr = PetscInfo1(NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1253           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1254           yaml_event_delete(&event);
1255           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1256         }
1257       } else { /* ignore all the other variables in the mapping */
1258         yaml_event_delete(&event);
1259         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1260       }
1261       break;
1262     case YAML_SEQUENCE_START_EVENT:
1263       ierr = PetscInfo(NULL,"Sequence start event \n");CHKERRQ(ierr);
1264       break;
1265     case YAML_SEQUENCE_END_EVENT:
1266       ierr = PetscInfo(NULL,"Sequence end event \n");CHKERRQ(ierr);
1267       break;
1268     default:
1269       /* It couldn't really happen. */
1270       break;
1271     }
1272 
1273     yaml_event_delete(&event);
1274     count++;
1275   }
1276   yaml_parser_delete(&parser);
1277 
1278   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,NULL,NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1279   if (fun) {
1280     ierr = PetscInfo1(NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1281     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1282   } else {
1283     ierr = PetscInfo1(NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1284   }
1285 
1286   for (i=0; i<argc; i++) {
1287     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1288   }
1289   ierr = PetscFree(args);CHKERRQ(ierr);
1290   ierr = PetscFree(methodname);CHKERRQ(ierr);
1291 
1292   /* convert the result back to YAML/JSON; should use YAML/JSON encoder, does not handle zero return arguments */
1293   ierr = PetscMalloc(16000,result);CHKERRQ(ierr);
1294   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1295   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1296   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1297   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1298   for (i=0; i<argco; i++) {
1299     if (argso[i][0] != '[') {
1300       ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1301     }
1302     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1303     if (argso[i][0] != '[') {
1304       ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1305     }
1306     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1307   }
1308   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1309   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1310   ierr = PetscInfo1(NULL,"YAML/JSON result of function %s\n",*result);CHKERRQ(ierr);
1311 
1312   /* free work space */
1313   ierr = PetscFree(idname);CHKERRQ(ierr);
1314   for (i=0; i<argco; i++) {
1315     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1316   }
1317   ierr = PetscFree(argso);CHKERRQ(ierr);
1318   PetscFunctionReturn(0);
1319 }
1320 
1321 #undef __FUNCT__
1322 #define __FUNCT__ "PetscWebServeRequestPostAMSJSONRPC"
1323 /*@C
1324       PetscWebServeRequestPostAMSJSONRPC - serves a single web POST request based on JSON-RPC
1325 
1326        This function allows a Javascript program (running in the browser) to make an AMS function
1327        call via JSON-RPC
1328 
1329        The currently available Javascript programs are in ${PETSC_DIR}/include/web
1330 
1331     Not collective
1332 
1333   Input Parameters:
1334 .   fd - the network file to read and write from
1335 -   path - the command from the server
1336 
1337     Level: developer
1338 
1339 .seealso: PetscWebServe()
1340 @*/
1341 static PetscErrorCode  PetscWebServeRequestPostAMSJSONRPC(FILE *fd,const char path[])
1342 {
1343   PetscErrorCode ierr;
1344   char           buf[16000];
1345   char           *result;
1346   int            len = -1;
1347   size_t         elen;
1348   char           *fnd;
1349 
1350   PetscFunctionBegin;
1351   while (PETSC_TRUE) {
1352     if (!fgets(buf, sizeof(buf), fd)) {
1353       ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1354       PetscFunctionReturn(0);
1355     }
1356     ierr = PetscInfo1(NULL,"POSTED header: %s",buf);CHKERRQ(ierr);
1357     ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1358     if (fnd) {
1359       ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1360       if (!fnd) {
1361         ierr = PetscInfo(NULL,"POSTED content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1362         PetscFunctionReturn(0);
1363       }
1364     }
1365     ierr = PetscStrstr(buf,"Content-Length:",&fnd);CHKERRQ(ierr);
1366     if (fnd) {
1367       sscanf(buf,"Content-Length: %d\n",&len);
1368       ierr = PetscInfo1(NULL,"POSTED Content-Length: %d\n",len);CHKERRQ(ierr);
1369     }
1370     if (buf[0] == '\r') break;
1371   }
1372   if (len == -1) {
1373     ierr = PetscInfo(NULL,"Did not find POST Content-Length in header, giving up\n");CHKERRQ(ierr);
1374   }
1375 
1376   if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1377     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1378     PetscFunctionReturn(0);
1379   }
1380   ierr = PetscInfo1(NULL,"POSTED JSON/RPC request: %s\n",buf);CHKERRQ(ierr);
1381   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1382   ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1383   ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1384   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1385   fprintf(fd, "%s",result);
1386   ierr = PetscInfo(NULL,"Completed AMS JSON-RPC function call\n");CHKERRQ(ierr);
1387   PetscFunctionReturn(0);
1388 }
1389 #endif
1390 
1391 #undef __FUNCT__
1392 #define __FUNCT__ "PetscWebServeRequest"
1393 /*@C
1394       PetscWebServeRequest - serves a single web request
1395 
1396     Not collective
1397 
1398   Input Parameters:
1399 .   port - the port
1400 
1401     Level: developer
1402 
1403 .seealso: PetscWebServe()
1404 @*/
1405 static PetscErrorCode  PetscWebServeRequest(int port)
1406 {
1407   PetscErrorCode ierr;
1408   FILE           *fd;
1409   char           buf[4096];
1410   char           *method, *path, *protocol;
1411   PetscBool      flg;
1412   PetscToken     tok;
1413 
1414   PetscFunctionBegin;
1415   fd = fdopen(port, "r+");
1416 
1417   ierr = PetscInfo(NULL,"Processing web request\n");CHKERRQ(ierr);
1418   if (!fgets(buf, sizeof(buf), fd)) {
1419     ierr = PetscInfo(NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1420     goto theend;
1421   }
1422   ierr = PetscInfo1(NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1423 
1424   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1425   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1426   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1427   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1428 
1429   if (!method || !path || !protocol) {
1430     ierr = PetscInfo(NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1431     goto theend;
1432   }
1433 
1434   ierr = PetscStrcmp(method,"GET",&flg);
1435   if (flg) {
1436       ierr = PetscWebServeRequestGet(fd,path);CHKERRQ(ierr);
1437   } else {
1438 #if defined(PETSC_HAVE_YAML)
1439     ierr = PetscStrcmp(method,"POST",&flg);
1440     if (flg) {
1441       ierr = PetscWebServeRequestPostAMSJSONRPC(fd,path);CHKERRQ(ierr);
1442     } else {
1443 #else
1444     {
1445 #endif
1446       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1447       ierr = PetscInfo(NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1448     }
1449   }
1450 theend:
1451   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1452   fclose(fd);
1453   ierr = PetscInfo1(NULL,"Finished processing request %s\n",method);CHKERRQ(ierr);
1454   PetscFunctionReturn(0);
1455 }
1456 
1457 #undef __FUNCT__
1458 #define __FUNCT__ "PetscWebServeWait"
1459 /*@C
1460       PetscWebServeWait - waits for requests on a thread
1461 
1462     Not collective
1463 
1464   Input Parameter:
1465 .   port - port to listen on
1466 
1467     Level: developer
1468 
1469 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1470 @*/
1471 void *PetscWebServeWait(int *port)
1472 {
1473   PetscErrorCode ierr;
1474   int            iport,listenport,tport = *port;
1475 
1476   ierr = PetscInfo1(NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1477   ierr = PetscFree(port);if (ierr) return 0;
1478   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1479   while (1) {
1480     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1481     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1482     close(iport);
1483   }
1484   close(listenport);
1485   return 0;
1486 }
1487 
1488 #undef __FUNCT__
1489 #define __FUNCT__ "PetscWebServe"
1490 /*@C
1491       PetscWebServe - start up the PETSc web server and respond to requests
1492 
1493     Not collective - only does something on process zero of the communicator
1494 
1495   Input Parameters:
1496 +   comm - the MPI communicator
1497 -   port - port to listen on
1498 
1499   Options Database Key:
1500 +  -server <port> - start PETSc webserver (default port is 8080)
1501 -  -xxx_view ams - publish object xxx to be accessible in the server
1502 
1503 
1504    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1505       If you are running PETSc on your local machine you can use http://localhost:8080
1506 
1507       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1508 
1509       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1510 
1511     Level: intermediate
1512 
1513 .seealso: PetscViewerSocketOpen()
1514 @*/
1515 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1516 {
1517   PetscErrorCode ierr;
1518   PetscMPIInt    rank;
1519   pthread_t      thread;
1520   int            *trueport;
1521 
1522   PetscFunctionBegin;
1523   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1524   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1525   if (rank) PetscFunctionReturn(0);
1526 
1527   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1528   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1529   *trueport = port;
1530   ierr = pthread_create(&thread, NULL, (void *(*)(void*))PetscWebServeWait, trueport);CHKERRQ(ierr);
1531   PetscFunctionReturn(0);
1532 }
1533 #endif
1534 
1535 
1536 
1537 
1538 
1539 
1540 
1541 
1542 
1543 
1544 
1545 
1546 
1547 
1548