Actual source code: send.c


  2: #include <petscsys.h>

  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

 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>

 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

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

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

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

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

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

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

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

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

 96:     Level: advanced

 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;

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

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

171: /*@C
172:    PetscSocketEstablish - starts a listener on a socket

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

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

180:     Level: advanced

182: .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
183: @*/
184: PETSC_INTERN 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;

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

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

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

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

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

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

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

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

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

237:     Level: advanced

239: .seealso: `PetscSocketEstablish()`
240: @*/
241: PETSC_INTERN 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

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

257: /*@C
258:    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.

260:    Collective

262:    Input Parameters:
263: +  comm - the MPI communicator
264: .  machine - the machine the server is running on, use `NULL` for the local machine, use "server" to passively wait for
265:              a connection from elsewhere
266: -  port - the port to connect to, use `PETSC_DEFAULT` for the default

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

271:    Options Database Keys:
272:    For use with  `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`,
273:    `PETSC_VIEWER_SOCKET_()` or if
274:     `NULL` is passed for machine or PETSC_DEFAULT is passed for port
275: +    -viewer_socket_machine <machine> - the machine where the socket is available
276: -    -viewer_socket_port <port> - the socket to conntect to

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

282:    Level: intermediate

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

289:     PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
290:     MatView(Mat matrix,PetscViewer viewer)
291: .ve
292:                 or
293: .vb
294:     PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
295:     VecView(Vec vector,PetscViewer viewer)
296: .ve

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.

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

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

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

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

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

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

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

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

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

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

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

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

370:   Level: beginner

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

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

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;

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

397:   PetscFunctionReturn(PETSC_SUCCESS);
398: }

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

404:   Logically Collective

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

412:     Level: advanced

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;

423:   PetscFunctionBegin;
426:   vmatlab = (PetscViewer_Socket *)v->data;
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:   }

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

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

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

470:      Collective

472:      Input Parameter:
473: .    comm - the MPI communicator to share the  `PETSCVIEWERSOCKET` `PetscViewer`

475:      Level: intermediate

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

483:    Environmental variables:
484: +   `PETSC_VIEWER_SOCKET_PORT` - portnumber
485: -   `PETSC_VIEWER_SOCKET_MACHINE` - machine name

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

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

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

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

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

513:   PetscFunctionBegin;
514:   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
515:   if (ierr) {
516:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
517:     PetscFunctionReturn(NULL);
518:   }
519:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
520:     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL);
521:     if (mpi_ierr) {
522:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
523:       PetscFunctionReturn(NULL);
524:     }
525:   }
526:   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg);
527:   if (mpi_ierr) {
528:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
529:     PetscFunctionReturn(NULL);
530:   }
531:   if (!flg) { /* PetscViewer not yet created */
532:     ierr = PetscViewerSocketOpen(ncomm, NULL, 0, &viewer);
533:     if (ierr) {
534:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
535:       PetscFunctionReturn(NULL);
536:     }
537:     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
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:     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer);
543:     if (mpi_ierr) {
544:       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
545:       PetscFunctionReturn(NULL);
546:     }
547:   }
548:   ierr = PetscCommDestroy(&ncomm);
549:   if (ierr) {
550:     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
551:     PetscFunctionReturn(NULL);
552:   }
553:   PetscFunctionReturn(viewer);
554: }