xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision 34fa283e3f79c4e6ee06127db834b156ca11f1ea)
15c6c1daeSBarry Smith 
25c6c1daeSBarry Smith #include <petscsys.h>
35c6c1daeSBarry Smith 
45c6c1daeSBarry Smith #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
55c6c1daeSBarry Smith /* Some systems have inconsistent include files that use but do not
65c6c1daeSBarry Smith    ensure that the following definitions are made */
75c6c1daeSBarry Smith typedef unsigned char  u_char;
85c6c1daeSBarry Smith typedef unsigned short u_short;
95c6c1daeSBarry Smith typedef unsigned short ushort;
105c6c1daeSBarry Smith typedef unsigned int   u_int;
115c6c1daeSBarry Smith typedef unsigned long  u_long;
125c6c1daeSBarry Smith #endif
135c6c1daeSBarry Smith 
145c6c1daeSBarry Smith #include <errno.h>
155c6c1daeSBarry Smith #include <ctype.h>
165c6c1daeSBarry Smith #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
175c6c1daeSBarry Smith   #include <machine/endian.h>
185c6c1daeSBarry Smith #endif
195c6c1daeSBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
205c6c1daeSBarry Smith   #include <unistd.h>
215c6c1daeSBarry Smith #endif
225c6c1daeSBarry Smith #if defined(PETSC_HAVE_SYS_SOCKET_H)
235c6c1daeSBarry Smith   #include <sys/socket.h>
245c6c1daeSBarry Smith #endif
255c6c1daeSBarry Smith #if defined(PETSC_HAVE_SYS_WAIT_H)
265c6c1daeSBarry Smith   #include <sys/wait.h>
275c6c1daeSBarry Smith #endif
285c6c1daeSBarry Smith #if defined(PETSC_HAVE_NETINET_IN_H)
295c6c1daeSBarry Smith   #include <netinet/in.h>
305c6c1daeSBarry Smith #endif
315c6c1daeSBarry Smith #if defined(PETSC_HAVE_NETDB_H)
325c6c1daeSBarry Smith   #include <netdb.h>
335c6c1daeSBarry Smith #endif
345c6c1daeSBarry Smith #if defined(PETSC_HAVE_FCNTL_H)
355c6c1daeSBarry Smith   #include <fcntl.h>
365c6c1daeSBarry Smith #endif
375c6c1daeSBarry Smith #if defined(PETSC_HAVE_IO_H)
385c6c1daeSBarry Smith   #include <io.h>
395c6c1daeSBarry Smith #endif
405c6c1daeSBarry Smith #if defined(PETSC_HAVE_WINSOCK2_H)
415c6c1daeSBarry Smith   #include <Winsock2.h>
425c6c1daeSBarry Smith #endif
435c6c1daeSBarry Smith #include <sys/stat.h>
445c6c1daeSBarry Smith #include <../src/sys/classes/viewer/impls/socket/socket.h>
455c6c1daeSBarry Smith 
465c6c1daeSBarry Smith #if defined(PETSC_NEED_CLOSE_PROTO)
478cc058d9SJed Brown PETSC_EXTERN int close(int);
485c6c1daeSBarry Smith #endif
495c6c1daeSBarry Smith #if defined(PETSC_NEED_SOCKET_PROTO)
508cc058d9SJed Brown PETSC_EXTERN int socket(int, int, int);
515c6c1daeSBarry Smith #endif
525c6c1daeSBarry Smith #if defined(PETSC_NEED_SLEEP_PROTO)
538cc058d9SJed Brown PETSC_EXTERN int sleep(unsigned);
545c6c1daeSBarry Smith #endif
555c6c1daeSBarry Smith #if defined(PETSC_NEED_CONNECT_PROTO)
568cc058d9SJed Brown PETSC_EXTERN int connect(int, struct sockaddr *, int);
575c6c1daeSBarry Smith #endif
585c6c1daeSBarry Smith 
59d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
60d71ae5a4SJacob Faibussowitsch {
615c6c1daeSBarry Smith   PetscViewer_Socket *vmatlab = (PetscViewer_Socket *)viewer->data;
625c6c1daeSBarry Smith 
635c6c1daeSBarry Smith   PetscFunctionBegin;
645c6c1daeSBarry Smith   if (vmatlab->port) {
653ba16761SJacob Faibussowitsch     int ierr;
663ba16761SJacob Faibussowitsch 
675c6c1daeSBarry Smith #if defined(PETSC_HAVE_CLOSESOCKET)
685c6c1daeSBarry Smith     ierr = closesocket(vmatlab->port);
695c6c1daeSBarry Smith #else
705c6c1daeSBarry Smith     ierr = close(vmatlab->port);
715c6c1daeSBarry Smith #endif
7228b400f6SJacob Faibussowitsch     PetscCheck(!ierr, PETSC_COMM_SELF, PETSC_ERR_SYS, "System error closing socket");
735c6c1daeSBarry Smith   }
749566063dSJacob Faibussowitsch   PetscCall(PetscFree(vmatlab));
752e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinarySetSkipHeader_C", NULL));
762e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetSkipHeader_C", NULL));
772e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetFlowControl_C", NULL));
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
795c6c1daeSBarry Smith }
805c6c1daeSBarry Smith 
814683183fSBarry Smith /*@C
82aec76313SJacob Faibussowitsch   PetscOpenSocket - handles connected to an open port where someone is waiting.
835c6c1daeSBarry Smith 
844683183fSBarry Smith   Input Parameters:
85aec76313SJacob Faibussowitsch + hostname - for example www.mcs.anl.gov
864683183fSBarry Smith - portnum  - for example 80
874683183fSBarry Smith 
8801d2d390SJose E. Roman   Output Parameter:
894683183fSBarry Smith . t - the socket number
904683183fSBarry Smith 
9195452b02SPatrick Sanan   Notes:
9295452b02SPatrick Sanan   Use close() to close the socket connection
934683183fSBarry Smith 
94811af0c4SBarry Smith   Use read() or `PetscHTTPRequest()` to read from the socket
954683183fSBarry Smith 
964683183fSBarry Smith   Level: advanced
974683183fSBarry Smith 
98db781477SPatrick Sanan .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()`
994683183fSBarry Smith @*/
100d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscOpenSocket(const char hostname[], int portnum, int *t)
101d71ae5a4SJacob Faibussowitsch {
1025c6c1daeSBarry Smith   struct sockaddr_in sa;
1035c6c1daeSBarry Smith   struct hostent    *hp;
1045c6c1daeSBarry Smith   int                s      = 0;
1055c6c1daeSBarry Smith   PetscBool          flg    = PETSC_TRUE;
1064a285bdaSBarry Smith   static int         refcnt = 0;
1075c6c1daeSBarry Smith 
1085c6c1daeSBarry Smith   PetscFunctionBegin;
1095c6c1daeSBarry Smith   if (!(hp = gethostbyname(hostname))) {
1105c6c1daeSBarry Smith     perror("SEND: error gethostbyname: ");
11198921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error open connection to %s", hostname);
1125c6c1daeSBarry Smith   }
1139566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&sa, sizeof(sa)));
1149566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(&sa.sin_addr, hp->h_addr_list[0], hp->h_length));
1155c6c1daeSBarry Smith 
1165c6c1daeSBarry Smith   sa.sin_family = hp->h_addrtype;
1175c6c1daeSBarry Smith   sa.sin_port   = htons((u_short)portnum);
1185c6c1daeSBarry Smith   while (flg) {
1195c6c1daeSBarry Smith     if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
1209371c9d4SSatish Balay       perror("SEND: error socket");
1219371c9d4SSatish Balay       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
1225c6c1daeSBarry Smith     }
1235c6c1daeSBarry Smith     if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
1245c6c1daeSBarry Smith #if defined(PETSC_HAVE_WSAGETLASTERROR)
1255c6c1daeSBarry Smith       ierr = WSAGetLastError();
126a297a907SKarl Rupp       if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
127a297a907SKarl Rupp       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
128a297a907SKarl Rupp       else if (ierr == WSAEISCONN) {
1295c6c1daeSBarry Smith         (*PetscErrorPrintf)("SEND: socket already connected\n");
1305c6c1daeSBarry Smith         Sleep((unsigned)1);
1315c6c1daeSBarry Smith       } else if (ierr == WSAECONNREFUSED) {
1325c6c1daeSBarry Smith         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
1335c6c1daeSBarry Smith         Sleep((unsigned)1);
1345c6c1daeSBarry Smith       } else {
1359371c9d4SSatish Balay         perror(NULL);
1369371c9d4SSatish Balay         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
1375c6c1daeSBarry Smith       }
1385c6c1daeSBarry Smith #else
1393ba16761SJacob Faibussowitsch       if (errno == EADDRINUSE) {
1403ba16761SJacob Faibussowitsch         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: address is in use\n");
1413ba16761SJacob Faibussowitsch         (void)ierr;
1423ba16761SJacob Faibussowitsch       } else if (errno == EALREADY) {
1433ba16761SJacob Faibussowitsch         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
1443ba16761SJacob Faibussowitsch         (void)ierr;
1453ba16761SJacob Faibussowitsch       } else if (errno == EISCONN) {
1463ba16761SJacob Faibussowitsch         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket already connected\n");
1473ba16761SJacob Faibussowitsch         (void)ierr;
1485c6c1daeSBarry Smith         sleep((unsigned)1);
1495c6c1daeSBarry Smith       } else if (errno == ECONNREFUSED) {
1504a285bdaSBarry Smith         refcnt++;
15108401ef6SPierre Jolivet         PetscCheck(refcnt <= 5, PETSC_COMM_SELF, PETSC_ERR_SYS, "Connection refused by remote host %s port %d", hostname, portnum);
1529566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Connection refused in attaching socket, trying again\n"));
1535c6c1daeSBarry Smith         sleep((unsigned)1);
1545c6c1daeSBarry Smith       } else {
1559371c9d4SSatish Balay         perror(NULL);
1569371c9d4SSatish Balay         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
1575c6c1daeSBarry Smith       }
1585c6c1daeSBarry Smith #endif
1595c6c1daeSBarry Smith       flg = PETSC_TRUE;
1605c6c1daeSBarry Smith #if defined(PETSC_HAVE_CLOSESOCKET)
1615c6c1daeSBarry Smith       closesocket(s);
1625c6c1daeSBarry Smith #else
1635c6c1daeSBarry Smith       close(s);
1645c6c1daeSBarry Smith #endif
165a297a907SKarl Rupp     } else flg = PETSC_FALSE;
1665c6c1daeSBarry Smith   }
1675c6c1daeSBarry Smith   *t = s;
1683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1695c6c1daeSBarry Smith }
1705c6c1daeSBarry Smith 
17110450e9eSJacob Faibussowitsch /*
1725c6c1daeSBarry Smith    PetscSocketEstablish - starts a listener on a socket
1735c6c1daeSBarry Smith 
1742fe279fdSBarry Smith    Input Parameter:
1754683183fSBarry Smith .    portnumber - the port to wait at
1764683183fSBarry Smith 
1772fe279fdSBarry Smith    Output Parameter:
178811af0c4SBarry Smith .     ss - the socket to be used with `PetscSocketListen()`
1794683183fSBarry Smith 
1804683183fSBarry Smith     Level: advanced
1814683183fSBarry Smith 
182db781477SPatrick Sanan .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
18310450e9eSJacob Faibussowitsch */
18410450e9eSJacob Faibussowitsch static PetscErrorCode PetscSocketEstablish(int portnum, int *ss)
185d71ae5a4SJacob Faibussowitsch {
186589a23caSBarry Smith   static size_t      MAXHOSTNAME = 100;
1875c6c1daeSBarry Smith   char               myname[MAXHOSTNAME + 1];
1885c6c1daeSBarry Smith   int                s;
1895c6c1daeSBarry Smith   struct sockaddr_in sa;
1905c6c1daeSBarry Smith   struct hostent    *hp;
1915c6c1daeSBarry Smith 
1925c6c1daeSBarry Smith   PetscFunctionBegin;
1939566063dSJacob Faibussowitsch   PetscCall(PetscGetHostName(myname, sizeof(myname)));
1945c6c1daeSBarry Smith 
1959566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&sa, sizeof(struct sockaddr_in)));
1965c6c1daeSBarry Smith 
1975c6c1daeSBarry Smith   hp = gethostbyname(myname);
19828b400f6SJacob Faibussowitsch   PetscCheck(hp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to get hostent information from system");
1995c6c1daeSBarry Smith 
2005c6c1daeSBarry Smith   sa.sin_family = hp->h_addrtype;
2015c6c1daeSBarry Smith   sa.sin_port   = htons((u_short)portnum);
2025c6c1daeSBarry Smith 
203cc73adaaSBarry Smith   PetscCheck((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Error running socket() command");
2045c6c1daeSBarry Smith #if defined(PETSC_HAVE_SO_REUSEADDR)
2055c6c1daeSBarry Smith   {
2065c6c1daeSBarry Smith     int optval = 1; /* Turn on the option */
2073ba16761SJacob Faibussowitsch     int ret    = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
2083ba16761SJacob Faibussowitsch     PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "setsockopt() failed with error code %d", ret);
2095c6c1daeSBarry Smith   }
2105c6c1daeSBarry Smith #endif
2115c6c1daeSBarry Smith 
2125c6c1daeSBarry Smith   while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
2135c6c1daeSBarry Smith #if defined(PETSC_HAVE_WSAGETLASTERROR)
2145c6c1daeSBarry Smith     ierr = WSAGetLastError();
2155c6c1daeSBarry Smith     if (ierr != WSAEADDRINUSE) {
2165c6c1daeSBarry Smith #else
2175c6c1daeSBarry Smith     if (errno != EADDRINUSE) {
2185c6c1daeSBarry Smith #endif
2195c6c1daeSBarry Smith       close(s);
2205c6c1daeSBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "Error from bind()");
2215c6c1daeSBarry Smith     }
2225c6c1daeSBarry Smith   }
2235c6c1daeSBarry Smith   listen(s, 0);
2245c6c1daeSBarry Smith   *ss = s;
2253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2265c6c1daeSBarry Smith }
2275c6c1daeSBarry Smith 
22810450e9eSJacob Faibussowitsch /*
229811af0c4SBarry Smith    PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()`
2304683183fSBarry Smith 
2314683183fSBarry Smith    Input Parameter:
232811af0c4SBarry Smith .    listenport - obtained with `PetscSocketEstablish()`
2334683183fSBarry Smith 
2344683183fSBarry Smith    Output Parameter:
2354683183fSBarry Smith .     t - pass this to read() to read what is passed to this connection
2364683183fSBarry Smith 
2374683183fSBarry Smith     Level: advanced
2385c6c1daeSBarry Smith 
239db781477SPatrick Sanan .seealso: `PetscSocketEstablish()`
24010450e9eSJacob Faibussowitsch */
24110450e9eSJacob Faibussowitsch static PetscErrorCode PetscSocketListen(int listenport, int *t)
242d71ae5a4SJacob Faibussowitsch {
2435c6c1daeSBarry Smith   struct sockaddr_in isa;
2445c6c1daeSBarry Smith #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
2455c6c1daeSBarry Smith   size_t i;
2465c6c1daeSBarry Smith #else
2475c6c1daeSBarry Smith   int i;
2485c6c1daeSBarry Smith #endif
2495c6c1daeSBarry Smith 
2505c6c1daeSBarry Smith   PetscFunctionBegin;
2515c6c1daeSBarry Smith   /* wait for someone to try to connect */
2525c6c1daeSBarry Smith   i = sizeof(struct sockaddr_in);
253cc73adaaSBarry Smith   PetscCheck((*t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "error from accept()");
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2555c6c1daeSBarry Smith }
2565c6c1daeSBarry Smith 
25710450e9eSJacob Faibussowitsch // "Unknown section 'Environmental Variables'"
25810450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
2595c6c1daeSBarry Smith /*@C
260a30fc760SBarry Smith   PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
2615c6c1daeSBarry Smith 
262d083f849SBarry Smith   Collective
2635c6c1daeSBarry Smith 
2645c6c1daeSBarry Smith   Input Parameters:
2655c6c1daeSBarry Smith + comm    - the MPI communicator
2663f423023SBarry Smith . machine - the machine the server is running on, use `NULL` for the local machine, use "server" to passively wait for
2675c6c1daeSBarry Smith              a connection from elsewhere
268811af0c4SBarry Smith - port    - the port to connect to, use `PETSC_DEFAULT` for the default
2695c6c1daeSBarry Smith 
2705c6c1daeSBarry Smith   Output Parameter:
2715c6c1daeSBarry Smith . lab - a context to use when communicating with the server
2725c6c1daeSBarry Smith 
273811af0c4SBarry Smith   Options Database Keys:
274811af0c4SBarry Smith    For use with  `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`,
275811af0c4SBarry Smith    `PETSC_VIEWER_SOCKET_()` or if
2763f423023SBarry Smith     `NULL` is passed for machine or PETSC_DEFAULT is passed for port
2773f423023SBarry Smith + -viewer_socket_machine <machine> - the machine where the socket is available
2783f423023SBarry Smith - -viewer_socket_port <port>       - the socket to conntect to
279811af0c4SBarry Smith 
280811af0c4SBarry Smith   Environmental variables:
2813f423023SBarry Smith +   `PETSC_VIEWER_SOCKET_MACHINE` - machine name
2823f423023SBarry Smith -   `PETSC_VIEWER_SOCKET_PORT` - portnumber
283811af0c4SBarry Smith 
2845c6c1daeSBarry Smith   Level: intermediate
2855c6c1daeSBarry Smith 
2865c6c1daeSBarry Smith   Notes:
2875c6c1daeSBarry Smith   Most users should employ the following commands to access the
288811af0c4SBarry Smith   MATLAB `PetscViewer`
2893f423023SBarry Smith .vb
2903f423023SBarry Smith 
2913f423023SBarry Smith     PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
2923f423023SBarry Smith     MatView(Mat matrix,PetscViewer viewer)
2933f423023SBarry Smith .ve
2943f423023SBarry Smith   or
2953f423023SBarry Smith .vb
2963f423023SBarry Smith     PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
2973f423023SBarry Smith     VecView(Vec vector,PetscViewer viewer)
2983f423023SBarry Smith .ve
2995c6c1daeSBarry Smith 
300750b007cSBarry Smith   Currently the only socket client available is MATLAB, PETSc must be configured with --with-matlab for this client. See
301c4762a1bSJed Brown   src/dm/tests/ex12.c and ex12.m for an example of usage.
3025c6c1daeSBarry Smith 
30395452b02SPatrick Sanan   The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
304811af0c4SBarry Smith   use `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`, `PetscViewerBinarWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`.
305a30fc760SBarry Smith 
306811af0c4SBarry Smith   Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
307811af0c4SBarry Smith   .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
308a30fc760SBarry Smith   for communicating with a MATLAB Engine
3095c6c1daeSBarry Smith 
310d1f92df0SBarry Smith .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSCVIEWERSOCKET`, `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`,
311db781477SPatrick Sanan           `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`,
312db781477SPatrick Sanan           `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`,
313db781477SPatrick Sanan           `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()`
3145c6c1daeSBarry Smith @*/
315d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm, const char machine[], int port, PetscViewer *lab)
316d71ae5a4SJacob Faibussowitsch {
3175c6c1daeSBarry Smith   PetscFunctionBegin;
3189566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, lab));
3199566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERSOCKET));
3209566063dSJacob Faibussowitsch   PetscCall(PetscViewerSocketSetConnection(*lab, machine, port));
3213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3225c6c1daeSBarry Smith }
3235c6c1daeSBarry Smith 
324d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems *PetscOptionsObject)
325d71ae5a4SJacob Faibussowitsch {
3265c6c1daeSBarry Smith   PetscInt  def = -1;
3275c6c1daeSBarry Smith   char      sdef[256];
3285c6c1daeSBarry Smith   PetscBool tflg;
3295c6c1daeSBarry Smith 
3305c6c1daeSBarry Smith   PetscFunctionBegin;
3315c6c1daeSBarry Smith   /*
3325c6c1daeSBarry Smith        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
3335c6c1daeSBarry Smith     are listed here for the GUI to display
3345c6c1daeSBarry Smith   */
335d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Socket PetscViewer Options");
3369566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", sdef, 16, &tflg));
3375c6c1daeSBarry Smith   if (tflg) {
3389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsStringToInt(sdef, &def));
339a297a907SKarl Rupp   } else def = PETSCSOCKETDEFAULTPORT;
3409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-viewer_socket_port", "Port number to use for socket", "PetscViewerSocketSetConnection", def, NULL, NULL));
3415c6c1daeSBarry Smith 
3429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-viewer_socket_machine", "Machine to use for socket", "PetscViewerSocketSetConnection", sdef, NULL, sizeof(sdef), NULL));
3439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", sdef, sizeof(sdef), &tflg));
34448a46eb9SPierre Jolivet   if (!tflg) PetscCall(PetscGetHostName(sdef, sizeof(sdef)));
345d0609cedSBarry Smith   PetscOptionsHeadEnd();
3463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3475c6c1daeSBarry Smith }
3485c6c1daeSBarry Smith 
349d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip)
350d71ae5a4SJacob Faibussowitsch {
3514c9f2355SSatish Balay   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
3524c9f2355SSatish Balay 
3534c9f2355SSatish Balay   PetscFunctionBegin;
3544c9f2355SSatish Balay   *skip = vsocket->skipheader;
3553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3564c9f2355SSatish Balay }
3574c9f2355SSatish Balay 
358d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip)
359d71ae5a4SJacob Faibussowitsch {
3604c9f2355SSatish Balay   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
3614c9f2355SSatish Balay 
3624c9f2355SSatish Balay   PetscFunctionBegin;
3634c9f2355SSatish Balay   vsocket->skipheader = skip;
3643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3654c9f2355SSatish Balay }
3664c9f2355SSatish Balay 
36776667918SBarry Smith PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *);
3684c9f2355SSatish Balay 
3698556b5ebSBarry Smith /*MC
3708556b5ebSBarry Smith    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
3718556b5ebSBarry Smith 
372811af0c4SBarry Smith   Level: beginner
373811af0c4SBarry Smith 
374d1f92df0SBarry Smith .seealso: [](sec_viewers), `PETSC_VIEWERBINARY`, `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
375db781477SPatrick Sanan           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`,
376db781477SPatrick Sanan           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
377db781477SPatrick Sanan           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
3788556b5ebSBarry Smith M*/
3798556b5ebSBarry Smith 
380d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
381d71ae5a4SJacob Faibussowitsch {
3825c6c1daeSBarry Smith   PetscViewer_Socket *vmatlab;
3835c6c1daeSBarry Smith 
3845c6c1daeSBarry Smith   PetscFunctionBegin;
3854dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&vmatlab));
3865c6c1daeSBarry Smith   vmatlab->port          = 0;
38776667918SBarry Smith   vmatlab->flowcontrol   = 256; /* same default as in PetscViewerCreate_Binary() */
3885c6c1daeSBarry Smith   v->data                = (void *)vmatlab;
3895c6c1daeSBarry Smith   v->ops->destroy        = PetscViewerDestroy_Socket;
39002c9f0b5SLisandro Dalcin   v->ops->flush          = NULL;
3915c6c1daeSBarry Smith   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
3925c6c1daeSBarry Smith 
3935c6c1daeSBarry Smith   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
3949566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)v, PETSCVIEWERBINARY));
3959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Socket));
3969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Socket));
39776667918SBarry Smith   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary));
3984c9f2355SSatish Balay 
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4005c6c1daeSBarry Smith }
4015c6c1daeSBarry Smith 
4025c6c1daeSBarry Smith /*@C
4035c6c1daeSBarry Smith   PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
4045c6c1daeSBarry Smith   viewer is to use
4055c6c1daeSBarry Smith 
406c3339decSBarry Smith   Logically Collective
4075c6c1daeSBarry Smith 
4085c6c1daeSBarry Smith   Input Parameters:
4095c6c1daeSBarry Smith + v       - viewer to connect
4103f423023SBarry Smith . machine - host to connect to, use `NULL` for the local machine,use "server" to passively wait for
4115c6c1daeSBarry Smith              a connection from elsewhere
412811af0c4SBarry Smith - port    - the port on the machine one is connecting to, use `PETSC_DEFAULT` for default
4135c6c1daeSBarry Smith 
4145c6c1daeSBarry Smith   Level: advanced
4155c6c1daeSBarry Smith 
416d1f92df0SBarry Smith .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PetscViewerSocketOpen()`
4175c6c1daeSBarry Smith @*/
418d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v, const char machine[], int port)
419d71ae5a4SJacob Faibussowitsch {
4205c6c1daeSBarry Smith   PetscMPIInt         rank;
4215c6c1daeSBarry Smith   char                mach[256];
4225c6c1daeSBarry Smith   PetscBool           tflg;
4233ca90d2dSJacob Faibussowitsch   PetscViewer_Socket *vmatlab;
4245c6c1daeSBarry Smith 
4255c6c1daeSBarry Smith   PetscFunctionBegin;
4263ca90d2dSJacob Faibussowitsch   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
4274f572ea9SToby Isaac   if (machine) PetscAssertPointer(machine, 2);
4283ca90d2dSJacob Faibussowitsch   vmatlab = (PetscViewer_Socket *)v->data;
4295c6c1daeSBarry Smith   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
4305c6c1daeSBarry Smith   if (port <= 0) {
4315c6c1daeSBarry Smith     char portn[16];
4329566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", portn, 16, &tflg));
4335c6c1daeSBarry Smith     if (tflg) {
4345c6c1daeSBarry Smith       PetscInt pport;
4359566063dSJacob Faibussowitsch       PetscCall(PetscOptionsStringToInt(portn, &pport));
4365c6c1daeSBarry Smith       port = (int)pport;
437a297a907SKarl Rupp     } else port = PETSCSOCKETDEFAULTPORT;
4385c6c1daeSBarry Smith   }
4395c6c1daeSBarry Smith   if (!machine) {
4409566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", mach, sizeof(mach), &tflg));
44148a46eb9SPierre Jolivet     if (!tflg) PetscCall(PetscGetHostName(mach, sizeof(mach)));
4425c6c1daeSBarry Smith   } else {
4439566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(mach, machine, sizeof(mach)));
4445c6c1daeSBarry Smith   }
4455c6c1daeSBarry Smith 
4469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank));
447dd400576SPatrick Sanan   if (rank == 0) {
4489566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(mach, "server", &tflg));
4495c6c1daeSBarry Smith     if (tflg) {
45010450e9eSJacob Faibussowitsch       int listenport = 0;
45110450e9eSJacob Faibussowitsch 
4529566063dSJacob Faibussowitsch       PetscCall(PetscInfo(v, "Waiting for connection from socket process on port %d\n", port));
4539566063dSJacob Faibussowitsch       PetscCall(PetscSocketEstablish(port, &listenport));
4549566063dSJacob Faibussowitsch       PetscCall(PetscSocketListen(listenport, &vmatlab->port));
4555c6c1daeSBarry Smith       close(listenport);
4565c6c1daeSBarry Smith     } else {
4579566063dSJacob Faibussowitsch       PetscCall(PetscInfo(v, "Connecting to socket process on port %d machine %s\n", port, mach));
4589566063dSJacob Faibussowitsch       PetscCall(PetscOpenSocket(mach, port, &vmatlab->port));
4595c6c1daeSBarry Smith     }
4605c6c1daeSBarry Smith   }
4613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4625c6c1daeSBarry Smith }
4635c6c1daeSBarry Smith 
4645c6c1daeSBarry Smith /*
4655c6c1daeSBarry Smith     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
4665c6c1daeSBarry Smith   is attached to a communicator, in this case the attribute is a PetscViewer.
4675c6c1daeSBarry Smith */
468d4c7638eSBarry Smith PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
4695c6c1daeSBarry Smith 
4705c6c1daeSBarry Smith /*@C
4715c6c1daeSBarry Smith      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
4725c6c1daeSBarry Smith 
473d083f849SBarry Smith      Collective
4745c6c1daeSBarry Smith 
4755c6c1daeSBarry Smith      Input Parameter:
476811af0c4SBarry Smith .    comm - the MPI communicator to share the  `PETSCVIEWERSOCKET` `PetscViewer`
4775c6c1daeSBarry Smith 
4785c6c1daeSBarry Smith      Level: intermediate
4795c6c1daeSBarry Smith 
4805c6c1daeSBarry Smith    Options Database Keys:
481811af0c4SBarry Smith    For use with the default `PETSC_VIEWER_SOCKET_WORLD` or if
4823f423023SBarry Smith     `NULL` is passed for machine or `PETSC_DEFAULT` is passed for port
483d1f92df0SBarry Smith +    -viewer_socket_machine <machine> - machine to connect to
484d1f92df0SBarry Smith -    -viewer_socket_port <port> - port to connect to
4855c6c1daeSBarry Smith 
4865c6c1daeSBarry Smith    Environmental variables:
487811af0c4SBarry Smith +   `PETSC_VIEWER_SOCKET_PORT` - portnumber
488811af0c4SBarry Smith -   `PETSC_VIEWER_SOCKET_MACHINE` - machine name
4895c6c1daeSBarry Smith 
4905c6c1daeSBarry Smith      Notes:
491*34fa283eSBarry Smith      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
492*34fa283eSBarry Smith 
493811af0c4SBarry Smith      Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return
494811af0c4SBarry Smith      an error code, it returns NULL if it fails. The  `PETSCVIEWERSOCKET`  `PetscViewer` is usually used in the form
4955c6c1daeSBarry Smith $       XXXView(XXX object, PETSC_VIEWER_SOCKET_(comm));
4965c6c1daeSBarry Smith 
4975c6c1daeSBarry Smith      Currently the only socket client available is MATLAB. See
498c4762a1bSJed Brown      src/dm/tests/ex12.c and ex12.m for an example of usage.
4995c6c1daeSBarry Smith 
500811af0c4SBarry Smith      Connects to a waiting socket and stays connected until `PetscViewerDestroy()` is called.
5015c6c1daeSBarry Smith 
502811af0c4SBarry Smith      Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
503811af0c4SBarry Smith      .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
504a30fc760SBarry Smith      for communicating with a MATLAB Engine
5055c6c1daeSBarry Smith 
506d1f92df0SBarry Smith .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`,
507db781477SPatrick Sanan           `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`,
508db781477SPatrick Sanan           `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()`
5095c6c1daeSBarry Smith @*/
510d71ae5a4SJacob Faibussowitsch PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
511d71ae5a4SJacob Faibussowitsch {
5125c6c1daeSBarry Smith   PetscErrorCode ierr;
5133ba16761SJacob Faibussowitsch   PetscMPIInt    mpi_ierr;
5145c6c1daeSBarry Smith   PetscBool      flg;
5155c6c1daeSBarry Smith   PetscViewer    viewer;
5165c6c1daeSBarry Smith   MPI_Comm       ncomm;
5175c6c1daeSBarry Smith 
5185c6c1daeSBarry Smith   PetscFunctionBegin;
5199371c9d4SSatish Balay   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
5209371c9d4SSatish Balay   if (ierr) {
5213ba16761SJacob Faibussowitsch     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
5229371c9d4SSatish Balay     PetscFunctionReturn(NULL);
5239371c9d4SSatish Balay   }
5245c6c1daeSBarry Smith   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
5253ba16761SJacob Faibussowitsch     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL);
5263ba16761SJacob Faibussowitsch     if (mpi_ierr) {
5273ba16761SJacob Faibussowitsch       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
5289371c9d4SSatish Balay       PetscFunctionReturn(NULL);
5299371c9d4SSatish Balay     }
5305c6c1daeSBarry Smith   }
5313ba16761SJacob Faibussowitsch   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg);
5323ba16761SJacob Faibussowitsch   if (mpi_ierr) {
5333ba16761SJacob Faibussowitsch     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
5349371c9d4SSatish Balay     PetscFunctionReturn(NULL);
5359371c9d4SSatish Balay   }
5365c6c1daeSBarry Smith   if (!flg) { /* PetscViewer not yet created */
53702c9f0b5SLisandro Dalcin     ierr                              = PetscViewerSocketOpen(ncomm, NULL, 0, &viewer);
538*34fa283eSBarry Smith     ((PetscObject)viewer)->persistent = PETSC_TRUE;
5399371c9d4SSatish Balay     if (ierr) {
5403ba16761SJacob Faibussowitsch       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
5419371c9d4SSatish Balay       PetscFunctionReturn(NULL);
5429371c9d4SSatish Balay     }
5435c6c1daeSBarry Smith     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
5449371c9d4SSatish Balay     if (ierr) {
5453ba16761SJacob Faibussowitsch       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
5469371c9d4SSatish Balay       PetscFunctionReturn(NULL);
5479371c9d4SSatish Balay     }
5483ba16761SJacob Faibussowitsch     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer);
5493ba16761SJacob Faibussowitsch     if (mpi_ierr) {
5503ba16761SJacob Faibussowitsch       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
5519371c9d4SSatish Balay       PetscFunctionReturn(NULL);
5529371c9d4SSatish Balay     }
5535c6c1daeSBarry Smith   }
5545c6c1daeSBarry Smith   ierr = PetscCommDestroy(&ncomm);
5559371c9d4SSatish Balay   if (ierr) {
5563ba16761SJacob Faibussowitsch     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
5579371c9d4SSatish Balay     PetscFunctionReturn(NULL);
5589371c9d4SSatish Balay   }
5595c6c1daeSBarry Smith   PetscFunctionReturn(viewer);
5605c6c1daeSBarry Smith }
561