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