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 64 PetscFunctionBegin; 65 if (vmatlab->port) { 66 int ierr; 67 68 #if defined(PETSC_HAVE_CLOSESOCKET) 69 ierr = closesocket(vmatlab->port); 70 #else 71 ierr = close(vmatlab->port); 72 #endif 73 PetscCheck(!ierr, PETSC_COMM_SELF, PETSC_ERR_SYS, "System error closing socket"); 74 } 75 PetscCall(PetscFree(vmatlab)); 76 PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinarySetSkipHeader_C", NULL)); 77 PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetSkipHeader_C", NULL)); 78 PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetFlowControl_C", NULL)); 79 PetscFunctionReturn(PETSC_SUCCESS); 80 } 81 82 /*--------------------------------------------------------------*/ 83 /*@C 84 PetscSocketOpen - handles connected to an open port where someone is waiting. 85 86 Input Parameters: 87 + url - for example www.mcs.anl.gov 88 - portnum - for example 80 89 90 Output Parameter: 91 . t - the socket number 92 93 Notes: 94 Use close() to close the socket connection 95 96 Use read() or `PetscHTTPRequest()` to read from the socket 97 98 Level: advanced 99 100 .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()` 101 @*/ 102 PetscErrorCode PetscOpenSocket(const char hostname[], int portnum, int *t) 103 { 104 struct sockaddr_in sa; 105 struct hostent *hp; 106 int s = 0; 107 PetscBool flg = PETSC_TRUE; 108 static int refcnt = 0; 109 110 PetscFunctionBegin; 111 if (!(hp = gethostbyname(hostname))) { 112 perror("SEND: error gethostbyname: "); 113 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error open connection to %s", hostname); 114 } 115 PetscCall(PetscMemzero(&sa, sizeof(sa))); 116 PetscCall(PetscMemcpy(&sa.sin_addr, hp->h_addr_list[0], hp->h_length)); 117 118 sa.sin_family = hp->h_addrtype; 119 sa.sin_port = htons((u_short)portnum); 120 while (flg) { 121 if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { 122 perror("SEND: error socket"); 123 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error"); 124 } 125 if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 126 #if defined(PETSC_HAVE_WSAGETLASTERROR) 127 ierr = WSAGetLastError(); 128 if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n"); 129 else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 130 else if (ierr == WSAEISCONN) { 131 (*PetscErrorPrintf)("SEND: socket already connected\n"); 132 Sleep((unsigned)1); 133 } else if (ierr == WSAECONNREFUSED) { 134 /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */ 135 Sleep((unsigned)1); 136 } else { 137 perror(NULL); 138 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error"); 139 } 140 #else 141 if (errno == EADDRINUSE) { 142 PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: address is in use\n"); 143 (void)ierr; 144 } else if (errno == EALREADY) { 145 PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket is non-blocking \n"); 146 (void)ierr; 147 } else if (errno == EISCONN) { 148 PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket already connected\n"); 149 (void)ierr; 150 sleep((unsigned)1); 151 } else if (errno == ECONNREFUSED) { 152 refcnt++; 153 PetscCheck(refcnt <= 5, PETSC_COMM_SELF, PETSC_ERR_SYS, "Connection refused by remote host %s port %d", hostname, portnum); 154 PetscCall(PetscInfo(NULL, "Connection refused in attaching socket, trying again\n")); 155 sleep((unsigned)1); 156 } else { 157 perror(NULL); 158 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error"); 159 } 160 #endif 161 flg = PETSC_TRUE; 162 #if defined(PETSC_HAVE_CLOSESOCKET) 163 closesocket(s); 164 #else 165 close(s); 166 #endif 167 } else flg = PETSC_FALSE; 168 } 169 *t = s; 170 PetscFunctionReturn(PETSC_SUCCESS); 171 } 172 173 /*@C 174 PetscSocketEstablish - starts a listener on a socket 175 176 Input Parameters: 177 . portnumber - the port to wait at 178 179 Output Parameters: 180 . ss - the socket to be used with `PetscSocketListen()` 181 182 Level: advanced 183 184 .seealso: `PetscSocketListen()`, `PetscOpenSocket()` 185 @*/ 186 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum, int *ss) 187 { 188 static size_t MAXHOSTNAME = 100; 189 char myname[MAXHOSTNAME + 1]; 190 int s; 191 struct sockaddr_in sa; 192 struct hostent *hp; 193 194 PetscFunctionBegin; 195 PetscCall(PetscGetHostName(myname, sizeof(myname))); 196 197 PetscCall(PetscMemzero(&sa, sizeof(struct sockaddr_in))); 198 199 hp = gethostbyname(myname); 200 PetscCheck(hp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to get hostent information from system"); 201 202 sa.sin_family = hp->h_addrtype; 203 sa.sin_port = htons((u_short)portnum); 204 205 PetscCheck((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Error running socket() command"); 206 #if defined(PETSC_HAVE_SO_REUSEADDR) 207 { 208 int optval = 1; /* Turn on the option */ 209 int ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)); 210 PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "setsockopt() failed with error code %d", ret); 211 } 212 #endif 213 214 while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 215 #if defined(PETSC_HAVE_WSAGETLASTERROR) 216 ierr = WSAGetLastError(); 217 if (ierr != WSAEADDRINUSE) { 218 #else 219 if (errno != EADDRINUSE) { 220 #endif 221 close(s); 222 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "Error from bind()"); 223 } 224 } 225 listen(s, 0); 226 *ss = s; 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 /*@C 231 PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()` 232 233 Input Parameter: 234 . listenport - obtained with `PetscSocketEstablish()` 235 236 Output Parameter: 237 . t - pass this to read() to read what is passed to this connection 238 239 Level: advanced 240 241 .seealso: `PetscSocketEstablish()` 242 @*/ 243 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport, int *t) 244 { 245 struct sockaddr_in isa; 246 #if defined(PETSC_HAVE_ACCEPT_SIZE_T) 247 size_t i; 248 #else 249 int i; 250 #endif 251 252 PetscFunctionBegin; 253 /* wait for someone to try to connect */ 254 i = sizeof(struct sockaddr_in); 255 PetscCheck((*t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "error from accept()"); 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 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> 278 $ -viewer_socket_port <port> 279 280 Environmental variables: 281 + `PETSC_VIEWER_SOCKET_PORT` - portnumber 282 - `PETSC_VIEWER_SOCKET_MACHINE` - machine name 283 284 Level: intermediate 285 286 Notes: 287 Most users should employ the following commands to access the 288 MATLAB `PetscViewer` 289 $ 290 $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer) 291 $ MatView(Mat matrix,PetscViewer viewer) 292 $ 293 $ or 294 $ 295 $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer) 296 $ VecView(Vec vector,PetscViewer viewer) 297 298 Currently the only socket client available is MATLAB, PETSc must be configured with --with-matlab for this client. See 299 src/dm/tests/ex12.c and ex12.m for an example of usage. 300 301 The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket 302 use `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`, `PetscViewerBinarWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`. 303 304 Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a 305 .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD` 306 for communicating with a MATLAB Engine 307 308 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSCVIEWERSOCKET`, `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`, 309 `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`, 310 `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`, 311 `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()` 312 @*/ 313 PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm, const char machine[], int port, PetscViewer *lab) 314 { 315 PetscFunctionBegin; 316 PetscCall(PetscViewerCreate(comm, lab)); 317 PetscCall(PetscViewerSetType(*lab, PETSCVIEWERSOCKET)); 318 PetscCall(PetscViewerSocketSetConnection(*lab, machine, port)); 319 PetscFunctionReturn(PETSC_SUCCESS); 320 } 321 322 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems *PetscOptionsObject) 323 { 324 PetscInt def = -1; 325 char sdef[256]; 326 PetscBool tflg; 327 328 PetscFunctionBegin; 329 /* 330 These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they 331 are listed here for the GUI to display 332 */ 333 PetscOptionsHeadBegin(PetscOptionsObject, "Socket PetscViewer Options"); 334 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", sdef, 16, &tflg)); 335 if (tflg) { 336 PetscCall(PetscOptionsStringToInt(sdef, &def)); 337 } else def = PETSCSOCKETDEFAULTPORT; 338 PetscCall(PetscOptionsInt("-viewer_socket_port", "Port number to use for socket", "PetscViewerSocketSetConnection", def, NULL, NULL)); 339 340 PetscCall(PetscOptionsString("-viewer_socket_machine", "Machine to use for socket", "PetscViewerSocketSetConnection", sdef, NULL, sizeof(sdef), NULL)); 341 PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", sdef, sizeof(sdef), &tflg)); 342 if (!tflg) PetscCall(PetscGetHostName(sdef, sizeof(sdef))); 343 PetscOptionsHeadEnd(); 344 PetscFunctionReturn(PETSC_SUCCESS); 345 } 346 347 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip) 348 { 349 PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data; 350 351 PetscFunctionBegin; 352 *skip = vsocket->skipheader; 353 PetscFunctionReturn(PETSC_SUCCESS); 354 } 355 356 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip) 357 { 358 PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data; 359 360 PetscFunctionBegin; 361 vsocket->skipheader = skip; 362 PetscFunctionReturn(PETSC_SUCCESS); 363 } 364 365 PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *); 366 367 /*MC 368 PETSCVIEWERSOCKET - A viewer that writes to a Unix socket 369 370 Level: beginner 371 372 .seealso: [](sec_viewers), `PETSC_VIEWERBINARY`, `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`, 373 `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`, 374 `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`, 375 `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()` 376 M*/ 377 378 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v) 379 { 380 PetscViewer_Socket *vmatlab; 381 382 PetscFunctionBegin; 383 PetscCall(PetscNew(&vmatlab)); 384 vmatlab->port = 0; 385 vmatlab->flowcontrol = 256; /* same default as in PetscViewerCreate_Binary() */ 386 v->data = (void *)vmatlab; 387 v->ops->destroy = PetscViewerDestroy_Socket; 388 v->ops->flush = NULL; 389 v->ops->setfromoptions = PetscViewerSetFromOptions_Socket; 390 391 /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */ 392 PetscCall(PetscObjectChangeTypeName((PetscObject)v, PETSCVIEWERBINARY)); 393 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Socket)); 394 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Socket)); 395 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary)); 396 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) PetscValidCharPointer(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; 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(PETSC_SUCCESS); 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 `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 Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return 490 an error code, it returns NULL if it fails. The `PETSCVIEWERSOCKET` `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: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `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 PetscMPIInt mpi_ierr; 510 PetscBool flg; 511 PetscViewer viewer; 512 MPI_Comm ncomm; 513 514 PetscFunctionBegin; 515 ierr = PetscCommDuplicate(comm, &ncomm, NULL); 516 if (ierr) { 517 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 518 PetscFunctionReturn(NULL); 519 } 520 if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) { 521 mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL); 522 if (mpi_ierr) { 523 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 524 PetscFunctionReturn(NULL); 525 } 526 } 527 mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg); 528 if (mpi_ierr) { 529 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 530 PetscFunctionReturn(NULL); 531 } 532 if (!flg) { /* PetscViewer not yet created */ 533 ierr = PetscViewerSocketOpen(ncomm, NULL, 0, &viewer); 534 if (ierr) { 535 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 536 PetscFunctionReturn(NULL); 537 } 538 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 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 mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer); 544 if (mpi_ierr) { 545 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 546 PetscFunctionReturn(NULL); 547 } 548 } 549 ierr = PetscCommDestroy(&ncomm); 550 if (ierr) { 551 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 552 PetscFunctionReturn(NULL); 553 } 554 PetscFunctionReturn(viewer); 555 } 556