xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision ec7429eab6e231810adac0f010b269bd5bae4496)
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   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
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     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
566     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
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         ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
574         ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
575         j    = 0;
576         fprintf(fd,"<ul>\r\n");
577         while (fld_list[j]) {
578           fprintf(fd,"<li> %s",fld_list[j]);
579           ierr = AMS_Memory_get_field_info(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
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   ierr = AMS_Disconnect();CHKERRQ(ierr);
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   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
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     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
625     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
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         ierr  = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
635         ierr  = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
636         ierr  = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
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         ierr          = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
651         ierr          = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
652         ierr          = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
653         Id            = (int*) addr2;
654         ierr          = AMS_Memory_get_field_info(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
655         parentId      = (int*) addr3;
656         ierr          = AMS_Memory_get_field_info(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
657         clas          = *(char**)addr;
658         ierr          = AMS_Memory_get_field_info(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
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       ierr = AMS_Disconnect();CHKERRQ(ierr);
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     if (PetscAMSPublishAll) {
791       fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
792       fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
793     }
794     fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
795 #endif
796     ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
797     PetscFunctionReturn(0);
798   }
799 
800 #if defined(PETSC_HAVE_AMS)
801   ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
802   if (flg) {
803     ierr = PetscAMSObjectsDisplayList(fd);CHKERRQ(ierr);
804     PetscFunctionReturn(0);
805   }
806   ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
807   if (flg) {
808     ierr = PetscAMSObjectsDisplayTree(fd);CHKERRQ(ierr);
809     PetscFunctionReturn(0);
810   }
811 #endif
812   ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
813   ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
814   ierr = PetscInfo1(NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
815   ierr = PetscStrstr(fullpath,"?",&qmark);CHKERRQ(ierr);
816   if (qmark) *qmark = 0;
817   ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
818   fdo  = fopen(truefullpath,"r");
819   if (fdo) {
820     PetscInt    length,index;
821     char        data[4096];
822     struct stat statbuf;
823     int         n;
824     const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};
825 
826     ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
827     type = mimes[index];
828     if (!stat(truefullpath, &statbuf)) length = -1;
829     else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
830     ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
831     while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
832     fclose(fdo);
833     ierr = PetscInfo2(NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
834     PetscFunctionReturn(0);
835   }
836   ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
837   PetscFunctionReturn(0);
838 }
839 
840 #if defined(PETSC_HAVE_YAML)
841 
842 /*
843     Toy YAML/JSON-RPC function that returns all the arguments it is passed
844 */
845 #undef __FUNCT__
846 #define __FUNCT__ "YAML_echo"
847 PETSC_UNUSED static PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
848 {
849   PetscErrorCode ierr;
850   PetscInt       i;
851 
852   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
853   for (i=0; i<argc; i++) {
854     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
855   }
856   *argco = argc;
857   ierr   = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
858   for (i=0; i<argc; i++) {
859     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
860   }
861   PetscFunctionReturn(0);
862 }
863 
864 /* -------------------------------------------------------------------------------------------
865      The following set of functions are wrapper functions for AMS functions that
866 
867     1)  convert from string arguments to appropriate AMS arguments (int, double, char*, etc)
868     2)  call the AMS function
869     3)  convert from the AMS result arguments to string arguments
870 
871     Developers Note: Rather than having PetscProcessYAMLRPC() convert the YAML/JSON representation of the params to an array of strings
872        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
873        Similarly these routines could put their result directly back into YAML/JSON rather than putting them into an array of strings
874        returning that and having PetscProcessYAMLRPC() put them into the YAML/JSON.
875 */
876 
877 #undef __FUNCT__
878 #define __FUNCT__ "YAML_AMS_Connect"
879 /*
880       Connects to the local AMS and gets only the first communication name
881 
882    Input Parameters:
883 .     none
884 
885    Output Parameter:
886 .     oarg1 - the string name of the first communicator
887 
888 */
889 PETSC_EXTERN PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
890 {
891   PetscErrorCode ierr;
892   char           **list = 0;
893 
894   PetscFunctionBegin;
895   ierr = AMS_Connect(0,-1,&list);
896   if (ierr) {
897     ierr = PetscInfo1(NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);
898   } else if (!list) {
899     ierr = PetscInfo(NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);
900   }
901   *argco = 1;
902   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
903   if (list) {
904     ierr = PetscStrallocpy(list[0],&(*argso)[0]);CHKERRQ(ierr);
905   } else {
906     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
907   }
908   PetscFunctionReturn(0);
909 }
910 
911 #undef __FUNCT__
912 #define __FUNCT__ "YAML_AMS_Comm_attach"
913 /*
914       Attaches to an AMS communicator
915 
916    Input Parameter:
917 .     arg1 - string name of the communicator
918 
919    Output Parameter:
920 .     oarg1 - the integer name of the communicator
921 
922 */
923 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
924 {
925   PetscErrorCode ierr;
926   AMS_Comm       comm = -1;
927 
928   PetscFunctionBegin;
929   ierr = AMS_Comm_attach(args[0],&comm);
930   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);}
931   *argco = 1;
932   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
933   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
934   sprintf(argso[0][0],"%d",(int)comm);
935   PetscFunctionReturn(0);
936 }
937 
938 #undef __FUNCT__
939 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
940 /*
941       Gets the list of memories on an AMS Comm
942 
943    Input Parameter:
944 .     arg1 - integer name of the communicator
945 
946    Output Parameter:
947 .     oarg1 - the list of names
948 
949 */
950 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
951 {
952   PetscErrorCode ierr;
953   char           **mem_list;
954   AMS_Comm       comm;
955   PetscInt       i,iargco = 0;
956 
957   PetscFunctionBegin;
958   sscanf(args[0],"%d",&comm);
959   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
960   if (ierr) {
961     ierr = PetscInfo1(NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
962   } else {
963     while (mem_list[iargco++]) ;
964     iargco--;
965 
966     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
967     for (i=0; i<iargco; i++) {
968       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
969     }
970   }
971   *argco = iargco;
972   PetscFunctionReturn(0);
973 }
974 
975 #undef __FUNCT__
976 #define __FUNCT__ "YAML_AMS_Memory_attach"
977 /*
978       Attaches to an AMS memory in a communicator
979 
980    Input Parameter:
981 .     arg1 - communicator
982 .     arg2 - string name of the memory
983 
984    Output Parameter:
985 .     oarg1 - the integer name of the memory
986 .     oarg2 - the integer step of the memory
987 
988 */
989 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
990 {
991   PetscErrorCode ierr;
992   AMS_Comm       comm;
993   AMS_Memory     mem;
994   unsigned int   step;
995 
996   PetscFunctionBegin;
997   sscanf(args[0],"%d",&comm);
998   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
999   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
1000   *argco = 2;
1001   ierr   = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
1002   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
1003   sprintf(argso[0][0],"%d",(int)mem);
1004   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
1005   sprintf(argso[0][1],"%d",(int)step);
1006   PetscFunctionReturn(0);
1007 }
1008 
1009 #undef __FUNCT__
1010 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
1011 /*
1012       Gets the list of fields on an AMS Memory
1013 
1014    Input Parameter:
1015 .     arg1 - integer name of the memory
1016 
1017    Output Parameter:
1018 .     oarg1 - the list of names
1019 
1020 */
1021 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1022 {
1023   PetscErrorCode ierr;
1024   char           **field_list;
1025   AMS_Memory     mem;
1026   PetscInt       i,iargco = 0;
1027 
1028   PetscFunctionBegin;
1029   sscanf(args[0],"%d",&mem);
1030   ierr = AMS_Memory_get_field_list(mem,&field_list);
1031   if (ierr) {
1032     ierr = PetscInfo1(NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
1033   } else {
1034     while (field_list[iargco++]) ;
1035     iargco--;
1036 
1037     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
1038     for (i=0; i<iargco; i++) {
1039       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
1040     }
1041   }
1042   *argco = iargco;
1043   PetscFunctionReturn(0);
1044 }
1045 
1046 const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
1047 const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
1048 const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
1049 const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};
1050 
1051 #undef __FUNCT__
1052 #define __FUNCT__ "YAML_AMS_Utility_ArrayToString"
1053 static PetscErrorCode YAML_AMS_Utility_ArrayToString(PetscInt n,void *addr,AMS_Data_type dtype,char **result)
1054 {
1055   PetscErrorCode ierr;
1056 
1057   PetscFunctionBegin;
1058   if (n == 1) {
1059     if (dtype == AMS_STRING) {
1060       ierr = PetscStrallocpy(*(const char**)addr,result);CHKERRQ(ierr);
1061     } else if (dtype == AMS_DOUBLE) {
1062       ierr = PetscMalloc(20*sizeof(char),result);CHKERRQ(ierr);
1063       sprintf(*result,"%18.16e",*(double*)addr);
1064     } else if (dtype == AMS_INT) {
1065       ierr = PetscMalloc(10*sizeof(char),result);CHKERRQ(ierr);
1066       sprintf(*result,"%d",*(int*)addr);
1067     } else if (dtype == AMS_BOOLEAN) {
1068       if (*(PetscBool*)addr) {
1069         ierr = PetscStrallocpy("true",result);CHKERRQ(ierr);
1070       } else {
1071         ierr = PetscStrallocpy("false",result);CHKERRQ(ierr);
1072       }
1073     } else {
1074       ierr = PetscStrallocpy("Not yet done",result);CHKERRQ(ierr);
1075     }
1076   } else {
1077     PetscInt i;
1078     size_t   len = 0,lent;
1079     char     buff[25],**array = (char**)addr;
1080 
1081     if (dtype == AMS_STRING) {
1082       for (i=0; i<n; i++) {
1083         ierr = PetscStrlen(array[i],&lent);CHKERRQ(ierr);
1084         len += lent + 3;
1085       }
1086       ierr = PetscMalloc(len*sizeof(char),result);CHKERRQ(ierr);
1087       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
1088       for (i=0; i<n-1; i++) {
1089         ierr = PetscStrcat(*result,array[i]);CHKERRQ(ierr);
1090         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
1091       }
1092       ierr = PetscStrcat(*result,array[n-1]);CHKERRQ(ierr);
1093       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
1094     } else if (dtype == AMS_DOUBLE) {
1095       ierr = PetscMalloc(30*n*sizeof(char),result);CHKERRQ(ierr);
1096       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
1097       for (i=0; i<n-1; i++) {
1098         sprintf(buff,"%18.16e",*(double*)addr);
1099         ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
1100         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
1101         addr = (void *) ((char *)addr + sizeof(PetscReal));
1102       }
1103       sprintf(buff,"%18.16e",*(double*)addr);
1104       ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
1105       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
1106     } else if (dtype == AMS_INT) {
1107       ierr = PetscMalloc(13*n*sizeof(char),result);CHKERRQ(ierr);
1108       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
1109       for (i=0; i<n-1; i++) {
1110         sprintf(buff,"%d",*(int*)addr);
1111         ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
1112         ierr = PetscStrcat(*result,"\",\"");CHKERRQ(ierr);
1113         addr = (void *) ((char *)addr + sizeof(PetscInt));
1114       }
1115       sprintf(buff,"%d",*(int*)addr);
1116       ierr = PetscStrcat(*result,buff);CHKERRQ(ierr);
1117       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
1118     } else if (dtype == AMS_BOOLEAN) {
1119       ierr = PetscMalloc(7*n*sizeof(char),result);CHKERRQ(ierr);
1120       ierr = PetscStrcpy(*result,"[\"");CHKERRQ(ierr);
1121       for (i=0; i<n-1; i++) {
1122       ierr = PetscStrcat(*result,*(PetscBool*)addr ? "true" : "false");CHKERRQ(ierr);
1123         addr = (void *) ((char *)addr + sizeof(int));
1124       }
1125       ierr = PetscStrcat(*result,*(PetscBool*)addr ? "true" : "false");CHKERRQ(ierr);
1126       ierr = PetscStrcat(*result,"\"]");CHKERRQ(ierr);
1127     } else {
1128       ierr = PetscStrallocpy("Not yet done",result);CHKERRQ(ierr);
1129     }
1130   }
1131   PetscFunctionReturn(0);
1132 }
1133 
1134 #undef __FUNCT__
1135 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
1136 /*
1137       Gets information about a field
1138 
1139    Input Parameter:
1140 .     arg1 - memory
1141 .     arg2 - string name of the field
1142 
1143    Output Parameter:
1144 
1145 */
1146 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1147 {
1148   PetscErrorCode     ierr;
1149   AMS_Memory         mem;
1150   char               *addr;
1151   int                len;
1152   AMS_Data_type      dtype;
1153   AMS_Memory_type    mtype;
1154   AMS_Shared_type    stype;
1155   AMS_Reduction_type rtype;
1156 
1157   PetscFunctionBegin;
1158   sscanf(args[0],"%d",&mem);
1159   ierr = AMS_Memory_get_field_info(mem,args[1],(void*)&addr,&len,&dtype,&mtype,&stype,&rtype);
1160   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
1161   *argco = 5;
1162   ierr   = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
1163   ierr   = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
1164   ierr   = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
1165   ierr   = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
1166   ierr   = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
1167   ierr   = YAML_AMS_Utility_ArrayToString(len,addr,dtype,&argso[0][4]);CHKERRQ(ierr);
1168   PetscFunctionReturn(0);
1169 }
1170 
1171 #include "yaml.h"
1172 #undef __FUNCT__
1173 #define __FUNCT__ "PetscProcessYAMLRPC"
1174 /*
1175      1) Parses a YAML/JSON-RPC function call generating a function name for an AMS wrapper function and the arguments to the function
1176      2) loads the function with dlsym(),
1177      3) calls the wrapper function with the arguments
1178      4) converts the result arguments back to YAML/JSON.
1179 */
1180 static PetscErrorCode PetscProcessYAMLRPC(const char *request,char **result)
1181 {
1182   yaml_parser_t  parser;
1183   yaml_event_t   event;
1184   int            done  = 0;
1185   int            count = 0;
1186   size_t         len;
1187   PetscErrorCode ierr;
1188   PetscBool      method,params,id;
1189   char           *methodname,*idname,**args,**argso = 0;
1190   PetscInt       argc = 0,argco,i;
1191   PetscErrorCode (*fun)(PetscInt,char**,PetscInt*,char***);
1192 
1193   PetscFunctionBegin;
1194   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1195   yaml_parser_initialize(&parser);
1196   PetscStrlen(request,&len);
1197   yaml_parser_set_input_string(&parser, (unsigned char*)request, len);
1198 
1199   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1200   while (!done) {
1201     if (!yaml_parser_parse(&parser, &event)) {
1202       ierr = PetscInfo(NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1203       break;
1204     }
1205     done = (event.type == YAML_STREAM_END_EVENT);
1206     switch (event.type) {
1207     case YAML_STREAM_START_EVENT:
1208       ierr = PetscInfo(NULL,"Stream start\n");CHKERRQ(ierr);
1209       break;
1210     case YAML_STREAM_END_EVENT:
1211       ierr = PetscInfo(NULL,"Stream end\n");CHKERRQ(ierr);
1212       break;
1213     case YAML_DOCUMENT_START_EVENT:
1214       ierr = PetscInfo(NULL,"Document start\n");CHKERRQ(ierr);
1215       break;
1216     case YAML_DOCUMENT_END_EVENT:
1217       ierr = PetscInfo(NULL,"Document end\n");CHKERRQ(ierr);
1218       break;
1219     case YAML_MAPPING_START_EVENT:
1220       ierr = PetscInfo(NULL,"Mapping start event\n");CHKERRQ(ierr);
1221       break;
1222     case YAML_MAPPING_END_EVENT:
1223       ierr = PetscInfo(NULL,"Mapping end event \n");CHKERRQ(ierr);
1224       break;
1225     case YAML_ALIAS_EVENT:
1226       ierr = PetscInfo1(NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1227       break;
1228     case YAML_SCALAR_EVENT:
1229       ierr = PetscInfo1(NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1230       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1231       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1232       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1233       if (method) {
1234         yaml_event_delete(&event);
1235         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1236         ierr = PetscInfo1(NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1237         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1238       } else if (id) {
1239         yaml_event_delete(&event);
1240         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1241         ierr = PetscInfo1(NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1242         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1243       } else if (params) {
1244         yaml_event_delete(&event);
1245         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1246         yaml_event_delete(&event);
1247         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1248         while (event.type != YAML_SEQUENCE_END_EVENT) {
1249           ierr = PetscInfo1(NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1250           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1251           yaml_event_delete(&event);
1252           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1253         }
1254       } else { /* ignore all the other variables in the mapping */
1255         yaml_event_delete(&event);
1256         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1257       }
1258       break;
1259     case YAML_SEQUENCE_START_EVENT:
1260       ierr = PetscInfo(NULL,"Sequence start event \n");CHKERRQ(ierr);
1261       break;
1262     case YAML_SEQUENCE_END_EVENT:
1263       ierr = PetscInfo(NULL,"Sequence end event \n");CHKERRQ(ierr);
1264       break;
1265     default:
1266       /* It couldn't really happen. */
1267       break;
1268     }
1269 
1270     yaml_event_delete(&event);
1271     count++;
1272   }
1273   yaml_parser_delete(&parser);
1274 
1275   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,NULL,NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1276   if (fun) {
1277     ierr = PetscInfo1(NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1278     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1279   } else {
1280     ierr = PetscInfo1(NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1281   }
1282 
1283   for (i=0; i<argc; i++) {
1284     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1285   }
1286   ierr = PetscFree(args);CHKERRQ(ierr);
1287   ierr = PetscFree(methodname);CHKERRQ(ierr);
1288 
1289   /* convert the result back to YAML/JSON; should use YAML/JSON encoder, does not handle zero return arguments */
1290   ierr = PetscMalloc(16000,result);CHKERRQ(ierr);
1291   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1292   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1293   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1294   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1295   for (i=0; i<argco; i++) {
1296     if (argso[i][0] != '[') {
1297       ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1298     }
1299     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1300     if (argso[i][0] != '[') {
1301       ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1302     }
1303     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1304   }
1305   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1306   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1307   ierr = PetscInfo1(NULL,"YAML/JSON result of function %s\n",*result);CHKERRQ(ierr);
1308 
1309   /* free work space */
1310   ierr = PetscFree(idname);CHKERRQ(ierr);
1311   for (i=0; i<argco; i++) {
1312     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1313   }
1314   ierr = PetscFree(argso);CHKERRQ(ierr);
1315   PetscFunctionReturn(0);
1316 }
1317 
1318 #undef __FUNCT__
1319 #define __FUNCT__ "PetscWebServeRequestPostAMSJSONRPC"
1320 /*@C
1321       PetscWebServeRequestPostAMSJSONRPC - serves a single web POST request based on JSON-RPC
1322 
1323        This function allows a Javascript program (running in the browser) to make an AMS function
1324        call via JSON-RPC
1325 
1326        The currently available Javascript programs are in ${PETSC_DIR}/include/web
1327 
1328     Not collective
1329 
1330   Input Parameters:
1331 .   fd - the network file to read and write from
1332 -   path - the command from the server
1333 
1334     Level: developer
1335 
1336 .seealso: PetscWebServe()
1337 @*/
1338 static PetscErrorCode  PetscWebServeRequestPostAMSJSONRPC(FILE *fd,const char path[])
1339 {
1340   PetscErrorCode ierr;
1341   char           buf[16000];
1342   char           *result;
1343   int            len = -1;
1344   size_t         elen;
1345   char           *fnd;
1346 
1347   PetscFunctionBegin;
1348   while (PETSC_TRUE) {
1349     if (!fgets(buf, sizeof(buf), fd)) {
1350       ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1351       PetscFunctionReturn(0);
1352     }
1353     ierr = PetscInfo1(NULL,"POSTED header: %s",buf);CHKERRQ(ierr);
1354     ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1355     if (fnd) {
1356       ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1357       if (!fnd) {
1358         ierr = PetscInfo(NULL,"POSTED content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1359         PetscFunctionReturn(0);
1360       }
1361     }
1362     ierr = PetscStrstr(buf,"Content-Length:",&fnd);CHKERRQ(ierr);
1363     if (fnd) {
1364       sscanf(buf,"Content-Length: %d\n",&len);
1365       ierr = PetscInfo1(NULL,"POSTED Content-Length: %d\n",len);CHKERRQ(ierr);
1366     }
1367     if (buf[0] == '\r') break;
1368   }
1369   if (len == -1) {
1370     ierr = PetscInfo(NULL,"Did not find POST Content-Length in header, giving up\n");CHKERRQ(ierr);
1371   }
1372 
1373   if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1374     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1375     PetscFunctionReturn(0);
1376   }
1377   ierr = PetscInfo1(NULL,"POSTED JSON/RPC request: %s\n",buf);CHKERRQ(ierr);
1378   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1379   ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1380   ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1381   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1382   fprintf(fd, "%s",result);
1383   ierr = PetscInfo(NULL,"Completed AMS JSON-RPC function call\n");CHKERRQ(ierr);
1384   PetscFunctionReturn(0);
1385 }
1386 #endif
1387 
1388 #undef __FUNCT__
1389 #define __FUNCT__ "PetscWebServeRequest"
1390 /*@C
1391       PetscWebServeRequest - serves a single web request
1392 
1393     Not collective
1394 
1395   Input Parameters:
1396 .   port - the port
1397 
1398     Level: developer
1399 
1400 .seealso: PetscWebServe()
1401 @*/
1402 static PetscErrorCode  PetscWebServeRequest(int port)
1403 {
1404   PetscErrorCode ierr;
1405   FILE           *fd;
1406   char           buf[4096];
1407   char           *method, *path, *protocol;
1408   PetscBool      flg;
1409   PetscToken     tok;
1410 
1411   PetscFunctionBegin;
1412   fd = fdopen(port, "r+");
1413 
1414   ierr = PetscInfo(NULL,"Processing web request\n");CHKERRQ(ierr);
1415   if (!fgets(buf, sizeof(buf), fd)) {
1416     ierr = PetscInfo(NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1417     goto theend;
1418   }
1419   ierr = PetscInfo1(NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1420 
1421   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1422   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1423   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1424   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1425 
1426   if (!method || !path || !protocol) {
1427     ierr = PetscInfo(NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1428     goto theend;
1429   }
1430 
1431   ierr = PetscStrcmp(method,"GET",&flg);
1432   if (flg) {
1433       ierr = PetscWebServeRequestGet(fd,path);CHKERRQ(ierr);
1434   } else {
1435 #if defined(PETSC_HAVE_YAML)
1436     ierr = PetscStrcmp(method,"POST",&flg);
1437     if (flg) {
1438       ierr = PetscWebServeRequestPostAMSJSONRPC(fd,path);CHKERRQ(ierr);
1439     } else {
1440 #else
1441     {
1442 #endif
1443       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1444       ierr = PetscInfo(NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1445     }
1446   }
1447 theend:
1448   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1449   fclose(fd);
1450   ierr = PetscInfo1(NULL,"Finished processing request %s\n",method);CHKERRQ(ierr);
1451   PetscFunctionReturn(0);
1452 }
1453 
1454 #undef __FUNCT__
1455 #define __FUNCT__ "PetscWebServeWait"
1456 /*@C
1457       PetscWebServeWait - waits for requests on a thread
1458 
1459     Not collective
1460 
1461   Input Parameter:
1462 .   port - port to listen on
1463 
1464     Level: developer
1465 
1466 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1467 @*/
1468 void *PetscWebServeWait(int *port)
1469 {
1470   PetscErrorCode ierr;
1471   int            iport,listenport,tport = *port;
1472 
1473   ierr = PetscInfo1(NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1474   ierr = PetscFree(port);if (ierr) return 0;
1475   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1476   while (1) {
1477     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1478     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1479     close(iport);
1480   }
1481   close(listenport);
1482   return 0;
1483 }
1484 
1485 #undef __FUNCT__
1486 #define __FUNCT__ "PetscWebServe"
1487 /*@C
1488       PetscWebServe - start up the PETSc web server and respond to requests
1489 
1490     Not collective - only does something on process zero of the communicator
1491 
1492   Input Parameters:
1493 +   comm - the MPI communicator
1494 -   port - port to listen on
1495 
1496   Options Database Key:
1497 +  -server <port> - start PETSc webserver (default port is 8080)
1498 -  -ams_publish_objects
1499 
1500 
1501    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1502       If you are running PETSc on your local machine you can use http://localhost:8080
1503 
1504       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1505 
1506       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1507 
1508     Level: intermediate
1509 
1510 .seealso: PetscViewerSocketOpen()
1511 @*/
1512 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1513 {
1514   PetscErrorCode ierr;
1515   PetscMPIInt    rank;
1516   pthread_t      thread;
1517   int            *trueport;
1518 
1519   PetscFunctionBegin;
1520   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1521   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1522   if (rank) PetscFunctionReturn(0);
1523 
1524   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1525   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1526   *trueport = port;
1527   ierr = pthread_create(&thread, NULL, (void *(*)(void*))PetscWebServeWait, trueport);CHKERRQ(ierr);
1528   PetscFunctionReturn(0);
1529 }
1530 #endif
1531 
1532 
1533 
1534 
1535 
1536 
1537 
1538 
1539 
1540 
1541 
1542 
1543 
1544 
1545