xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision c3e4dd79e17d3f0a51a524340fae4661630fd09e)
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   PetscErrorCode     ierr;
64 
65   PetscFunctionBegin;
66   if (vmatlab->port) {
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(0);
79 }
80 
81 /*--------------------------------------------------------------*/
82 /*@C
83     PetscSocketOpen - handles connected to an open port where someone is waiting.
84 
85     Input Parameters:
86 +    url - for example www.mcs.anl.gov
87 -    portnum - for example 80
88 
89     Output Parameter:
90 .    t - the socket number
91 
92     Notes:
93     Use close() to close the socket connection
94 
95     Use read() or PetscHTTPRequest() to read from the socket
96 
97     Level: advanced
98 
99 .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()`
100 @*/
101 PetscErrorCode  PetscOpenSocket(const char hostname[],int portnum,int *t)
102 {
103   struct sockaddr_in sa;
104   struct hostent     *hp;
105   int                s = 0;
106   PetscBool          flg = PETSC_TRUE;
107   static int         refcnt = 0;
108 
109   PetscFunctionBegin;
110   if (!(hp=gethostbyname(hostname))) {
111     perror("SEND: error gethostbyname: ");
112     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
113   }
114   PetscCall(PetscMemzero(&sa,sizeof(sa)));
115   PetscCall(PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length));
116 
117   sa.sin_family = hp->h_addrtype;
118   sa.sin_port   = htons((u_short) portnum);
119   while (flg) {
120     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
121       perror("SEND: error socket");  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); 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); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
150       }
151 #endif
152       flg = PETSC_TRUE;
153 #if defined(PETSC_HAVE_CLOSESOCKET)
154       closesocket(s);
155 #else
156       close(s);
157 #endif
158     } else flg = PETSC_FALSE;
159   }
160   *t = s;
161   PetscFunctionReturn(0);
162 }
163 
164 /*@C
165    PetscSocketEstablish - starts a listener on a socket
166 
167    Input Parameters:
168 .    portnumber - the port to wait at
169 
170    Output Parameters:
171 .     ss - the socket to be used with PetscSocketListen()
172 
173     Level: advanced
174 
175 .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
176 
177 @*/
178 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
179 {
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 {
236   struct sockaddr_in isa;
237 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
238   size_t             i;
239 #else
240   int                i;
241 #endif
242 
243   PetscFunctionBegin;
244   /* wait for someone to try to connect */
245   i = sizeof(struct sockaddr_in);
246   PetscCheck((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) >= 0,PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()");
247   PetscFunctionReturn(0);
248 }
249 
250 /*@C
251    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
252 
253    Collective
254 
255    Input Parameters:
256 +  comm - the MPI communicator
257 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
258              a connection from elsewhere
259 -  port - the port to connect to, use PETSC_DEFAULT for the default
260 
261    Output Parameter:
262 .  lab - a context to use when communicating with the server
263 
264    Level: intermediate
265 
266    Notes:
267    Most users should employ the following commands to access the
268    MATLAB PetscViewers
269 $
270 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
271 $    MatView(Mat matrix,PetscViewer viewer)
272 $
273 $                or
274 $
275 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
276 $    VecView(Vec vector,PetscViewer viewer)
277 
278    Options Database Keys:
279    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
280    PETSC_VIEWER_SOCKET_() or if
281     NULL is passed for machine or PETSC_DEFAULT is passed for port
282 $    -viewer_socket_machine <machine>
283 $    -viewer_socket_port <port>
284 
285    Environmental variables:
286 +   PETSC_VIEWER_SOCKET_PORT - portnumber
287 -   PETSC_VIEWER_SOCKET_MACHINE - machine name
288 
289      Currently the only socket client available is MATLAB. See
290      src/dm/tests/ex12.c and ex12.m for an example of usage.
291 
292    Notes:
293     The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
294           use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().
295 
296      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
297      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
298      for communicating with a MATLAB Engine
299 
300 .seealso: `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`,
301           `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`,
302           `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`,
303           `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()`
304 @*/
305 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
306 {
307   PetscFunctionBegin;
308   PetscCall(PetscViewerCreate(comm,lab));
309   PetscCall(PetscViewerSetType(*lab,PETSCVIEWERSOCKET));
310   PetscCall(PetscViewerSocketSetConnection(*lab,machine,port));
311   PetscFunctionReturn(0);
312 }
313 
314 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
315 {
316   PetscInt       def = -1;
317   char           sdef[256];
318   PetscBool      tflg;
319 
320   PetscFunctionBegin;
321   /*
322        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
323     are listed here for the GUI to display
324   */
325   PetscOptionsHeadBegin(PetscOptionsObject,"Socket PetscViewer Options");
326   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg));
327   if (tflg) {
328     PetscCall(PetscOptionsStringToInt(sdef,&def));
329   } else def = PETSCSOCKETDEFAULTPORT;
330   PetscCall(PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,NULL,NULL));
331 
332   PetscCall(PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,sizeof(sdef),NULL));
333   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,sizeof(sdef),&tflg));
334   if (!tflg) {
335     PetscCall(PetscGetHostName(sdef,sizeof(sdef)));
336   }
337   PetscOptionsHeadEnd();
338   PetscFunctionReturn(0);
339 }
340 
341 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool  *skip)
342 {
343   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
344 
345   PetscFunctionBegin;
346   *skip = vsocket->skipheader;
347   PetscFunctionReturn(0);
348 }
349 
350 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
351 {
352   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
353 
354   PetscFunctionBegin;
355   vsocket->skipheader = skip;
356   PetscFunctionReturn(0);
357 }
358 
359 static PetscErrorCode  PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
360 {
361   PetscFunctionBegin;
362   *fc = 0;
363   PetscFunctionReturn(0);
364 }
365 
366 /*MC
367    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
368 
369 .seealso: `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
370           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`,
371           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
372           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
373 
374   Level: beginner
375 M*/
376 
377 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
378 {
379   PetscViewer_Socket *vmatlab;
380 
381   PetscFunctionBegin;
382   PetscCall(PetscNewLog(v,&vmatlab));
383   vmatlab->port          = 0;
384   v->data                = (void*)vmatlab;
385   v->ops->destroy        = PetscViewerDestroy_Socket;
386   v->ops->flush          = NULL;
387   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
388 
389   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
390   PetscCall(PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY));
391   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket));
392   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket));
393   PetscCall(PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket));
394 
395   PetscFunctionReturn(0);
396 }
397 
398 /*@C
399       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
400              viewer is to use
401 
402   Logically Collective on PetscViewer
403 
404   Input Parameters:
405 +   v - viewer to connect
406 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
407              a connection from elsewhere
408 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
409 
410     Level: advanced
411 
412 .seealso: `PetscViewerSocketOpen()`
413 @*/
414 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
415 {
416   PetscMPIInt        rank;
417   char               mach[256];
418   PetscBool          tflg;
419   PetscViewer_Socket *vmatlab;
420 
421   PetscFunctionBegin;
422   PetscValidHeaderSpecific(v,PETSC_VIEWER_CLASSID,1);
423   if (machine) PetscValidCharPointer(machine,2);
424   vmatlab = (PetscViewer_Socket*)v->data;
425   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
426   if (port <= 0) {
427     char portn[16];
428     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg));
429     if (tflg) {
430       PetscInt pport;
431       PetscCall(PetscOptionsStringToInt(portn,&pport));
432       port = (int)pport;
433     } else port = PETSCSOCKETDEFAULTPORT;
434   }
435   if (!machine) {
436     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,sizeof(mach),&tflg));
437     if (!tflg) {
438       PetscCall(PetscGetHostName(mach,sizeof(mach)));
439     }
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(0);
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 socket 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>
482 $    -viewer_socket_port <port>
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 socket 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: `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   PetscBool      flg;
510   PetscViewer    viewer;
511   MPI_Comm       ncomm;
512 
513   PetscFunctionBegin;
514   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
515   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
516     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL);
517     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
518   }
519   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
520   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
521   if (!flg) { /* PetscViewer not yet created */
522     ierr = PetscViewerSocketOpen(ncomm,NULL,0,&viewer);
523     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
524     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
525     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
526     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
527     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
528   }
529   ierr = PetscCommDestroy(&ncomm);
530   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
531   PetscFunctionReturn(viewer);
532 }
533