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