xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 0e03b746557e2551025fde0294144c0532d12f68)
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     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
73   }
74   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
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 Paramater:
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   PetscErrorCode     ierr;
104   PetscBool          flg = PETSC_TRUE;
105   static int         refcnt = 0;
106 
107   PetscFunctionBegin;
108   if (!(hp=gethostbyname(hostname))) {
109     perror("SEND: error gethostbyname: ");
110     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
111   }
112   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
113   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
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");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
120     }
121     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
122 #if defined(PETSC_HAVE_WSAGETLASTERROR)
123       ierr = WSAGetLastError();
124       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
125       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
126       else if (ierr == WSAEISCONN) {
127         (*PetscErrorPrintf)("SEND: socket already connected\n");
128         Sleep((unsigned) 1);
129       } else if (ierr == WSAECONNREFUSED) {
130         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
131         Sleep((unsigned) 1);
132       } else {
133         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
134       }
135 #else
136       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
137       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
138       else if (errno == EISCONN) {
139         (*PetscErrorPrintf)("SEND: socket already connected\n");
140         sleep((unsigned) 1);
141       } else if (errno == ECONNREFUSED) {
142         refcnt++;
143         if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum);
144         ierr = PetscInfo(NULL,"Connection refused in attaching socket, trying again\n");CHKERRQ(ierr);
145         sleep((unsigned) 1);
146       } else {
147         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
148       }
149 #endif
150       flg = PETSC_TRUE;
151 #if defined(PETSC_HAVE_CLOSESOCKET)
152       closesocket(s);
153 #else
154       close(s);
155 #endif
156     } else flg = PETSC_FALSE;
157   }
158   *t = s;
159   PetscFunctionReturn(0);
160 }
161 
162 #define MAXHOSTNAME 100
163 /*@C
164    PetscSocketEstablish - starts a listener on a socket
165 
166    Input Parameters:
167 .    portnumber - the port to wait at
168 
169    Output Parameters:
170 .     ss - the socket to be used with PetscSocketListen()
171 
172     Level: advanced
173 
174 .seealso:   PetscSocketListen(), PetscOpenSocket()
175 
176 @*/
177 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
178 {
179   char               myname[MAXHOSTNAME+1];
180   int                s;
181   PetscErrorCode     ierr;
182   struct sockaddr_in sa;
183   struct hostent     *hp;
184 
185   PetscFunctionBegin;
186   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
187 
188   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
189 
190   hp = gethostbyname(myname);
191   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
192 
193   sa.sin_family = hp->h_addrtype;
194   sa.sin_port   = htons((u_short)portnum);
195 
196   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
197 #if defined(PETSC_HAVE_SO_REUSEADDR)
198   {
199     int optval = 1; /* Turn on the option */
200     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
201   }
202 #endif
203 
204   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
205 #if defined(PETSC_HAVE_WSAGETLASTERROR)
206     ierr = WSAGetLastError();
207     if (ierr != WSAEADDRINUSE) {
208 #else
209     if (errno != EADDRINUSE) {
210 #endif
211       close(s);
212       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
213     }
214   }
215   listen(s,0);
216   *ss = s;
217   return(0);
218 }
219 
220 /*@C
221    PetscSocketListen - Listens at a socket created with PetscSocketEstablish()
222 
223    Input Parameter:
224 .    listenport - obtained with PetscSocketEstablish()
225 
226    Output Parameter:
227 .     t - pass this to read() to read what is passed to this connection
228 
229     Level: advanced
230 
231 .seealso:   PetscSocketEstablish()
232 @*/
233 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
234 {
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   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
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 
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   PetscErrorCode ierr;
308 
309   PetscFunctionBegin;
310   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
311   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
312   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
317 {
318   PetscErrorCode ierr;
319   PetscInt       def = -1;
320   char           sdef[256];
321   PetscBool      tflg;
322 
323   PetscFunctionBegin;
324   /*
325        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
326     are listed here for the GUI to display
327   */
328   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
329   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
330   if (tflg) {
331     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
332   } else def = PETSCSOCKETDEFAULTPORT;
333   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,NULL,NULL);CHKERRQ(ierr);
334 
335   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,0,NULL);CHKERRQ(ierr);
336   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
337   if (!tflg) {
338     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
339   }
340   ierr = PetscOptionsTail();CHKERRQ(ierr);
341   PetscFunctionReturn(0);
342 }
343 
344 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool  *skip)
345 {
346   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
347 
348   PetscFunctionBegin;
349   *skip = vsocket->skipheader;
350   PetscFunctionReturn(0);
351 }
352 
353 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
354 {
355   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
356 
357   PetscFunctionBegin;
358   vsocket->skipheader = skip;
359   PetscFunctionReturn(0);
360 }
361 
362 static PetscErrorCode  PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
363 {
364   PetscFunctionBegin;
365   *fc = 0;
366   PetscFunctionReturn(0);
367 }
368 
369 /*MC
370    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
371 
372 
373 .seealso:  PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
374            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
375            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
376            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
377 
378   Level: beginner
379 M*/
380 
381 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
382 {
383   PetscViewer_Socket *vmatlab;
384   PetscErrorCode     ierr;
385 
386   PetscFunctionBegin;
387   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
388   vmatlab->port          = 0;
389   v->data                = (void*)vmatlab;
390   v->ops->destroy        = PetscViewerDestroy_Socket;
391   v->ops->flush          = NULL;
392   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
393 
394   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
395   ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
396   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);CHKERRQ(ierr);
397   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);CHKERRQ(ierr);
398   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);CHKERRQ(ierr);
399 
400   PetscFunctionReturn(0);
401 }
402 
403 /*@C
404       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
405              viewer is to use
406 
407   Logically Collective on PetscViewer
408 
409   Input Parameters:
410 +   v - viewer to connect
411 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
412              a connection from elsewhere
413 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
414 
415     Level: advanced
416 
417 .seealso: PetscViewerSocketOpen()
418 @*/
419 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
420 {
421   PetscErrorCode     ierr;
422   PetscMPIInt        rank;
423   char               mach[256];
424   PetscBool          tflg;
425   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
426 
427   PetscFunctionBegin;
428   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
429   if (port <= 0) {
430     char portn[16];
431     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
432     if (tflg) {
433       PetscInt pport;
434       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
435       port = (int)pport;
436     } else port = PETSCSOCKETDEFAULTPORT;
437   }
438   if (!machine) {
439     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
440     if (!tflg) {
441       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
442     }
443   } else {
444     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
445   }
446 
447   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
448   if (!rank) {
449     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
450     if (tflg) {
451       int listenport;
452       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
453       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
454       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
455       close(listenport);
456     } else {
457       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
458       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
459     }
460   }
461   PetscFunctionReturn(0);
462 }
463 
464 /* ---------------------------------------------------------------------*/
465 /*
466     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
467   is attached to a communicator, in this case the attribute is a PetscViewer.
468 */
469 PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
470 
471 
472 /*@C
473      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
474 
475      Collective
476 
477      Input Parameter:
478 .    comm - the MPI communicator to share the socket PetscViewer
479 
480      Level: intermediate
481 
482    Options Database Keys:
483    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
484     NULL is passed for machine or PETSC_DEFAULT is passed for port
485 $    -viewer_socket_machine <machine>
486 $    -viewer_socket_port <port>
487 
488    Environmental variables:
489 +   PETSC_VIEWER_SOCKET_PORT - portnumber
490 -   PETSC_VIEWER_SOCKET_MACHINE - machine name
491 
492      Notes:
493      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
494      an error code.  The socket PetscViewer is usually used in the form
495 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
496 
497      Currently the only socket client available is MATLAB. See
498      src/dm/tests/ex12.c and ex12.m for an example of usage.
499 
500      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
501 
502      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
503      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
504      for communicating with a MATLAB Engine
505 
506 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
507           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
508           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
509 @*/
510 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
511 {
512   PetscErrorCode ierr;
513   PetscBool      flg;
514   PetscViewer    viewer;
515   MPI_Comm       ncomm;
516 
517   PetscFunctionBegin;
518   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
519   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
520     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL);
521     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
522   }
523   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
524   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
525   if (!flg) { /* PetscViewer not yet created */
526     ierr = PetscViewerSocketOpen(ncomm,NULL,0,&viewer);
527     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
528     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
529     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
530     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
531     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
532   }
533   ierr = PetscCommDestroy(&ncomm);
534   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
535   PetscFunctionReturn(viewer);
536 }
537 
538