Actual source code: send.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  2: #include <petscsys.h>

  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

 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>

 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

 59: /*--------------------------------------------------------------*/
 62: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
 63: {
 64:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
 65:   PetscErrorCode     ierr;

 68:   if (vmatlab->port) {
 69: #if defined(PETSC_HAVE_CLOSESOCKET)
 70:     closesocket(vmatlab->port);
 71: #else
 72:     close(vmatlab->port);
 73: #endif
 74:     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
 75:   }
 76:   PetscFree(vmatlab);
 77:   return(0);
 78: }

 80: /*--------------------------------------------------------------*/
 83: /*
 84:     PetscSocketOpen - handles connected to an open port where someone is waiting.

 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;

 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:   PetscMemzero(&sa,sizeof(sa));
103:   PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);

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:       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:         PetscInfo(0,"Connection refused in attaching socket, trying again\n");
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:   return(0);
150: }

152: #define MAXHOSTNAME 100
155: /*
156:    PetscSocketEstablish - starts a listener on a socket

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;

169:   PetscGetHostName(myname,MAXHOSTNAME);

171:   PetscMemzero(&sa,sizeof(struct sockaddr_in));

173:   hp = gethostbyname(myname);
174:   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");

176:   sa.sin_family = hp->h_addrtype;
177:   sa.sin_port   = htons((u_short)portnum);

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:     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));
184:   }
185: #endif

187:   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
188: #if defined(PETSC_HAVE_WSAGETLASTERROR)
189:     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: }

205: /*
206:    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()

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

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:   return(0);
224: }

228: /*@C
229:    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.

231:    Collective on MPI_Comm

233:    Input Parameters:
234: +  comm - the MPI communicator
235: .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
236:              a connection from elsewhere
237: -  port - the port to connect to, use PETSC_DEFAULT for the default

239:    Output Parameter:
240: .  lab - a context to use when communicating with the server

242:    Level: intermediate

244:    Notes:
245:    Most users should employ the following commands to access the
246:    MATLAB PetscViewers
247: $
248: $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
249: $    MatView(Mat matrix,PetscViewer viewer)
250: $
251: $                or
252: $
253: $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
254: $    VecView(Vec vector,PetscViewer viewer)

256:    Options Database Keys:
257:    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
258:    PETSC_VIEWER_SOCKET_() or if
259:     NULL is passed for machine or PETSC_DEFAULT is passed for port
260: $    -viewer_socket_machine <machine>
261: $    -viewer_socket_port <port>

263:    Environmental variables:
264: +   PETSC_VIEWER_SOCKET_PORT portnumber
265: -   PETSC_VIEWER_SOCKET_MACHINE machine name

267:      Currently the only socket client available is MATLAB. See
268:      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.

270:    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
271:           use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().

273:      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
274:      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
275:      for communicating with a MATLAB Engine

277:    Concepts: MATLAB^sending data
278:    Concepts: sockets^sending data

280: .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
281:           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
282:           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
283:           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
284: @*/
285: PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
286: {

290:   PetscViewerCreate(comm,lab);
291:   PetscViewerSetType(*lab,PETSCVIEWERSOCKET);
292:   PetscViewerSocketSetConnection(*lab,machine,port);
293:   return(0);
294: }

298: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
299: {
301:   PetscInt       def = -1;
302:   char           sdef[256];
303:   PetscBool      tflg;

306:   /*
307:        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
308:     are listed here for the GUI to display
309:   */
310:   PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");
311:   PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);
312:   if (tflg) {
313:     PetscOptionsStringToInt(sdef,&def);
314:   } else def = PETSCSOCKETDEFAULTPORT;
315:   PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);

317:   PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);
318:   PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);
319:   if (!tflg) {
320:     PetscGetHostName(sdef,256);
321:   }
322:   PetscOptionsTail();
323:   return(0);
324: }

328: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
329: {
330:   PetscViewer_Socket *vmatlab;
331:   PetscErrorCode     ierr;

334:   PetscNewLog(v,&vmatlab);
335:   vmatlab->port          = 0;
336:   v->data                = (void*)vmatlab;
337:   v->ops->destroy        = PetscViewerDestroy_Socket;
338:   v->ops->flush          = 0;
339:   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;

341:   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
342:   PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);
343:   return(0);
344: }

348: /*@C
349:       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
350:              viewer is to use

352:   Logically Collective on PetscViewer

354:   Input Parameters:
355: +   v - viewer to connect
356: .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
357:              a connection from elsewhere
358: -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default

360:     Level: advanced

362: .seealso: PetscViewerSocketOpen()
363: @*/
364: PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
365: {
366:   PetscErrorCode     ierr;
367:   PetscMPIInt        rank;
368:   char               mach[256];
369:   PetscBool          tflg;
370:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;

374:   if (port <= 0) {
375:     char portn[16];
376:     PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);
377:     if (tflg) {
378:       PetscInt pport;
379:       PetscOptionsStringToInt(portn,&pport);
380:       port = (int)pport;
381:     } else port = PETSCSOCKETDEFAULTPORT;
382:   }
383:   if (!machine) {
384:     PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);
385:     if (!tflg) {
386:       PetscGetHostName(mach,256);
387:     }
388:   } else {
389:     PetscStrncpy(mach,machine,256);
390:   }

392:   MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);
393:   if (!rank) {
394:     PetscStrcmp(mach,"server",&tflg);
395:     if (tflg) {
396:       int listenport;
397:       PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);
398:       PetscSocketEstablish(port,&listenport);
399:       PetscSocketListen(listenport,&vmatlab->port);
400:       close(listenport);
401:     } else {
402:       PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);
403:       PetscOpenSocket(mach,port,&vmatlab->port);
404:     }
405:   }
406:   return(0);
407: }

409: /* ---------------------------------------------------------------------*/
410: /*
411:     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
412:   is attached to a communicator, in this case the attribute is a PetscViewer.
413: */
414: static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;


419: /*@C
420:      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.

422:      Collective on MPI_Comm

424:      Input Parameter:
425: .    comm - the MPI communicator to share the socket PetscViewer

427:      Level: intermediate

429:    Options Database Keys:
430:    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
431:     NULL is passed for machine or PETSC_DEFAULT is passed for port
432: $    -viewer_socket_machine <machine>
433: $    -viewer_socket_port <port>

435:    Environmental variables:
436: +   PETSC_VIEWER_SOCKET_PORT portnumber
437: -   PETSC_VIEWER_SOCKET_MACHINE machine name

439:      Notes:
440:      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
441:      an error code.  The socket PetscViewer is usually used in the form
442: $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));

444:      Currently the only socket client available is MATLAB. See
445:      src/dm/examples/tests/ex12.c and ex12.m for an example of usage.

447:      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.

449:      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
450:      .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD 
451:      for communicating with a MATLAB Engine

453: .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
454:           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
455:           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
456: @*/
457: PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
458: {
460:   PetscBool      flg;
461:   PetscViewer    viewer;
462:   MPI_Comm       ncomm;

465:   PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
466:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
467:     MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
468:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
469:   }
470:   MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
471:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
472:   if (!flg) { /* PetscViewer not yet created */
473:     PetscViewerSocketOpen(ncomm,0,0,&viewer);
474:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
475:     PetscObjectRegisterDestroy((PetscObject)viewer);
476:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
477:     MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
478:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
479:   }
480:   PetscCommDestroy(&ncomm);
481:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return(0);}
482:   PetscFunctionReturn(viewer);
483: }