xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 6f15834202b007a5ab068dd8e4ddb895b50471bb)
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(0,"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 on MPI_Comm
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/examples/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    Concepts: MATLAB^sending data
300    Concepts: sockets^sending data
301 
302 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
303           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
304           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
305           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
306 @*/
307 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
308 {
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
313   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
314   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
315   PetscFunctionReturn(0);
316 }
317 
318 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
319 {
320   PetscErrorCode ierr;
321   PetscInt       def = -1;
322   char           sdef[256];
323   PetscBool      tflg;
324 
325   PetscFunctionBegin;
326   /*
327        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
328     are listed here for the GUI to display
329   */
330   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
331   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
332   if (tflg) {
333     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
334   } else def = PETSCSOCKETDEFAULTPORT;
335   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
336 
337   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
338   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
339   if (!tflg) {
340     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
341   }
342   ierr = PetscOptionsTail();CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool  *skip)
347 {
348   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
349 
350   PetscFunctionBegin;
351   *skip = vsocket->skipheader;
352   PetscFunctionReturn(0);
353 }
354 
355 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
356 {
357   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
358 
359   PetscFunctionBegin;
360   vsocket->skipheader = skip;
361   PetscFunctionReturn(0);
362 }
363 
364 static PetscErrorCode  PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
365 {
366   PetscFunctionBegin;
367   *fc = 0;
368   PetscFunctionReturn(0);
369 }
370 
371 /*MC
372    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
373 
374 
375 .seealso:  PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
376            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
377            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
378            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
379 
380   Level: beginner
381 M*/
382 
383 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
384 {
385   PetscViewer_Socket *vmatlab;
386   PetscErrorCode     ierr;
387 
388   PetscFunctionBegin;
389   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
390   vmatlab->port          = 0;
391   v->data                = (void*)vmatlab;
392   v->ops->destroy        = PetscViewerDestroy_Socket;
393   v->ops->flush          = 0;
394   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
395 
396   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
397   ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
398   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);CHKERRQ(ierr);
399   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);CHKERRQ(ierr);
400   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);CHKERRQ(ierr);
401 
402   PetscFunctionReturn(0);
403 }
404 
405 /*@C
406       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
407              viewer is to use
408 
409   Logically Collective on PetscViewer
410 
411   Input Parameters:
412 +   v - viewer to connect
413 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
414              a connection from elsewhere
415 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
416 
417     Level: advanced
418 
419 .seealso: PetscViewerSocketOpen()
420 @*/
421 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
422 {
423   PetscErrorCode     ierr;
424   PetscMPIInt        rank;
425   char               mach[256];
426   PetscBool          tflg;
427   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
428 
429   PetscFunctionBegin;
430   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
431   if (port <= 0) {
432     char portn[16];
433     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
434     if (tflg) {
435       PetscInt pport;
436       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
437       port = (int)pport;
438     } else port = PETSCSOCKETDEFAULTPORT;
439   }
440   if (!machine) {
441     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
442     if (!tflg) {
443       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
444     }
445   } else {
446     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
447   }
448 
449   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
450   if (!rank) {
451     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
452     if (tflg) {
453       int listenport;
454       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
455       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
456       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
457       close(listenport);
458     } else {
459       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
460       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
461     }
462   }
463   PetscFunctionReturn(0);
464 }
465 
466 /* ---------------------------------------------------------------------*/
467 /*
468     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
469   is attached to a communicator, in this case the attribute is a PetscViewer.
470 */
471 PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
472 
473 
474 /*@C
475      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
476 
477      Collective on MPI_Comm
478 
479      Input Parameter:
480 .    comm - the MPI communicator to share the socket PetscViewer
481 
482      Level: intermediate
483 
484    Options Database Keys:
485    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
486     NULL is passed for machine or PETSC_DEFAULT is passed for port
487 $    -viewer_socket_machine <machine>
488 $    -viewer_socket_port <port>
489 
490    Environmental variables:
491 +   PETSC_VIEWER_SOCKET_PORT portnumber
492 -   PETSC_VIEWER_SOCKET_MACHINE machine name
493 
494      Notes:
495      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
496      an error code.  The socket PetscViewer is usually used in the form
497 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
498 
499      Currently the only socket client available is MATLAB. See
500      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
501 
502      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
503 
504      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
505      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
506      for communicating with a MATLAB Engine
507 
508 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
509           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
510           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
511 @*/
512 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
513 {
514   PetscErrorCode ierr;
515   PetscBool      flg;
516   PetscViewer    viewer;
517   MPI_Comm       ncomm;
518 
519   PetscFunctionBegin;
520   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
521   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
522     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
523     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
524   }
525   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
526   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
527   if (!flg) { /* PetscViewer not yet created */
528     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
529     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
530     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
531     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
532     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
533     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
534   }
535   ierr = PetscCommDestroy(&ncomm);
536   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
537   PetscFunctionReturn(viewer);
538 }
539 
540