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 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer) 61 { 62 PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data; 63 PetscErrorCode ierr; 64 65 PetscFunctionBegin; 66 if (vmatlab->port) { 67 #if defined(PETSC_HAVE_CLOSESOCKET) 68 ierr = closesocket(vmatlab->port); 69 #else 70 ierr = close(vmatlab->port); 71 #endif 72 PetscCheck(!ierr,PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket"); 73 } 74 PetscCall(PetscFree(vmatlab)); 75 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerBinarySetSkipHeader_C",NULL)); 76 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerBinaryGetSkipHeader_C",NULL)); 77 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerBinaryGetFlowControl_C",NULL)); 78 PetscFunctionReturn(0); 79 } 80 81 /*--------------------------------------------------------------*/ 82 /*@C 83 PetscSocketOpen - handles connected to an open port where someone is waiting. 84 85 Input Parameters: 86 + url - for example www.mcs.anl.gov 87 - portnum - for example 80 88 89 Output Parameter: 90 . t - the socket number 91 92 Notes: 93 Use close() to close the socket connection 94 95 Use read() or PetscHTTPRequest() to read from the socket 96 97 Level: advanced 98 99 .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()` 100 @*/ 101 PetscErrorCode PetscOpenSocket(const char hostname[],int portnum,int *t) 102 { 103 struct sockaddr_in sa; 104 struct hostent *hp; 105 int s = 0; 106 PetscBool flg = PETSC_TRUE; 107 static int refcnt = 0; 108 109 PetscFunctionBegin; 110 if (!(hp=gethostbyname(hostname))) { 111 perror("SEND: error gethostbyname: "); 112 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname); 113 } 114 PetscCall(PetscMemzero(&sa,sizeof(sa))); 115 PetscCall(PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length)); 116 117 sa.sin_family = hp->h_addrtype; 118 sa.sin_port = htons((u_short) portnum); 119 while (flg) { 120 if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) { 121 perror("SEND: error socket"); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 122 } 123 if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) { 124 #if defined(PETSC_HAVE_WSAGETLASTERROR) 125 ierr = WSAGetLastError(); 126 if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n"); 127 else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 128 else if (ierr == WSAEISCONN) { 129 (*PetscErrorPrintf)("SEND: socket already connected\n"); 130 Sleep((unsigned) 1); 131 } else if (ierr == WSAECONNREFUSED) { 132 /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */ 133 Sleep((unsigned) 1); 134 } else { 135 perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 136 } 137 #else 138 if (errno == EADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n"); 139 else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 140 else if (errno == EISCONN) { 141 (*PetscErrorPrintf)("SEND: socket already connected\n"); 142 sleep((unsigned) 1); 143 } else if (errno == ECONNREFUSED) { 144 refcnt++; 145 PetscCheck(refcnt <= 5,PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum); 146 PetscCall(PetscInfo(NULL,"Connection refused in attaching socket, trying again\n")); 147 sleep((unsigned) 1); 148 } else { 149 perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error"); 150 } 151 #endif 152 flg = PETSC_TRUE; 153 #if defined(PETSC_HAVE_CLOSESOCKET) 154 closesocket(s); 155 #else 156 close(s); 157 #endif 158 } else flg = PETSC_FALSE; 159 } 160 *t = s; 161 PetscFunctionReturn(0); 162 } 163 164 /*@C 165 PetscSocketEstablish - starts a listener on a socket 166 167 Input Parameters: 168 . portnumber - the port to wait at 169 170 Output Parameters: 171 . ss - the socket to be used with PetscSocketListen() 172 173 Level: advanced 174 175 .seealso: `PetscSocketListen()`, `PetscOpenSocket()` 176 177 @*/ 178 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss) 179 { 180 static size_t MAXHOSTNAME = 100; 181 char myname[MAXHOSTNAME+1]; 182 int s; 183 struct sockaddr_in sa; 184 struct hostent *hp; 185 186 PetscFunctionBegin; 187 PetscCall(PetscGetHostName(myname,sizeof(myname))); 188 189 PetscCall(PetscMemzero(&sa,sizeof(struct sockaddr_in))); 190 191 hp = gethostbyname(myname); 192 PetscCheck(hp,PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system"); 193 194 sa.sin_family = hp->h_addrtype; 195 sa.sin_port = htons((u_short)portnum); 196 197 PetscCheck((s = socket(AF_INET,SOCK_STREAM,0)) >= 0,PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command"); 198 #if defined(PETSC_HAVE_SO_REUSEADDR) 199 { 200 int optval = 1; /* Turn on the option */ 201 PetscCall(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval))); 202 } 203 #endif 204 205 while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) { 206 #if defined(PETSC_HAVE_WSAGETLASTERROR) 207 ierr = WSAGetLastError(); 208 if (ierr != WSAEADDRINUSE) { 209 #else 210 if (errno != EADDRINUSE) { 211 #endif 212 close(s); 213 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()"); 214 } 215 } 216 listen(s,0); 217 *ss = s; 218 return(0); 219 } 220 221 /*@C 222 PetscSocketListen - Listens at a socket created with PetscSocketEstablish() 223 224 Input Parameter: 225 . listenport - obtained with PetscSocketEstablish() 226 227 Output Parameter: 228 . t - pass this to read() to read what is passed to this connection 229 230 Level: advanced 231 232 .seealso: `PetscSocketEstablish()` 233 @*/ 234 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t) 235 { 236 struct sockaddr_in isa; 237 #if defined(PETSC_HAVE_ACCEPT_SIZE_T) 238 size_t i; 239 #else 240 int i; 241 #endif 242 243 PetscFunctionBegin; 244 /* wait for someone to try to connect */ 245 i = sizeof(struct sockaddr_in); 246 PetscCheck((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) >= 0,PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()"); 247 PetscFunctionReturn(0); 248 } 249 250 /*@C 251 PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server. 252 253 Collective 254 255 Input Parameters: 256 + comm - the MPI communicator 257 . machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for 258 a connection from elsewhere 259 - port - the port to connect to, use PETSC_DEFAULT for the default 260 261 Output Parameter: 262 . lab - a context to use when communicating with the server 263 264 Level: intermediate 265 266 Notes: 267 Most users should employ the following commands to access the 268 MATLAB PetscViewers 269 $ 270 $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer) 271 $ MatView(Mat matrix,PetscViewer viewer) 272 $ 273 $ or 274 $ 275 $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer) 276 $ VecView(Vec vector,PetscViewer viewer) 277 278 Options Database Keys: 279 For use with PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, 280 PETSC_VIEWER_SOCKET_() or if 281 NULL is passed for machine or PETSC_DEFAULT is passed for port 282 $ -viewer_socket_machine <machine> 283 $ -viewer_socket_port <port> 284 285 Environmental variables: 286 + PETSC_VIEWER_SOCKET_PORT - portnumber 287 - PETSC_VIEWER_SOCKET_MACHINE - machine name 288 289 Currently the only socket client available is MATLAB. See 290 src/dm/tests/ex12.c and ex12.m for an example of usage. 291 292 Notes: 293 The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket 294 use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor(). 295 296 Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a 297 .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD 298 for communicating with a MATLAB Engine 299 300 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`, 301 `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`, 302 `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`, 303 `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()` 304 @*/ 305 PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab) 306 { 307 PetscFunctionBegin; 308 PetscCall(PetscViewerCreate(comm,lab)); 309 PetscCall(PetscViewerSetType(*lab,PETSCVIEWERSOCKET)); 310 PetscCall(PetscViewerSocketSetConnection(*lab,machine,port)); 311 PetscFunctionReturn(0); 312 } 313 314 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v,PetscOptionItems *PetscOptionsObject) 315 { 316 PetscInt def = -1; 317 char sdef[256]; 318 PetscBool tflg; 319 320 PetscFunctionBegin; 321 /* 322 These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they 323 are listed here for the GUI to display 324 */ 325 PetscOptionsHeadBegin(PetscOptionsObject,"Socket PetscViewer Options"); 326 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg)); 327 if (tflg) { 328 PetscCall(PetscOptionsStringToInt(sdef,&def)); 329 } else def = PETSCSOCKETDEFAULTPORT; 330 PetscCall(PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,NULL,NULL)); 331 332 PetscCall(PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,sizeof(sdef),NULL)); 333 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,sizeof(sdef),&tflg)); 334 if (!tflg) { 335 PetscCall(PetscGetHostName(sdef,sizeof(sdef))); 336 } 337 PetscOptionsHeadEnd(); 338 PetscFunctionReturn(0); 339 } 340 341 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool *skip) 342 { 343 PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data; 344 345 PetscFunctionBegin; 346 *skip = vsocket->skipheader; 347 PetscFunctionReturn(0); 348 } 349 350 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip) 351 { 352 PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data; 353 354 PetscFunctionBegin; 355 vsocket->skipheader = skip; 356 PetscFunctionReturn(0); 357 } 358 359 static PetscErrorCode PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc) 360 { 361 PetscFunctionBegin; 362 *fc = 0; 363 PetscFunctionReturn(0); 364 } 365 366 /*MC 367 PETSCVIEWERSOCKET - A viewer that writes to a Unix socket 368 369 .seealso: `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`, 370 `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`, 371 `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`, 372 `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()` 373 374 Level: beginner 375 M*/ 376 377 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v) 378 { 379 PetscViewer_Socket *vmatlab; 380 381 PetscFunctionBegin; 382 PetscCall(PetscNewLog(v,&vmatlab)); 383 vmatlab->port = 0; 384 v->data = (void*)vmatlab; 385 v->ops->destroy = PetscViewerDestroy_Socket; 386 v->ops->flush = NULL; 387 v->ops->setfromoptions = PetscViewerSetFromOptions_Socket; 388 389 /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */ 390 PetscCall(PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY)); 391 PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket)); 392 PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket)); 393 PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket)); 394 395 PetscFunctionReturn(0); 396 } 397 398 /*@C 399 PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket 400 viewer is to use 401 402 Logically Collective on PetscViewer 403 404 Input Parameters: 405 + v - viewer to connect 406 . machine - host to connect to, use NULL for the local machine,use "server" to passively wait for 407 a connection from elsewhere 408 - port - the port on the machine one is connecting to, use PETSC_DEFAULT for default 409 410 Level: advanced 411 412 .seealso: `PetscViewerSocketOpen()` 413 @*/ 414 PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port) 415 { 416 PetscMPIInt rank; 417 char mach[256]; 418 PetscBool tflg; 419 PetscViewer_Socket *vmatlab; 420 421 PetscFunctionBegin; 422 PetscValidHeaderSpecific(v,PETSC_VIEWER_CLASSID,1); 423 if (machine) PetscValidCharPointer(machine,2); 424 vmatlab = (PetscViewer_Socket*)v->data; 425 /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */ 426 if (port <= 0) { 427 char portn[16]; 428 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg)); 429 if (tflg) { 430 PetscInt pport; 431 PetscCall(PetscOptionsStringToInt(portn,&pport)); 432 port = (int)pport; 433 } else port = PETSCSOCKETDEFAULTPORT; 434 } 435 if (!machine) { 436 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,sizeof(mach),&tflg)); 437 if (!tflg) { 438 PetscCall(PetscGetHostName(mach,sizeof(mach))); 439 } 440 } else { 441 PetscCall(PetscStrncpy(mach,machine,sizeof(mach))); 442 } 443 444 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank)); 445 if (rank == 0) { 446 PetscCall(PetscStrcmp(mach,"server",&tflg)); 447 if (tflg) { 448 int listenport; 449 PetscCall(PetscInfo(v,"Waiting for connection from socket process on port %d\n",port)); 450 PetscCall(PetscSocketEstablish(port,&listenport)); 451 PetscCall(PetscSocketListen(listenport,&vmatlab->port)); 452 close(listenport); 453 } else { 454 PetscCall(PetscInfo(v,"Connecting to socket process on port %d machine %s\n",port,mach)); 455 PetscCall(PetscOpenSocket(mach,port,&vmatlab->port)); 456 } 457 } 458 PetscFunctionReturn(0); 459 } 460 461 /* ---------------------------------------------------------------------*/ 462 /* 463 The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that 464 is attached to a communicator, in this case the attribute is a PetscViewer. 465 */ 466 PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID; 467 468 /*@C 469 PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator. 470 471 Collective 472 473 Input Parameter: 474 . comm - the MPI communicator to share the socket PetscViewer 475 476 Level: intermediate 477 478 Options Database Keys: 479 For use with the default PETSC_VIEWER_SOCKET_WORLD or if 480 NULL is passed for machine or PETSC_DEFAULT is passed for port 481 $ -viewer_socket_machine <machine> 482 $ -viewer_socket_port <port> 483 484 Environmental variables: 485 + PETSC_VIEWER_SOCKET_PORT - portnumber 486 - PETSC_VIEWER_SOCKET_MACHINE - machine name 487 488 Notes: 489 Unlike almost all other PETSc routines, Petsc_VIEWER_SOCKET_ does not return 490 an error code, it returns NULL if it fails. The socket PetscViewer is usually used in the form 491 $ XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm)); 492 493 Currently the only socket client available is MATLAB. See 494 src/dm/tests/ex12.c and ex12.m for an example of usage. 495 496 Connects to a waiting socket and stays connected until PetscViewerDestroy() is called. 497 498 Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a 499 .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD 500 for communicating with a MATLAB Engine 501 502 .seealso: `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`, 503 `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, 504 `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()` 505 @*/ 506 PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm) 507 { 508 PetscErrorCode ierr; 509 PetscBool flg; 510 PetscViewer viewer; 511 MPI_Comm ncomm; 512 513 PetscFunctionBegin; 514 ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 515 if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) { 516 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL); 517 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 518 } 519 ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg); 520 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 521 if (!flg) { /* PetscViewer not yet created */ 522 ierr = PetscViewerSocketOpen(ncomm,NULL,0,&viewer); 523 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);} 524 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 525 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);} 526 ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer); 527 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 528 } 529 ierr = PetscCommDestroy(&ncomm); 530 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);} 531 PetscFunctionReturn(viewer); 532 } 533