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