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