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