Actual source code: send.c

  1: #include <petscsys.h>

  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

 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>

 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

 58: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
 59: {
 60:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket *)viewer->data;

 62:   PetscFunctionBegin;
 63:   if (vmatlab->port) {
 64:     int ierr;

 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: }

 80: /*@C
 81:   PetscOpenSocket - handles connected to an open port where someone is waiting.

 83:   Input Parameters:
 84: + hostname - for example www.mcs.anl.gov
 85: - portnum  - for example 80

 87:   Output Parameter:
 88: . t - the socket number

 90:   Notes:
 91:   Use close() to close the socket connection

 93:   Use read() or `PetscHTTPRequest()` to read from the socket

 95:   Level: advanced

 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;

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));

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: }

170: /*
171:    PetscSocketEstablish - starts a listener on a socket

173:    Input Parameter:
174: .    portnumber - the port to wait at

176:    Output Parameter:
177: .     ss - the socket to be used with `PetscSocketListen()`

179:     Level: advanced

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;

191:   PetscFunctionBegin;
192:   PetscCall(PetscGetHostName(myname, sizeof(myname)));

194:   PetscCall(PetscMemzero(&sa, sizeof(struct sockaddr_in)));

196:   hp = gethostbyname(myname);
197:   PetscCheck(hp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to get hostent information from system");

199:   sa.sin_family = hp->h_addrtype;
200:   sa.sin_port   = htons((u_short)portnum);

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

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: }

227: /*
228:    PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()`

230:    Input Parameter:
231: .    listenport - obtained with `PetscSocketEstablish()`

233:    Output Parameter:
234: .     t - pass this to read() to read what is passed to this connection

236:     Level: advanced

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

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: }

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.

261:   Collective

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

269:   Output Parameter:
270: . lab - a context to use when communicating with the server

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

279:   Environmental variables:
280: +   `PETSC_VIEWER_SOCKET_MACHINE` - machine name
281: -   `PETSC_VIEWER_SOCKET_PORT` - portnumber

283:   Level: intermediate

285:   Notes:
286:   Most users should employ the following commands to access the
287:   MATLAB `PetscViewer`
288: .vb

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

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.

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()`.

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

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: }

323: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems *PetscOptionsObject)
324: {
325:   PetscInt  def = -1;
326:   char      sdef[256];
327:   PetscBool tflg;

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));

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: }

348: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip)
349: {
350:   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;

352:   PetscFunctionBegin;
353:   *skip = vsocket->skipheader;
354:   PetscFunctionReturn(PETSC_SUCCESS);
355: }

357: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip)
358: {
359:   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;

361:   PetscFunctionBegin;
362:   vsocket->skipheader = skip;
363:   PetscFunctionReturn(PETSC_SUCCESS);
364: }

366: PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *);

368: /*MC
369:    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket

371:   Level: beginner

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*/

379: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
380: {
381:   PetscViewer_Socket *vmatlab;

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;

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));

398:   PetscFunctionReturn(PETSC_SUCCESS);
399: }

401: /*@C
402:   PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
403:   viewer is to use

405:   Logically Collective

407:   Input Parameters:
408: + v       - viewer to connect
409: . machine - host to connect to, use `NULL` for the local machine,use "server" to passively wait for
410:              a connection from elsewhere
411: - port    - the port on the machine one is connecting to, use `PETSC_DEFAULT` for default

413:   Level: advanced

415: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PetscViewerSocketOpen()`
416: @*/
417: PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v, const char machine[], int port)
418: {
419:   PetscMPIInt         rank;
420:   char                mach[256];
421:   PetscBool           tflg;
422:   PetscViewer_Socket *vmatlab;

424:   PetscFunctionBegin;
426:   if (machine) PetscAssertPointer(machine, 2);
427:   vmatlab = (PetscViewer_Socket *)v->data;
429:   if (port <= 0) {
430:     char portn[16];
431:     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", portn, 16, &tflg));
432:     if (tflg) {
433:       PetscInt pport;
434:       PetscCall(PetscOptionsStringToInt(portn, &pport));
435:       port = (int)pport;
436:     } else port = PETSCSOCKETDEFAULTPORT;
437:   }
438:   if (!machine) {
439:     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", mach, sizeof(mach), &tflg));
440:     if (!tflg) PetscCall(PetscGetHostName(mach, sizeof(mach)));
441:   } else {
442:     PetscCall(PetscStrncpy(mach, machine, sizeof(mach)));
443:   }

445:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank));
446:   if (rank == 0) {
447:     PetscCall(PetscStrcmp(mach, "server", &tflg));
448:     if (tflg) {
449:       int listenport = 0;

451:       PetscCall(PetscInfo(v, "Waiting for connection from socket process on port %d\n", port));
452:       PetscCall(PetscSocketEstablish(port, &listenport));
453:       PetscCall(PetscSocketListen(listenport, &vmatlab->port));
454:       close(listenport);
455:     } else {
456:       PetscCall(PetscInfo(v, "Connecting to socket process on port %d machine %s\n", port, mach));
457:       PetscCall(PetscOpenSocket(mach, port, &vmatlab->port));
458:     }
459:   }
460:   PetscFunctionReturn(PETSC_SUCCESS);
461: }

463: /*
464:     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
465:   is attached to a communicator, in this case the attribute is a PetscViewer.
466: */
467: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;

469: /*@C
470:      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.

472:      Collective

474:      Input Parameter:
475: .    comm - the MPI communicator to share the  `PETSCVIEWERSOCKET` `PetscViewer`

477:      Level: intermediate

479:    Options Database Keys:
480:    For use with the default `PETSC_VIEWER_SOCKET_WORLD` or if
481:     `NULL` is passed for machine or `PETSC_DEFAULT` is passed for port
482: +    -viewer_socket_machine <machine> - machine to connect to
483: -    -viewer_socket_port <port> - port to connect to

485:    Environmental variables:
486: +   `PETSC_VIEWER_SOCKET_PORT` - portnumber
487: -   `PETSC_VIEWER_SOCKET_MACHINE` - machine name

489:      Notes:
490:      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

492:      Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return
493:      an error code, it returns NULL if it fails. The  `PETSCVIEWERSOCKET`  `PetscViewer` is usually used in the form
494: $       XXXView(XXX object, PETSC_VIEWER_SOCKET_(comm));

496:      Currently the only socket client available is MATLAB. See
497:      src/dm/tests/ex12.c and ex12.m for an example of usage.

499:      Connects to a waiting socket and stays connected until `PetscViewerDestroy()` is called.

501:      Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
502:      .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
503:      for communicating with a MATLAB Engine

505: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`,
506:           `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`,
507:           `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()`
508: @*/
509: PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
510: {
511:   PetscErrorCode ierr;
512:   PetscMPIInt    mpi_ierr;
513:   PetscBool      flg;
514:   PetscViewer    viewer;
515:   MPI_Comm       ncomm;

517:   PetscFunctionBegin;
518:   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
519:   if (ierr) {
520:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
521:     PetscFunctionReturn(NULL);
522:   }
523:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
524:     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL);
525:     if (mpi_ierr) {
526:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
527:       PetscFunctionReturn(NULL);
528:     }
529:   }
530:   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg);
531:   if (mpi_ierr) {
532:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
533:     PetscFunctionReturn(NULL);
534:   }
535:   if (!flg) { /* PetscViewer not yet created */
536:     ierr                              = PetscViewerSocketOpen(ncomm, NULL, 0, &viewer);
537:     ((PetscObject)viewer)->persistent = PETSC_TRUE;
538:     if (ierr) {
539:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
540:       PetscFunctionReturn(NULL);
541:     }
542:     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
543:     if (ierr) {
544:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
545:       PetscFunctionReturn(NULL);
546:     }
547:     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer);
548:     if (mpi_ierr) {
549:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
550:       PetscFunctionReturn(NULL);
551:     }
552:   }
553:   ierr = PetscCommDestroy(&ncomm);
554:   if (ierr) {
555:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
556:     PetscFunctionReturn(NULL);
557:   }
558:   PetscFunctionReturn(viewer);
559: }