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