xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision e611a964e9853b74d61a56642fe9d06a6e51780f)
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
230         based server.
231 
232    Collective on MPI_Comm
233 
234    Input Parameters:
235 +  comm - the MPI communicator
236 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
237              a connection from elsewhere
238 -  port - the port to connect to, use PETSC_DEFAULT for the default
239 
240    Output Parameter:
241 .  lab - a context to use when communicating with the server
242 
243    Level: intermediate
244 
245    Notes:
246    Most users should employ the following commands to access the
247    MATLAB PetscViewers
248 $
249 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
250 $    MatView(Mat matrix,PetscViewer viewer)
251 $
252 $                or
253 $
254 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
255 $    VecView(Vec vector,PetscViewer viewer)
256 
257    Options Database Keys:
258    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
259    PETSC_VIEWER_SOCKET_() or if
260     NULL is passed for machine or PETSC_DEFAULT is passed for port
261 $    -viewer_socket_machine <machine>
262 $    -viewer_socket_port <port>
263 
264    Environmental variables:
265 +   PETSC_VIEWER_SOCKET_PORT portnumber
266 -   PETSC_VIEWER_SOCKET_MACHINE machine name
267 
268      Currently the only socket client available is MATLAB. See
269      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
270 
271    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
272           use PetscViewerBinaryRead/Write/GetDescriptor().
273 
274    Concepts: MATLAB^sending data
275    Concepts: sockets^sending data
276 
277 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
278           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
279           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
280           PetscBinaryViewerGetDescriptor()
281 @*/
282 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
283 {
284   PetscErrorCode ierr;
285 
286   PetscFunctionBegin;
287   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
288   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
289   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
290   PetscFunctionReturn(0);
291 }
292 
293 #undef __FUNCT__
294 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
295 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
296 {
297   PetscErrorCode ierr;
298   PetscInt       def = -1;
299   char           sdef[256];
300   PetscBool      tflg;
301 
302   PetscFunctionBegin;
303   /*
304        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
305     are listed here for the GUI to display
306   */
307   ierr = PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");CHKERRQ(ierr);
308   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
309   if (tflg) {
310     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
311   } else def = PETSCSOCKETDEFAULTPORT;
312   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
313 
314   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
315   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
316   if (!tflg) {
317     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
318   }
319   ierr = PetscOptionsTail();CHKERRQ(ierr);
320   PetscFunctionReturn(0);
321 }
322 
323 #undef __FUNCT__
324 #define __FUNCT__ "PetscViewerCreate_Socket"
325 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
326 {
327   PetscViewer_Socket *vmatlab;
328   PetscErrorCode     ierr;
329 
330   PetscFunctionBegin;
331   ierr                   = PetscNewLog(v,&vmatlab);CHKERRQ(ierr);
332   vmatlab->port          = 0;
333   v->data                = (void*)vmatlab;
334   v->ops->destroy        = PetscViewerDestroy_Socket;
335   v->ops->flush          = 0;
336   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
337 
338   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
339   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
340   PetscFunctionReturn(0);
341 }
342 
343 #undef __FUNCT__
344 #define __FUNCT__ "PetscViewerSocketSetConnection"
345 /*@C
346       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
347              viewer is to use
348 
349   Logically Collective on PetscViewer
350 
351   Input Parameters:
352 +   v - viewer to connect
353 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
354              a connection from elsewhere
355 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
356 
357     Level: advanced
358 
359 .seealso: PetscViewerSocketOpen()
360 @*/
361 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
362 {
363   PetscErrorCode     ierr;
364   PetscMPIInt        rank;
365   char               mach[256];
366   PetscBool          tflg;
367   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
368 
369   PetscFunctionBegin;
370   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
371   if (port <= 0) {
372     char portn[16];
373     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
374     if (tflg) {
375       PetscInt pport;
376       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
377       port = (int)pport;
378     } else port = PETSCSOCKETDEFAULTPORT;
379   }
380   if (!machine) {
381     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
382     if (!tflg) {
383       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
384     }
385   } else {
386     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
387   }
388 
389   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
390   if (!rank) {
391     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
392     if (tflg) {
393       int listenport;
394       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
395       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
396       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
397       close(listenport);
398     } else {
399       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
400       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
401     }
402   }
403   PetscFunctionReturn(0);
404 }
405 
406 /* ---------------------------------------------------------------------*/
407 /*
408     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
409   is attached to a communicator, in this case the attribute is a PetscViewer.
410 */
411 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
412 
413 
414 #undef __FUNCT__
415 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
416 /*@C
417      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
418 
419      Collective on MPI_Comm
420 
421      Input Parameter:
422 .    comm - the MPI communicator to share the socket PetscViewer
423 
424      Level: intermediate
425 
426    Options Database Keys:
427    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
428     NULL is passed for machine or PETSC_DEFAULT is passed for port
429 $    -viewer_socket_machine <machine>
430 $    -viewer_socket_port <port>
431 
432    Environmental variables:
433 +   PETSC_VIEWER_SOCKET_PORT portnumber
434 -   PETSC_VIEWER_SOCKET_MACHINE machine name
435 
436      Notes:
437      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
438      an error code.  The socket PetscViewer is usually used in the form
439 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
440 
441      Currently the only socket client available is MATLAB. See
442      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
443 
444      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
445 
446      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine.
447 
448 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
449           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
450           PetscViewerBinaryWriteStringArray(), PetscBinaryViewerGetDescriptor(), PETSC_VIEWER_MATLAB_()
451 @*/
452 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
453 {
454   PetscErrorCode ierr;
455   PetscBool      flg;
456   PetscViewer    viewer;
457   MPI_Comm       ncomm;
458 
459   PetscFunctionBegin;
460   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
461   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
462     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
463     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
464   }
465   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
466   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
467   if (!flg) { /* PetscViewer not yet created */
468     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
469     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
470     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
471     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
472     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
473     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
474   }
475   ierr = PetscCommDestroy(&ncomm);
476   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
477   PetscFunctionReturn(viewer);
478 }
479 
480