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