xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 0b49a1d0cbb4269e5740fcf0f6f0dc40b18c5a16)
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 #undef __FUNCT__
61 #define __FUNCT__ "PetscViewerDestroy_Socket"
62 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
63 {
64   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
65   PetscErrorCode     ierr;
66 
67   PetscFunctionBegin;
68   if (vmatlab->port) {
69 #if defined(PETSC_HAVE_CLOSESOCKET)
70     ierr = closesocket(vmatlab->port);
71 #else
72     ierr = close(vmatlab->port);
73 #endif
74     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
75   }
76   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
77   PetscFunctionReturn(0);
78 }
79 
80 /*--------------------------------------------------------------*/
81 #undef __FUNCT__
82 #define __FUNCT__ "PetscOpenSocket"
83 /*
84     PetscSocketOpen - handles connected to an open port where someone is waiting.
85 
86 .seealso:   PetscSocketListen(), PetscSocketEstablish()
87 */
88 PetscErrorCode  PetscOpenSocket(const char hostname[],int portnum,int *t)
89 {
90   struct sockaddr_in sa;
91   struct hostent     *hp;
92   int                s = 0;
93   PetscErrorCode     ierr;
94   PetscBool          flg = PETSC_TRUE;
95   static int         refcnt = 0;
96 
97   PetscFunctionBegin;
98   if (!(hp=gethostbyname(hostname))) {
99     perror("SEND: error gethostbyname: ");
100     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
101   }
102   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
103   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
104 
105   sa.sin_family = hp->h_addrtype;
106   sa.sin_port   = htons((u_short) portnum);
107   while (flg) {
108     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
109       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
110     }
111     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
112 #if defined(PETSC_HAVE_WSAGETLASTERROR)
113       ierr = WSAGetLastError();
114       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
115       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
116       else if (ierr == WSAEISCONN) {
117         (*PetscErrorPrintf)("SEND: socket already connected\n");
118         Sleep((unsigned) 1);
119       } else if (ierr == WSAECONNREFUSED) {
120         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
121         Sleep((unsigned) 1);
122       } else {
123         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
124       }
125 #else
126       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
127       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
128       else if (errno == EISCONN) {
129         (*PetscErrorPrintf)("SEND: socket already connected\n");
130         sleep((unsigned) 1);
131       } else if (errno == ECONNREFUSED) {
132         refcnt++;
133         if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum);
134         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again\n");CHKERRQ(ierr);
135         sleep((unsigned) 1);
136       } else {
137         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
138       }
139 #endif
140       flg = PETSC_TRUE;
141 #if defined(PETSC_HAVE_CLOSESOCKET)
142       closesocket(s);
143 #else
144       close(s);
145 #endif
146     } else flg = PETSC_FALSE;
147   }
148   *t = s;
149   PetscFunctionReturn(0);
150 }
151 
152 #define MAXHOSTNAME 100
153 #undef __FUNCT__
154 #define __FUNCT__ "PetscSocketEstablish"
155 /*
156    PetscSocketEstablish - starts a listener on a socket
157 
158 .seealso:   PetscSocketListen()
159 */
160 PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
161 {
162   char               myname[MAXHOSTNAME+1];
163   int                s;
164   PetscErrorCode     ierr;
165   struct sockaddr_in sa;
166   struct hostent     *hp;
167 
168   PetscFunctionBegin;
169   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
170 
171   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
172 
173   hp = gethostbyname(myname);
174   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
175 
176   sa.sin_family = hp->h_addrtype;
177   sa.sin_port   = htons((u_short)portnum);
178 
179   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
180 #if defined(PETSC_HAVE_SO_REUSEADDR)
181   {
182     int optval = 1; /* Turn on the option */
183     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
184   }
185 #endif
186 
187   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
188 #if defined(PETSC_HAVE_WSAGETLASTERROR)
189     ierr = WSAGetLastError();
190     if (ierr != WSAEADDRINUSE) {
191 #else
192     if (errno != EADDRINUSE) {
193 #endif
194       close(s);
195       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
196     }
197   }
198   listen(s,0);
199   *ss = s;
200   return(0);
201 }
202 
203 #undef __FUNCT__
204 #define __FUNCT__ "PetscSocketListen"
205 /*
206    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()
207 
208 .seealso:   PetscSocketEstablish()
209 */
210 PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
211 {
212   struct sockaddr_in isa;
213 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
214   size_t             i;
215 #else
216   int                i;
217 #endif
218 
219   PetscFunctionBegin;
220   /* wait for someone to try to connect */
221   i = sizeof(struct sockaddr_in);
222   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
223   PetscFunctionReturn(0);
224 }
225 
226 #undef __FUNCT__
227 #define __FUNCT__ "PetscViewerSocketOpen"
228 /*@C
229    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
230 
231    Collective on MPI_Comm
232 
233    Input Parameters:
234 +  comm - the MPI communicator
235 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
236              a connection from elsewhere
237 -  port - the port to connect to, use PETSC_DEFAULT for the default
238 
239    Output Parameter:
240 .  lab - a context to use when communicating with the server
241 
242    Level: intermediate
243 
244    Notes:
245    Most users should employ the following commands to access the
246    MATLAB PetscViewers
247 $
248 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
249 $    MatView(Mat matrix,PetscViewer viewer)
250 $
251 $                or
252 $
253 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
254 $    VecView(Vec vector,PetscViewer viewer)
255 
256    Options Database Keys:
257    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
258    PETSC_VIEWER_SOCKET_() or if
259     NULL is passed for machine or PETSC_DEFAULT is passed for port
260 $    -viewer_socket_machine <machine>
261 $    -viewer_socket_port <port>
262 
263    Environmental variables:
264 +   PETSC_VIEWER_SOCKET_PORT portnumber
265 -   PETSC_VIEWER_SOCKET_MACHINE machine name
266 
267      Currently the only socket client available is MATLAB. See
268      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
269 
270    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
271           use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().
272 
273      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
274      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
275      for communicating with a MATLAB Engine
276 
277    Concepts: MATLAB^sending data
278    Concepts: sockets^sending data
279 
280 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
281           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
282           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
283           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
284 @*/
285 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
286 {
287   PetscErrorCode ierr;
288 
289   PetscFunctionBegin;
290   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
291   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
292   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
293   PetscFunctionReturn(0);
294 }
295 
296 #undef __FUNCT__
297 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
298 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
299 {
300   PetscErrorCode ierr;
301   PetscInt       def = -1;
302   char           sdef[256];
303   PetscBool      tflg;
304 
305   PetscFunctionBegin;
306   /*
307        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
308     are listed here for the GUI to display
309   */
310   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
311   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
312   if (tflg) {
313     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
314   } else def = PETSCSOCKETDEFAULTPORT;
315   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
316 
317   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
318   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
319   if (!tflg) {
320     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
321   }
322   ierr = PetscOptionsTail();CHKERRQ(ierr);
323   PetscFunctionReturn(0);
324 }
325 
326 /*MC
327    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
328 
329 
330 .seealso:  PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
331            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
332            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
333            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
334 
335 M*/
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "PetscViewerCreate_Socket"
339 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
340 {
341   PetscViewer_Socket *vmatlab;
342   PetscErrorCode     ierr;
343 
344   PetscFunctionBegin;
345   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
346   vmatlab->port          = 0;
347   v->data                = (void*)vmatlab;
348   v->ops->destroy        = PetscViewerDestroy_Socket;
349   v->ops->flush          = 0;
350   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
351 
352   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
353   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "PetscViewerSocketSetConnection"
359 /*@C
360       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
361              viewer is to use
362 
363   Logically Collective on PetscViewer
364 
365   Input Parameters:
366 +   v - viewer to connect
367 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
368              a connection from elsewhere
369 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
370 
371     Level: advanced
372 
373 .seealso: PetscViewerSocketOpen()
374 @*/
375 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
376 {
377   PetscErrorCode     ierr;
378   PetscMPIInt        rank;
379   char               mach[256];
380   PetscBool          tflg;
381   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
382 
383   PetscFunctionBegin;
384   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
385   if (port <= 0) {
386     char portn[16];
387     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
388     if (tflg) {
389       PetscInt pport;
390       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
391       port = (int)pport;
392     } else port = PETSCSOCKETDEFAULTPORT;
393   }
394   if (!machine) {
395     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
396     if (!tflg) {
397       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
398     }
399   } else {
400     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
401   }
402 
403   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
404   if (!rank) {
405     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
406     if (tflg) {
407       int listenport;
408       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
409       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
410       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
411       close(listenport);
412     } else {
413       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
414       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
415     }
416   }
417   PetscFunctionReturn(0);
418 }
419 
420 /* ---------------------------------------------------------------------*/
421 /*
422     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
423   is attached to a communicator, in this case the attribute is a PetscViewer.
424 */
425 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
426 
427 
428 #undef __FUNCT__
429 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
430 /*@C
431      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
432 
433      Collective on MPI_Comm
434 
435      Input Parameter:
436 .    comm - the MPI communicator to share the socket PetscViewer
437 
438      Level: intermediate
439 
440    Options Database Keys:
441    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
442     NULL is passed for machine or PETSC_DEFAULT is passed for port
443 $    -viewer_socket_machine <machine>
444 $    -viewer_socket_port <port>
445 
446    Environmental variables:
447 +   PETSC_VIEWER_SOCKET_PORT portnumber
448 -   PETSC_VIEWER_SOCKET_MACHINE machine name
449 
450      Notes:
451      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
452      an error code.  The socket PetscViewer is usually used in the form
453 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
454 
455      Currently the only socket client available is MATLAB. See
456      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
457 
458      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
459 
460      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
461      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
462      for communicating with a MATLAB Engine
463 
464 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
465           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
466           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
467 @*/
468 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
469 {
470   PetscErrorCode ierr;
471   PetscBool      flg;
472   PetscViewer    viewer;
473   MPI_Comm       ncomm;
474 
475   PetscFunctionBegin;
476   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
477   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
478     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
479     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
480   }
481   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
482   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
483   if (!flg) { /* PetscViewer not yet created */
484     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
485     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
486     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
487     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
488     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
489     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
490   }
491   ierr = PetscCommDestroy(&ncomm);
492   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
493   PetscFunctionReturn(viewer);
494 }
495 
496