xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 69c1e2ab082ac3c0e7742bd5c06d72610a654dd3)
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_Memory_get_field_info"
1039 /*
1040       Gets information about a field
1041 
1042    Input Parameter:
1043 .     arg1 - memory
1044 .     arg2 - string name of the field
1045 
1046    Output Parameter:
1047 
1048 */
1049 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1050 {
1051   PetscErrorCode     ierr;
1052   AMS_Memory         mem;
1053   void               *addr;
1054   int                len;
1055   AMS_Data_type      dtype;
1056   AMS_Memory_type    mtype;
1057   AMS_Shared_type    stype;
1058   AMS_Reduction_type rtype;
1059   PetscInt           i;
1060 
1061   PetscFunctionBegin;
1062   sscanf(args[0],"%d",&mem);
1063   ierr = AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
1064   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
1065   *argco = 4 + len;
1066   ierr   = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
1067   ierr   = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
1068   ierr   = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
1069   ierr   = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
1070   ierr   = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
1071   for (i=0; i<len; i++) {
1072     if (dtype == AMS_STRING) {
1073       ierr = PetscStrallocpy(*(const char**)addr,&argso[0][4+i]);CHKERRQ(ierr);
1074     } else if (dtype == AMS_DOUBLE) {
1075       ierr = PetscMalloc(20*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1076       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
1077     } else if (dtype == AMS_INT) {
1078       ierr = PetscMalloc(10*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1079       sprintf(argso[0][4+i],"%d",*(int*)addr);
1080     } else if (dtype == AMS_BOOLEAN) {
1081       if (*(int*)addr) {
1082         ierr = PetscStrallocpy("true",&argso[0][4+i]);CHKERRQ(ierr);
1083       } else {
1084         ierr = PetscStrallocpy("false",&argso[0][4+i]);CHKERRQ(ierr);
1085       }
1086     } else {
1087       ierr = PetscStrallocpy("Not yet done",&argso[0][4+i]);CHKERRQ(ierr);
1088     }
1089   }
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 #include "yaml.h"
1094 #undef __FUNCT__
1095 #define __FUNCT__ "PetscProcessYAMLRPC"
1096 /*
1097      1) Parses a YAML/JSON-RPC function call generating a function name for an AMS wrapper function and the arguments to the function
1098      2) loads the function with dlsym(),
1099      3) calls the wrapper function with the arguments
1100      4) converts the result arguments back to YAML/JSON.
1101 */
1102 static PetscErrorCode PetscProcessYAMLRPC(const char *request,char **result)
1103 {
1104   yaml_parser_t  parser;
1105   yaml_event_t   event;
1106   int            done  = 0;
1107   int            count = 0;
1108   size_t         len;
1109   PetscErrorCode ierr;
1110   PetscBool      method,params,id;
1111   char           *methodname,*idname,**args,**argso = 0;
1112   PetscInt       argc = 0,argco,i;
1113   PetscErrorCode (*fun)(PetscInt,char**,PetscInt*,char***);
1114 
1115   PetscFunctionBegin;
1116   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1117   yaml_parser_initialize(&parser);
1118   PetscStrlen(request,&len);
1119   yaml_parser_set_input_string(&parser, (unsigned char*)request, len);
1120 
1121   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1122   while (!done) {
1123     if (!yaml_parser_parse(&parser, &event)) {
1124       ierr = PetscInfo(NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1125       break;
1126     }
1127     done = (event.type == YAML_STREAM_END_EVENT);
1128     switch (event.type) {
1129     case YAML_STREAM_START_EVENT:
1130       ierr = PetscInfo(NULL,"Stream start\n");CHKERRQ(ierr);
1131       break;
1132     case YAML_STREAM_END_EVENT:
1133       ierr = PetscInfo(NULL,"Stream end\n");CHKERRQ(ierr);
1134       break;
1135     case YAML_DOCUMENT_START_EVENT:
1136       ierr = PetscInfo(NULL,"Document start\n");CHKERRQ(ierr);
1137       break;
1138     case YAML_DOCUMENT_END_EVENT:
1139       ierr = PetscInfo(NULL,"Document end\n");CHKERRQ(ierr);
1140       break;
1141     case YAML_MAPPING_START_EVENT:
1142       ierr = PetscInfo(NULL,"Mapping start event\n");CHKERRQ(ierr);
1143       break;
1144     case YAML_MAPPING_END_EVENT:
1145       ierr = PetscInfo(NULL,"Mapping end event \n");CHKERRQ(ierr);
1146       break;
1147     case YAML_ALIAS_EVENT:
1148       ierr = PetscInfo1(NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1149       break;
1150     case YAML_SCALAR_EVENT:
1151       ierr = PetscInfo1(NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1152       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1153       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1154       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1155       if (method) {
1156         yaml_event_delete(&event);
1157         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1158         ierr = PetscInfo1(NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1159         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1160       } else if (id) {
1161         yaml_event_delete(&event);
1162         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1163         ierr = PetscInfo1(NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1164         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1165       } else if (params) {
1166         yaml_event_delete(&event);
1167         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1168         yaml_event_delete(&event);
1169         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1170         while (event.type != YAML_SEQUENCE_END_EVENT) {
1171           ierr = PetscInfo1(NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1172           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1173           yaml_event_delete(&event);
1174           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1175         }
1176       } else { /* ignore all the other variables in the mapping */
1177         yaml_event_delete(&event);
1178         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1179       }
1180       break;
1181     case YAML_SEQUENCE_START_EVENT:
1182       ierr = PetscInfo(NULL,"Sequence start event \n");CHKERRQ(ierr);
1183       break;
1184     case YAML_SEQUENCE_END_EVENT:
1185       ierr = PetscInfo(NULL,"Sequence end event \n");CHKERRQ(ierr);
1186       break;
1187     default:
1188       /* It couldn't really happen. */
1189       break;
1190     }
1191 
1192     yaml_event_delete(&event);
1193     count++;
1194   }
1195   yaml_parser_delete(&parser);
1196 
1197   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,NULL,NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1198   if (fun) {
1199     ierr = PetscInfo1(NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1200     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1201   } else {
1202     ierr = PetscInfo1(NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1203   }
1204 
1205   for (i=0; i<argc; i++) {
1206     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1207   }
1208   ierr = PetscFree(args);CHKERRQ(ierr);
1209   ierr = PetscFree(methodname);CHKERRQ(ierr);
1210 
1211   /* convert the result back to YAML/JSON; should use YAML/JSON encoder, does not handle zero return arguments */
1212   ierr = PetscMalloc(1024,result);CHKERRQ(ierr);
1213   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1214   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1215   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1216   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1217   for (i=0; i<argco; i++) {
1218     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1219     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1220     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1221     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1222   }
1223   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1224   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1225   ierr = PetscInfo1(NULL,"YAML/JSON result of function %s\n",*result);CHKERRQ(ierr);
1226 
1227   /* free work space */
1228   ierr = PetscFree(idname);CHKERRQ(ierr);
1229   for (i=0; i<argco; i++) {
1230     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1231   }
1232   ierr = PetscFree(argso);CHKERRQ(ierr);
1233   PetscFunctionReturn(0);
1234 }
1235 
1236 #undef __FUNCT__
1237 #define __FUNCT__ "PetscWebServeRequestPostAMSJSONRPC"
1238 /*@C
1239       PetscWebServeRequestPostAMSJSONRPC - serves a single web POST request based on JSON-RPC
1240 
1241        This function allows a Javascript program (running in the browser) to make an AMS function
1242        call via JSON-RPC
1243 
1244        The currently available Javascript programs are in ${PETSC_DIR}/include/web
1245 
1246     Not collective
1247 
1248   Input Parameters:
1249 .   fd - the network file to read and write from
1250 -   path - the command from the server
1251 
1252     Level: developer
1253 
1254 .seealso: PetscWebServe()
1255 @*/
1256 static PetscErrorCode  PetscWebServeRequestPostAMSJSONRPC(FILE *fd,const char path[])
1257 {
1258   PetscErrorCode ierr;
1259   char           buf[4096];
1260   char           *result;
1261   PetscInt       cnt = 8;
1262   int            len;
1263   size_t         elen;
1264   char           *fnd;
1265 
1266   PetscFunctionBegin;
1267   while (cnt--) {
1268 
1269     if (!fgets(buf, sizeof(buf), fd)) {
1270       ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1271       PetscFunctionReturn(0);
1272     }
1273     ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1274     ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1275     if (fnd) {
1276       ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1277       if (!fnd) {
1278         ierr = PetscInfo(NULL,"POST content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1279         PetscFunctionReturn(0);
1280       }
1281     }
1282   }
1283   if (!fgets(buf, sizeof(buf), fd)) {
1284     ierr = PetscInfo(NULL,"Cannot read POST length data, giving up\n");CHKERRQ(ierr);
1285     PetscFunctionReturn(0);
1286   }
1287   ierr = PetscInfo1(NULL,"POSTED length data %s",buf);CHKERRQ(ierr);
1288   sscanf(buf,"Content-Length: %d\n",&len);
1289   ierr = PetscInfo1(NULL,"Length of POSTED data %d\n",len);CHKERRQ(ierr);
1290   if (!fgets(buf, sizeof(buf), fd)) {
1291     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1292     PetscFunctionReturn(0);
1293   }
1294   ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1295   if (!fgets(buf, sizeof(buf), fd)) {
1296     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1297     PetscFunctionReturn(0);
1298   }
1299   ierr = PetscInfo1(NULL,"POSTED data %s",buf);CHKERRQ(ierr);
1300   if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1301     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1302     PetscFunctionReturn(0);
1303   }
1304   ierr = PetscInfo1(NULL,"POSTED data %s\n",buf);CHKERRQ(ierr);
1305   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1306   ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1307   ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1308   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1309   fprintf(fd, "%s",result);
1310   PetscFunctionReturn(0);
1311 }
1312 #endif
1313 
1314 #undef __FUNCT__
1315 #define __FUNCT__ "PetscWebServeRequest"
1316 /*@C
1317       PetscWebServeRequest - serves a single web request
1318 
1319     Not collective
1320 
1321   Input Parameters:
1322 .   port - the port
1323 
1324     Level: developer
1325 
1326 .seealso: PetscWebServe()
1327 @*/
1328 static PetscErrorCode  PetscWebServeRequest(int port)
1329 {
1330   PetscErrorCode ierr;
1331   FILE           *fd;
1332   char           buf[4096];
1333   char           *method, *path, *protocol;
1334   PetscBool      flg;
1335   PetscToken     tok;
1336 
1337   PetscFunctionBegin;
1338   fd = fdopen(port, "r+");
1339 
1340   ierr = PetscInfo(NULL,"Processing web request\n");CHKERRQ(ierr);
1341   if (!fgets(buf, sizeof(buf), fd)) {
1342     ierr = PetscInfo(NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1343     goto theend;
1344   }
1345   ierr = PetscInfo1(NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1346 
1347   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1348   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1349   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1350   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1351   ierr = PetscInfo3(NULL,"Browser method %s path %s protocol %s\n",method,path,protocol);
1352 
1353   if (!method || !path || !protocol) {
1354     ierr = PetscInfo(NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1355     goto theend;
1356   }
1357 
1358   ierr = PetscStrcmp(method,"GET",&flg);
1359   if (flg) {
1360       ierr = PetscWebServeRequestGet(fd,path);CHKERRQ(ierr);
1361   } else {
1362 #if defined(PETSC_HAVE_YAML)
1363     ierr = PetscStrcmp(method,"POST",&flg);
1364     if (flg) {
1365       ierr = PetscWebServeRequestPostAMSJSONRPC(fd,path);CHKERRQ(ierr);
1366     } else {
1367 #else
1368     {
1369 #endif
1370       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1371       ierr = PetscInfo(NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1372     }
1373   }
1374 theend:
1375   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1376   fclose(fd);
1377   ierr = PetscInfo1(NULL,"Finished processing request %s\n",method);CHKERRQ(ierr);
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "PetscWebServeWait"
1383 /*@C
1384       PetscWebServeWait - waits for requests on a thread
1385 
1386     Not collective
1387 
1388   Input Parameter:
1389 .   port - port to listen on
1390 
1391     Level: developer
1392 
1393 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1394 @*/
1395 void *PetscWebServeWait(int *port)
1396 {
1397   PetscErrorCode ierr;
1398   int            iport,listenport,tport = *port;
1399 
1400   ierr = PetscInfo1(NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1401   ierr = PetscFree(port);if (ierr) return 0;
1402   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1403   while (1) {
1404     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1405     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1406     close(iport);
1407   }
1408   close(listenport);
1409   return 0;
1410 }
1411 
1412 #undef __FUNCT__
1413 #define __FUNCT__ "PetscWebServe"
1414 /*@
1415       PetscWebServe - start up the PETSc web server and respond to requests
1416 
1417     Not collective - only does something on process zero of the communicator
1418 
1419   Input Parameters:
1420 +   comm - the MPI communicator
1421 -   port - port to listen on
1422 
1423   Options Database Key:
1424 +  -server <port> - start PETSc webserver (default port is 8080)
1425 -  -ams_publish_objects
1426 
1427 
1428    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1429       If you are running PETSc on your local machine you can use http://localhost:8080
1430 
1431       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1432 
1433       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1434 
1435     Level: intermediate
1436 
1437 .seealso: PetscViewerSocketOpen()
1438 @*/
1439 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1440 {
1441   PetscErrorCode ierr;
1442   PetscMPIInt    rank;
1443   pthread_t      thread;
1444   int            *trueport;
1445 
1446   PetscFunctionBegin;
1447   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1448   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1449   if (rank) PetscFunctionReturn(0);
1450 
1451   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1452   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1453   *trueport = port;
1454   ierr = pthread_create(&thread, NULL, (void *(*)(void*))PetscWebServeWait, trueport);CHKERRQ(ierr);
1455   PetscFunctionReturn(0);
1456 }
1457 #endif
1458 
1459 
1460 
1461 
1462 
1463 
1464 
1465 
1466 
1467 
1468 
1469 
1470 
1471 
1472