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