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