xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision ee12ae39415b2e672d944cdca066227dadbf8b14)
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 
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   static size_t      MAXHOSTNAME = 100;
180   char               myname[MAXHOSTNAME+1];
181   int                s;
182   PetscErrorCode     ierr;
183   struct sockaddr_in sa;
184   struct hostent     *hp;
185 
186   PetscFunctionBegin;
187   ierr = PetscGetHostName(myname,sizeof(myname));CHKERRQ(ierr);
188 
189   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
190 
191   hp = gethostbyname(myname);
192   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
193 
194   sa.sin_family = hp->h_addrtype;
195   sa.sin_port   = htons((u_short)portnum);
196 
197   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
198 #if defined(PETSC_HAVE_SO_REUSEADDR)
199   {
200     int optval = 1; /* Turn on the option */
201     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
202   }
203 #endif
204 
205   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
206 #if defined(PETSC_HAVE_WSAGETLASTERROR)
207     ierr = WSAGetLastError();
208     if (ierr != WSAEADDRINUSE) {
209 #else
210     if (errno != EADDRINUSE) {
211 #endif
212       close(s);
213       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
214     }
215   }
216   listen(s,0);
217   *ss = s;
218   return(0);
219 }
220 
221 /*@C
222    PetscSocketListen - Listens at a socket created with PetscSocketEstablish()
223 
224    Input Parameter:
225 .    listenport - obtained with PetscSocketEstablish()
226 
227    Output Parameter:
228 .     t - pass this to read() to read what is passed to this connection
229 
230     Level: advanced
231 
232 .seealso:   PetscSocketEstablish()
233 @*/
234 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
235 {
236   struct sockaddr_in isa;
237 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
238   size_t             i;
239 #else
240   int                i;
241 #endif
242 
243   PetscFunctionBegin;
244   /* wait for someone to try to connect */
245   i = sizeof(struct sockaddr_in);
246   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
247   PetscFunctionReturn(0);
248 }
249 
250 /*@C
251    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
252 
253    Collective
254 
255    Input Parameters:
256 +  comm - the MPI communicator
257 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
258              a connection from elsewhere
259 -  port - the port to connect to, use PETSC_DEFAULT for the default
260 
261    Output Parameter:
262 .  lab - a context to use when communicating with the server
263 
264    Level: intermediate
265 
266    Notes:
267    Most users should employ the following commands to access the
268    MATLAB PetscViewers
269 $
270 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
271 $    MatView(Mat matrix,PetscViewer viewer)
272 $
273 $                or
274 $
275 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
276 $    VecView(Vec vector,PetscViewer viewer)
277 
278    Options Database Keys:
279    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
280    PETSC_VIEWER_SOCKET_() or if
281     NULL is passed for machine or PETSC_DEFAULT is passed for port
282 $    -viewer_socket_machine <machine>
283 $    -viewer_socket_port <port>
284 
285    Environmental variables:
286 +   PETSC_VIEWER_SOCKET_PORT - portnumber
287 -   PETSC_VIEWER_SOCKET_MACHINE - machine name
288 
289      Currently the only socket client available is MATLAB. See
290      src/dm/tests/ex12.c and ex12.m for an example of usage.
291 
292    Notes:
293     The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
294           use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().
295 
296      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
297      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
298      for communicating with a MATLAB Engine
299 
300 
301 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
302           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
303           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
304           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
305 @*/
306 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
307 {
308   PetscErrorCode ierr;
309 
310   PetscFunctionBegin;
311   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
312   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
313   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
314   PetscFunctionReturn(0);
315 }
316 
317 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
318 {
319   PetscErrorCode ierr;
320   PetscInt       def = -1;
321   char           sdef[256];
322   PetscBool      tflg;
323 
324   PetscFunctionBegin;
325   /*
326        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
327     are listed here for the GUI to display
328   */
329   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
330   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
331   if (tflg) {
332     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
333   } else def = PETSCSOCKETDEFAULTPORT;
334   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,NULL,NULL);CHKERRQ(ierr);
335 
336   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,sizeof(sdef),NULL);CHKERRQ(ierr);
337   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,sizeof(sdef),&tflg);CHKERRQ(ierr);
338   if (!tflg) {
339     ierr = PetscGetHostName(sdef,sizeof(sdef));CHKERRQ(ierr);
340   }
341   ierr = PetscOptionsTail();CHKERRQ(ierr);
342   PetscFunctionReturn(0);
343 }
344 
345 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool  *skip)
346 {
347   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
348 
349   PetscFunctionBegin;
350   *skip = vsocket->skipheader;
351   PetscFunctionReturn(0);
352 }
353 
354 static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
355 {
356   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
357 
358   PetscFunctionBegin;
359   vsocket->skipheader = skip;
360   PetscFunctionReturn(0);
361 }
362 
363 static PetscErrorCode  PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
364 {
365   PetscFunctionBegin;
366   *fc = 0;
367   PetscFunctionReturn(0);
368 }
369 
370 /*MC
371    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
372 
373 
374 .seealso:  PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
375            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
376            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
377            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
378 
379   Level: beginner
380 M*/
381 
382 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
383 {
384   PetscViewer_Socket *vmatlab;
385   PetscErrorCode     ierr;
386 
387   PetscFunctionBegin;
388   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
389   vmatlab->port          = 0;
390   v->data                = (void*)vmatlab;
391   v->ops->destroy        = PetscViewerDestroy_Socket;
392   v->ops->flush          = NULL;
393   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
394 
395   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
396   ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
397   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);CHKERRQ(ierr);
398   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);CHKERRQ(ierr);
399   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);CHKERRQ(ierr);
400 
401   PetscFunctionReturn(0);
402 }
403 
404 /*@C
405       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
406              viewer is to use
407 
408   Logically Collective on PetscViewer
409 
410   Input Parameters:
411 +   v - viewer to connect
412 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
413              a connection from elsewhere
414 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
415 
416     Level: advanced
417 
418 .seealso: PetscViewerSocketOpen()
419 @*/
420 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
421 {
422   PetscErrorCode     ierr;
423   PetscMPIInt        rank;
424   char               mach[256];
425   PetscBool          tflg;
426   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
427 
428   PetscFunctionBegin;
429   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
430   if (port <= 0) {
431     char portn[16];
432     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
433     if (tflg) {
434       PetscInt pport;
435       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
436       port = (int)pport;
437     } else port = PETSCSOCKETDEFAULTPORT;
438   }
439   if (!machine) {
440     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,sizeof(mach),&tflg);CHKERRQ(ierr);
441     if (!tflg) {
442       ierr = PetscGetHostName(mach,sizeof(mach));CHKERRQ(ierr);
443     }
444   } else {
445     ierr = PetscStrncpy(mach,machine,sizeof(mach));CHKERRQ(ierr);
446   }
447 
448   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRMPI(ierr);
449   if (!rank) {
450     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
451     if (tflg) {
452       int listenport;
453       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
454       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
455       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
456       close(listenport);
457     } else {
458       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
459       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
460     }
461   }
462   PetscFunctionReturn(0);
463 }
464 
465 /* ---------------------------------------------------------------------*/
466 /*
467     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
468   is attached to a communicator, in this case the attribute is a PetscViewer.
469 */
470 PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
471 
472 
473 /*@C
474      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
475 
476      Collective
477 
478      Input Parameter:
479 .    comm - the MPI communicator to share the socket PetscViewer
480 
481      Level: intermediate
482 
483    Options Database Keys:
484    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
485     NULL is passed for machine or PETSC_DEFAULT is passed for port
486 $    -viewer_socket_machine <machine>
487 $    -viewer_socket_port <port>
488 
489    Environmental variables:
490 +   PETSC_VIEWER_SOCKET_PORT - portnumber
491 -   PETSC_VIEWER_SOCKET_MACHINE - machine name
492 
493      Notes:
494      Unlike almost all other PETSc routines, Petsc_VIEWER_SOCKET_ does not return
495      an error code, it returns NULL if it fails. The socket PetscViewer is usually used in the form
496 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
497 
498      Currently the only socket client available is MATLAB. See
499      src/dm/tests/ex12.c and ex12.m for an example of usage.
500 
501      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
502 
503      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
504      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
505      for communicating with a MATLAB Engine
506 
507 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
508           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
509           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
510 @*/
511 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
512 {
513   PetscErrorCode ierr;
514   PetscBool      flg;
515   PetscViewer    viewer;
516   MPI_Comm       ncomm;
517 
518   PetscFunctionBegin;
519   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
520   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
521     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL);
522     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
523   }
524   ierr = MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
525   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
526   if (!flg) { /* PetscViewer not yet created */
527     ierr = PetscViewerSocketOpen(ncomm,NULL,0,&viewer);
528     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
529     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
530     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
531     ierr = MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
532     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
533   }
534   ierr = PetscCommDestroy(&ncomm);
535   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
536   PetscFunctionReturn(viewer);
537 }
538