xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision feff33ee0b5b037fa8f9f294dede656a2f85cc47)
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: Use close() to close the socket connection
90 
91     Use read() or PetscHTTPRequest() to read from the socket
92 
93     Level: advanced
94 
95 .seealso:   PetscSocketListen(), PetscSocketEstablish(), PetscHTTPRequest(), PetscHTTPSConnect()
96 @*/
97 PetscErrorCode  PetscOpenSocket(const char hostname[],int portnum,int *t)
98 {
99   struct sockaddr_in sa;
100   struct hostent     *hp;
101   int                s = 0;
102   PetscErrorCode     ierr;
103   PetscBool          flg = PETSC_TRUE;
104   static int         refcnt = 0;
105 
106   PetscFunctionBegin;
107   if (!(hp=gethostbyname(hostname))) {
108     perror("SEND: error gethostbyname: ");
109     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
110   }
111   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
112   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
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         if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum);
143         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again\n");CHKERRQ(ierr);
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 #define MAXHOSTNAME 100
162 /*@C
163    PetscSocketEstablish - starts a listener on a socket
164 
165    Input Parameters:
166 .    portnumber - the port to wait at
167 
168    Output Parameters:
169 .     ss - the socket to be used with PetscSocketListen()
170 
171     Level: advanced
172 
173 .seealso:   PetscSocketListen(), PetscOpenSocket()
174 
175 @*/
176 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
177 {
178   char               myname[MAXHOSTNAME+1];
179   int                s;
180   PetscErrorCode     ierr;
181   struct sockaddr_in sa;
182   struct hostent     *hp;
183 
184   PetscFunctionBegin;
185   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
186 
187   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
188 
189   hp = gethostbyname(myname);
190   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
191 
192   sa.sin_family = hp->h_addrtype;
193   sa.sin_port   = htons((u_short)portnum);
194 
195   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
196 #if defined(PETSC_HAVE_SO_REUSEADDR)
197   {
198     int optval = 1; /* Turn on the option */
199     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
200   }
201 #endif
202 
203   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
204 #if defined(PETSC_HAVE_WSAGETLASTERROR)
205     ierr = WSAGetLastError();
206     if (ierr != WSAEADDRINUSE) {
207 #else
208     if (errno != EADDRINUSE) {
209 #endif
210       close(s);
211       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
212     }
213   }
214   listen(s,0);
215   *ss = s;
216   return(0);
217 }
218 
219 /*@C
220    PetscSocketListen - Listens at a socket created with PetscSocketEstablish()
221 
222    Input Parameter:
223 .    listenport - obtained with PetscSocketEstablish()
224 
225    Output Parameter:
226 .     t - pass this to read() to read what is passed to this connection
227 
228     Level: advanced
229 
230 .seealso:   PetscSocketEstablish()
231 @*/
232 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
233 {
234   struct sockaddr_in isa;
235 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
236   size_t             i;
237 #else
238   int                i;
239 #endif
240 
241   PetscFunctionBegin;
242   /* wait for someone to try to connect */
243   i = sizeof(struct sockaddr_in);
244   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
245   PetscFunctionReturn(0);
246 }
247 
248 /*@C
249    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
250 
251    Collective on MPI_Comm
252 
253    Input Parameters:
254 +  comm - the MPI communicator
255 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
256              a connection from elsewhere
257 -  port - the port to connect to, use PETSC_DEFAULT for the default
258 
259    Output Parameter:
260 .  lab - a context to use when communicating with the server
261 
262    Level: intermediate
263 
264    Notes:
265    Most users should employ the following commands to access the
266    MATLAB PetscViewers
267 $
268 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
269 $    MatView(Mat matrix,PetscViewer viewer)
270 $
271 $                or
272 $
273 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
274 $    VecView(Vec vector,PetscViewer viewer)
275 
276    Options Database Keys:
277    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
278    PETSC_VIEWER_SOCKET_() or if
279     NULL is passed for machine or PETSC_DEFAULT is passed for port
280 $    -viewer_socket_machine <machine>
281 $    -viewer_socket_port <port>
282 
283    Environmental variables:
284 +   PETSC_VIEWER_SOCKET_PORT portnumber
285 -   PETSC_VIEWER_SOCKET_MACHINE machine name
286 
287      Currently the only socket client available is MATLAB. See
288      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
289 
290    Notes: 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    Concepts: MATLAB^sending data
298    Concepts: sockets^sending data
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,0,0);CHKERRQ(ierr);
334 
335   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);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          = 0;
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 on MPI_Comm
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/examples/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(0);}
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,0);
521     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
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(0);}
525   if (!flg) { /* PetscViewer not yet created */
526     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
527     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
528     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
529     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
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(0);}
532   }
533   ierr = PetscCommDestroy(&ncomm);
534   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
535   PetscFunctionReturn(viewer);
536 }
537 
538