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