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",¶ms);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