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