Actual source code: send.c


  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: /*--------------------------------------------------------------*/
 60: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
 61: {
 62:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
 63:   PetscErrorCode     ierr;

 65:   if (vmatlab->port) {
 66: #if defined(PETSC_HAVE_CLOSESOCKET)
 67:     closesocket(vmatlab->port);
 68: #else
 69:     close(vmatlab->port);
 70: #endif
 72:   }
 73:   PetscFree(vmatlab);
 74:   return 0;
 75: }

 77: /*--------------------------------------------------------------*/
 78: /*@C
 79:     PetscSocketOpen - handles connected to an open port where someone is waiting.

 81:     Input Parameters:
 82: +    url - for example www.mcs.anl.gov
 83: -    portnum - for example 80

 85:     Output Parameter:
 86: .    t - the socket number

 88:     Notes:
 89:     Use close() to close the socket connection

 91:     Use read() or PetscHTTPRequest() to read from the socket

 93:     Level: advanced

 95: .seealso:   PetscSocketListen(), PetscSocketEstablish(), PetscHTTPRequest(), PetscHTTPSConnect()
 96: @*/
 97: PetscErrorCode  PetscOpenSocket(const char hostname[],int portnum,int *t)
 98: {
 99:   struct sockaddr_in sa;
100:   struct hostent     *hp;
101:   int                s = 0;
102:   PetscBool          flg = PETSC_TRUE;
103:   static int         refcnt = 0;

105:   if (!(hp=gethostbyname(hostname))) {
106:     perror("SEND: error gethostbyname: ");
107:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
108:   }
109:   PetscMemzero(&sa,sizeof(sa));
110:   PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);

112:   sa.sin_family = hp->h_addrtype;
113:   sa.sin_port   = htons((u_short) portnum);
114:   while (flg) {
115:     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
116:       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
117:     }
118:     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
119: #if defined(PETSC_HAVE_WSAGETLASTERROR)
120:       WSAGetLastError();
121:       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
122:       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
123:       else if (ierr == WSAEISCONN) {
124:         (*PetscErrorPrintf)("SEND: socket already connected\n");
125:         Sleep((unsigned) 1);
126:       } else if (ierr == WSAECONNREFUSED) {
127:         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
128:         Sleep((unsigned) 1);
129:       } else {
130:         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
131:       }
132: #else
133:       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
134:       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
135:       else if (errno == EISCONN) {
136:         (*PetscErrorPrintf)("SEND: socket already connected\n");
137:         sleep((unsigned) 1);
138:       } else if (errno == ECONNREFUSED) {
139:         refcnt++;
141:         PetscInfo(NULL,"Connection refused in attaching socket, trying again\n");
142:         sleep((unsigned) 1);
143:       } else {
144:         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
145:       }
146: #endif
147:       flg = PETSC_TRUE;
148: #if defined(PETSC_HAVE_CLOSESOCKET)
149:       closesocket(s);
150: #else
151:       close(s);
152: #endif
153:     } else flg = PETSC_FALSE;
154:   }
155:   *t = s;
156:   return 0;
157: }

159: /*@C
160:    PetscSocketEstablish - starts a listener on a socket

162:    Input Parameters:
163: .    portnumber - the port to wait at

165:    Output Parameters:
166: .     ss - the socket to be used with PetscSocketListen()

168:     Level: advanced

170: .seealso:   PetscSocketListen(), PetscOpenSocket()

172: @*/
173: PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
174: {
175:   static size_t      MAXHOSTNAME = 100;
176:   char               myname[MAXHOSTNAME+1];
177:   int                s;
178:   struct sockaddr_in sa;
179:   struct hostent     *hp;

181:   PetscGetHostName(myname,sizeof(myname));

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

185:   hp = gethostbyname(myname);

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

192: #if defined(PETSC_HAVE_SO_REUSEADDR)
193:   {
194:     int optval = 1; /* Turn on the option */
195:     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));
196:   }
197: #endif

199:   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
200: #if defined(PETSC_HAVE_WSAGETLASTERROR)
201:     WSAGetLastError();
202:     if (ierr != WSAEADDRINUSE) {
203: #else
204:     if (errno != EADDRINUSE) {
205: #endif
206:       close(s);
207:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
208:     }
209:   }
210:   listen(s,0);
211:   *ss = s;
212:   return(0);
213: }

215: /*@C
216:    PetscSocketListen - Listens at a socket created with PetscSocketEstablish()

218:    Input Parameter:
219: .    listenport - obtained with PetscSocketEstablish()

221:    Output Parameter:
222: .     t - pass this to read() to read what is passed to this connection

224:     Level: advanced

226: .seealso:   PetscSocketEstablish()
227: @*/
228: PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
229: {
230:   struct sockaddr_in isa;
231: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
232:   size_t             i;
233: #else
234:   int                i;
235: #endif

237:   /* wait for someone to try to connect */
238:   i = sizeof(struct sockaddr_in);
240:   return 0;
241: }

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

246:    Collective

248:    Input Parameters:
249: +  comm - the MPI communicator
250: .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
251:              a connection from elsewhere
252: -  port - the port to connect to, use PETSC_DEFAULT for the default

254:    Output Parameter:
255: .  lab - a context to use when communicating with the server

257:    Level: intermediate

259:    Notes:
260:    Most users should employ the following commands to access the
261:    MATLAB PetscViewers
262: $
263: $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
264: $    MatView(Mat matrix,PetscViewer viewer)
265: $
266: $                or
267: $
268: $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
269: $    VecView(Vec vector,PetscViewer viewer)

271:    Options Database Keys:
272:    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
273:    PETSC_VIEWER_SOCKET_() or if
274:     NULL is passed for machine or PETSC_DEFAULT is passed for port
275: $    -viewer_socket_machine <machine>
276: $    -viewer_socket_port <port>

278:    Environmental variables:
279: +   PETSC_VIEWER_SOCKET_PORT - portnumber
280: -   PETSC_VIEWER_SOCKET_MACHINE - machine name

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

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

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

293: .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
294:           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
295:           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
296:           PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
297: @*/
298: PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
299: {
300:   PetscViewerCreate(comm,lab);
301:   PetscViewerSetType(*lab,PETSCVIEWERSOCKET);
302:   PetscViewerSocketSetConnection(*lab,machine,port);
303:   return 0;
304: }

306: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
307: {
308:   PetscInt       def = -1;
309:   char           sdef[256];
310:   PetscBool      tflg;

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

323:   PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,sizeof(sdef),NULL);
324:   PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,sizeof(sdef),&tflg);
325:   if (!tflg) {
326:     PetscGetHostName(sdef,sizeof(sdef));
327:   }
328:   PetscOptionsTail();
329:   return 0;
330: }

332: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool  *skip)
333: {
334:   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;

336:   *skip = vsocket->skipheader;
337:   return 0;
338: }

340: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
341: {
342:   PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;

344:   vsocket->skipheader = skip;
345:   return 0;
346: }

348: static PetscErrorCode  PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
349: {
350:   *fc = 0;
351:   return 0;
352: }

354: /*MC
355:    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket

357: .seealso:  PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
358:            PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
359:            PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
360:            PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()

362:   Level: beginner
363: M*/

365: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
366: {
367:   PetscViewer_Socket *vmatlab;

369:   PetscNewLog(v,&vmatlab);
370:   vmatlab->port          = 0;
371:   v->data                = (void*)vmatlab;
372:   v->ops->destroy        = PetscViewerDestroy_Socket;
373:   v->ops->flush          = NULL;
374:   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;

376:   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
377:   PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);
378:   PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);
379:   PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);
380:   PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);

382:   return 0;
383: }

385: /*@C
386:       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
387:              viewer is to use

389:   Logically Collective on PetscViewer

391:   Input Parameters:
392: +   v - viewer to connect
393: .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
394:              a connection from elsewhere
395: -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default

397:     Level: advanced

399: .seealso: PetscViewerSocketOpen()
400: @*/
401: PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
402: {
403:   PetscMPIInt        rank;
404:   char               mach[256];
405:   PetscBool          tflg;
406:   PetscViewer_Socket *vmatlab;

410:   vmatlab = (PetscViewer_Socket*)v->data;
412:   if (port <= 0) {
413:     char portn[16];
414:     PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);
415:     if (tflg) {
416:       PetscInt pport;
417:       PetscOptionsStringToInt(portn,&pport);
418:       port = (int)pport;
419:     } else port = PETSCSOCKETDEFAULTPORT;
420:   }
421:   if (!machine) {
422:     PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,sizeof(mach),&tflg);
423:     if (!tflg) {
424:       PetscGetHostName(mach,sizeof(mach));
425:     }
426:   } else {
427:     PetscStrncpy(mach,machine,sizeof(mach));
428:   }

430:   MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);
431:   if (rank == 0) {
432:     PetscStrcmp(mach,"server",&tflg);
433:     if (tflg) {
434:       int listenport;
435:       PetscInfo(v,"Waiting for connection from socket process on port %d\n",port);
436:       PetscSocketEstablish(port,&listenport);
437:       PetscSocketListen(listenport,&vmatlab->port);
438:       close(listenport);
439:     } else {
440:       PetscInfo(v,"Connecting to socket process on port %d machine %s\n",port,mach);
441:       PetscOpenSocket(mach,port,&vmatlab->port);
442:     }
443:   }
444:   return 0;
445: }

447: /* ---------------------------------------------------------------------*/
448: /*
449:     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
450:   is attached to a communicator, in this case the attribute is a PetscViewer.
451: */
452: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;

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

457:      Collective

459:      Input Parameter:
460: .    comm - the MPI communicator to share the socket PetscViewer

462:      Level: intermediate

464:    Options Database Keys:
465:    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
466:     NULL is passed for machine or PETSC_DEFAULT is passed for port
467: $    -viewer_socket_machine <machine>
468: $    -viewer_socket_port <port>

470:    Environmental variables:
471: +   PETSC_VIEWER_SOCKET_PORT - portnumber
472: -   PETSC_VIEWER_SOCKET_MACHINE - machine name

474:      Notes:
475:      Unlike almost all other PETSc routines, Petsc_VIEWER_SOCKET_ does not return
476:      an error code, it returns NULL if it fails. The socket PetscViewer is usually used in the form
477: $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));

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

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

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

488: .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
489:           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
490:           PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
491: @*/
492: PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
493: {
495:   PetscBool      flg;
496:   PetscViewer    viewer;
497:   MPI_Comm       ncomm;

499:   PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return NULL;}
500:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
501:     MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL);
502:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return NULL;}
503:   }
504:   MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
505:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return NULL;}
506:   if (!flg) { /* PetscViewer not yet created */
507:     PetscViewerSocketOpen(ncomm,NULL,0,&viewer);
508:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");return NULL;}
509:     PetscObjectRegisterDestroy((PetscObject)viewer);
510:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");return NULL;}
511:     MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
512:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");return NULL;}
513:   }
514:   PetscCommDestroy(&ncomm);
515:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");return NULL;}
516:   return viewer;
517: }