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