xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision ecd1d7b800a8e5d54bd2bb04019759f2bc8b1326)
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 M*/
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "PetscViewerCreate_Socket"
400 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
401 {
402   PetscViewer_Socket *vmatlab;
403   PetscErrorCode     ierr;
404 
405   PetscFunctionBegin;
406   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
407   vmatlab->port          = 0;
408   v->data                = (void*)vmatlab;
409   v->ops->destroy        = PetscViewerDestroy_Socket;
410   v->ops->flush          = 0;
411   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
412 
413   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
414   ierr = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
415   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);CHKERRQ(ierr);
416   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);CHKERRQ(ierr);
417   ierr = PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);CHKERRQ(ierr);
418 
419   PetscFunctionReturn(0);
420 }
421 
422 #undef __FUNCT__
423 #define __FUNCT__ "PetscViewerSocketSetConnection"
424 /*@C
425       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
426              viewer is to use
427 
428   Logically Collective on PetscViewer
429 
430   Input Parameters:
431 +   v - viewer to connect
432 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
433              a connection from elsewhere
434 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
435 
436     Level: advanced
437 
438 .seealso: PetscViewerSocketOpen()
439 @*/
440 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
441 {
442   PetscErrorCode     ierr;
443   PetscMPIInt        rank;
444   char               mach[256];
445   PetscBool          tflg;
446   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
447 
448   PetscFunctionBegin;
449   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
450   if (port <= 0) {
451     char portn[16];
452     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
453     if (tflg) {
454       PetscInt pport;
455       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
456       port = (int)pport;
457     } else port = PETSCSOCKETDEFAULTPORT;
458   }
459   if (!machine) {
460     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
461     if (!tflg) {
462       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
463     }
464   } else {
465     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
466   }
467 
468   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
469   if (!rank) {
470     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
471     if (tflg) {
472       int listenport;
473       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
474       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
475       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
476       close(listenport);
477     } else {
478       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
479       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
480     }
481   }
482   PetscFunctionReturn(0);
483 }
484 
485 /* ---------------------------------------------------------------------*/
486 /*
487     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
488   is attached to a communicator, in this case the attribute is a PetscViewer.
489 */
490 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
491 
492 
493 #undef __FUNCT__
494 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
495 /*@C
496      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
497 
498      Collective on MPI_Comm
499 
500      Input Parameter:
501 .    comm - the MPI communicator to share the socket PetscViewer
502 
503      Level: intermediate
504 
505    Options Database Keys:
506    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
507     NULL is passed for machine or PETSC_DEFAULT is passed for port
508 $    -viewer_socket_machine <machine>
509 $    -viewer_socket_port <port>
510 
511    Environmental variables:
512 +   PETSC_VIEWER_SOCKET_PORT portnumber
513 -   PETSC_VIEWER_SOCKET_MACHINE machine name
514 
515      Notes:
516      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
517      an error code.  The socket PetscViewer is usually used in the form
518 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
519 
520      Currently the only socket client available is MATLAB. See
521      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.
522 
523      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
524 
525      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
526      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
527      for communicating with a MATLAB Engine
528 
529 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
530           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
531           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
532 @*/
533 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
534 {
535   PetscErrorCode ierr;
536   PetscBool      flg;
537   PetscViewer    viewer;
538   MPI_Comm       ncomm;
539 
540   PetscFunctionBegin;
541   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
542   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
543     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
544     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
545   }
546   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
547   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
548   if (!flg) { /* PetscViewer not yet created */
549     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
550     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
551     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
552     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
553     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
554     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
555   }
556   ierr = PetscCommDestroy(&ncomm);
557   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
558   PetscFunctionReturn(viewer);
559 }
560 
561