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