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