Actual source code: send.c
petsc-3.14.6 2021-03-30
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;
66: if (vmatlab->port) {
67: #if defined(PETSC_HAVE_CLOSESOCKET)
68: closesocket(vmatlab->port);
69: #else
70: close(vmatlab->port);
71: #endif
72: if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
73: }
74: PetscFree(vmatlab);
75: return(0);
76: }
78: /*--------------------------------------------------------------*/
79: /*@C
80: PetscSocketOpen - handles connected to an open port where someone is waiting.
82: Input Parameters:
83: + url - for example www.mcs.anl.gov
84: - portnum - for example 80
86: Output Paramater:
87: . t - the socket number
89: Notes:
90: Use close() to close the socket connection
92: Use read() or PetscHTTPRequest() to read from the socket
94: Level: advanced
96: .seealso: PetscSocketListen(), PetscSocketEstablish(), PetscHTTPRequest(), PetscHTTPSConnect()
97: @*/
98: PetscErrorCode PetscOpenSocket(const char hostname[],int portnum,int *t)
99: {
100: struct sockaddr_in sa;
101: struct hostent *hp;
102: int s = 0;
103: PetscErrorCode ierr;
104: PetscBool flg = PETSC_TRUE;
105: static int refcnt = 0;
108: if (!(hp=gethostbyname(hostname))) {
109: perror("SEND: error gethostbyname: ");
110: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
111: }
112: PetscMemzero(&sa,sizeof(sa));
113: PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);
115: sa.sin_family = hp->h_addrtype;
116: sa.sin_port = htons((u_short) portnum);
117: while (flg) {
118: if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
119: perror("SEND: error socket"); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
120: }
121: if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
122: #if defined(PETSC_HAVE_WSAGETLASTERROR)
123: WSAGetLastError();
124: if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
125: else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
126: else if (ierr == WSAEISCONN) {
127: (*PetscErrorPrintf)("SEND: socket already connected\n");
128: Sleep((unsigned) 1);
129: } else if (ierr == WSAECONNREFUSED) {
130: /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
131: Sleep((unsigned) 1);
132: } else {
133: perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
134: }
135: #else
136: if (errno == EADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
137: else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
138: else if (errno == EISCONN) {
139: (*PetscErrorPrintf)("SEND: socket already connected\n");
140: sleep((unsigned) 1);
141: } else if (errno == ECONNREFUSED) {
142: refcnt++;
143: if (refcnt > 5) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Connection refused by remote host %s port %d",hostname,portnum);
144: PetscInfo(NULL,"Connection refused in attaching socket, trying again\n");
145: sleep((unsigned) 1);
146: } else {
147: perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
148: }
149: #endif
150: flg = PETSC_TRUE;
151: #if defined(PETSC_HAVE_CLOSESOCKET)
152: closesocket(s);
153: #else
154: close(s);
155: #endif
156: } else flg = PETSC_FALSE;
157: }
158: *t = s;
159: return(0);
160: }
163: /*@C
164: PetscSocketEstablish - starts a listener on a socket
166: Input Parameters:
167: . portnumber - the port to wait at
169: Output Parameters:
170: . ss - the socket to be used with PetscSocketListen()
172: Level: advanced
174: .seealso: PetscSocketListen(), PetscOpenSocket()
176: @*/
177: PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
178: {
179: static size_t MAXHOSTNAME = 100;
180: char myname[MAXHOSTNAME+1];
181: int s;
182: PetscErrorCode ierr;
183: struct sockaddr_in sa;
184: struct hostent *hp;
187: PetscGetHostName(myname,sizeof(myname));
189: PetscMemzero(&sa,sizeof(struct sockaddr_in));
191: hp = gethostbyname(myname);
192: if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
194: sa.sin_family = hp->h_addrtype;
195: sa.sin_port = htons((u_short)portnum);
197: if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
198: #if defined(PETSC_HAVE_SO_REUSEADDR)
199: {
200: int optval = 1; /* Turn on the option */
201: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));
202: }
203: #endif
205: while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
206: #if defined(PETSC_HAVE_WSAGETLASTERROR)
207: WSAGetLastError();
208: if (ierr != WSAEADDRINUSE) {
209: #else
210: if (errno != EADDRINUSE) {
211: #endif
212: close(s);
213: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
214: }
215: }
216: listen(s,0);
217: *ss = s;
218: return(0);
219: }
221: /*@C
222: PetscSocketListen - Listens at a socket created with PetscSocketEstablish()
224: Input Parameter:
225: . listenport - obtained with PetscSocketEstablish()
227: Output Parameter:
228: . t - pass this to read() to read what is passed to this connection
230: Level: advanced
232: .seealso: PetscSocketEstablish()
233: @*/
234: PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport,int *t)
235: {
236: struct sockaddr_in isa;
237: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
238: size_t i;
239: #else
240: int i;
241: #endif
244: /* wait for someone to try to connect */
245: i = sizeof(struct sockaddr_in);
246: if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
247: return(0);
248: }
250: /*@C
251: PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
253: Collective
255: Input Parameters:
256: + comm - the MPI communicator
257: . machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
258: a connection from elsewhere
259: - port - the port to connect to, use PETSC_DEFAULT for the default
261: Output Parameter:
262: . lab - a context to use when communicating with the server
264: Level: intermediate
266: Notes:
267: Most users should employ the following commands to access the
268: MATLAB PetscViewers
269: $
270: $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
271: $ MatView(Mat matrix,PetscViewer viewer)
272: $
273: $ or
274: $
275: $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
276: $ VecView(Vec vector,PetscViewer viewer)
278: Options Database Keys:
279: For use with PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
280: PETSC_VIEWER_SOCKET_() or if
281: NULL is passed for machine or PETSC_DEFAULT is passed for port
282: $ -viewer_socket_machine <machine>
283: $ -viewer_socket_port <port>
285: Environmental variables:
286: + PETSC_VIEWER_SOCKET_PORT - portnumber
287: - PETSC_VIEWER_SOCKET_MACHINE - machine name
289: Currently the only socket client available is MATLAB. See
290: src/dm/tests/ex12.c and ex12.m for an example of usage.
292: Notes:
293: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
294: use PetscViewerBinaryRead(), PetscViewerBinaryWrite(), PetscViewerBinarWriteStringArray(), PetscViewerBinaryGetDescriptor().
296: Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
297: .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
298: for communicating with a MATLAB Engine
301: .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
302: PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
303: PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
304: PetscBinaryViewerGetDescriptor(), PetscMatlabEngineCreate()
305: @*/
306: PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
307: {
311: PetscViewerCreate(comm,lab);
312: PetscViewerSetType(*lab,PETSCVIEWERSOCKET);
313: PetscViewerSocketSetConnection(*lab,machine,port);
314: return(0);
315: }
317: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscOptionItems *PetscOptionsObject,PetscViewer v)
318: {
320: PetscInt def = -1;
321: char sdef[256];
322: PetscBool tflg;
325: /*
326: These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
327: are listed here for the GUI to display
328: */
329: PetscOptionsHead(PetscOptionsObject,"Socket PetscViewer Options");
330: PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);
331: if (tflg) {
332: PetscOptionsStringToInt(sdef,&def);
333: } else def = PETSCSOCKETDEFAULTPORT;
334: PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,NULL,NULL);
336: PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,NULL,sizeof(sdef),NULL);
337: PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,sizeof(sdef),&tflg);
338: if (!tflg) {
339: PetscGetHostName(sdef,sizeof(sdef));
340: }
341: PetscOptionsTail();
342: return(0);
343: }
345: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer,PetscBool *skip)
346: {
347: PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
350: *skip = vsocket->skipheader;
351: return(0);
352: }
354: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer,PetscBool skip)
355: {
356: PetscViewer_Socket *vsocket = (PetscViewer_Socket*)viewer->data;
359: vsocket->skipheader = skip;
360: return(0);
361: }
363: static PetscErrorCode PetscViewerBinaryGetFlowControl_Socket(PetscViewer viewer,PetscInt *fc)
364: {
366: *fc = 0;
367: return(0);
368: }
370: /*MC
371: PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
374: .seealso: PetscViewerSocketOpen(), PetscViewerDrawOpen(), PETSC_VIEWER_DRAW_(),PETSC_VIEWER_DRAW_SELF, PETSC_VIEWER_DRAW_WORLD,
375: PetscViewerCreate(), PetscViewerASCIIOpen(), PetscViewerBinaryOpen(), PETSCVIEWERBINARY, PETSCVIEWERDRAW,
376: PetscViewerMatlabOpen(), VecView(), DMView(), PetscViewerMatlabPutArray(), PETSCVIEWERASCII, PETSCVIEWERMATLAB,
377: PetscViewerFileSetName(), PetscViewerFileSetMode(), PetscViewerFormat, PetscViewerType, PetscViewerSetType()
379: Level: beginner
380: M*/
382: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
383: {
384: PetscViewer_Socket *vmatlab;
385: PetscErrorCode ierr;
388: PetscNewLog(v,&vmatlab);
389: vmatlab->port = 0;
390: v->data = (void*)vmatlab;
391: v->ops->destroy = PetscViewerDestroy_Socket;
392: v->ops->flush = NULL;
393: v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
395: /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
396: PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);
397: PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinarySetSkipHeader_C",PetscViewerBinarySetSkipHeader_Socket);
398: PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetSkipHeader_C",PetscViewerBinaryGetSkipHeader_Socket);
399: PetscObjectComposeFunction((PetscObject)v,"PetscViewerBinaryGetFlowControl_C",PetscViewerBinaryGetFlowControl_Socket);
401: return(0);
402: }
404: /*@C
405: PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
406: viewer is to use
408: Logically Collective on PetscViewer
410: Input Parameters:
411: + v - viewer to connect
412: . machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
413: a connection from elsewhere
414: - port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
416: Level: advanced
418: .seealso: PetscViewerSocketOpen()
419: @*/
420: PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
421: {
422: PetscErrorCode ierr;
423: PetscMPIInt rank;
424: char mach[256];
425: PetscBool tflg;
426: PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
430: if (port <= 0) {
431: char portn[16];
432: PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);
433: if (tflg) {
434: PetscInt pport;
435: PetscOptionsStringToInt(portn,&pport);
436: port = (int)pport;
437: } else port = PETSCSOCKETDEFAULTPORT;
438: }
439: if (!machine) {
440: PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,sizeof(mach),&tflg);
441: if (!tflg) {
442: PetscGetHostName(mach,sizeof(mach));
443: }
444: } else {
445: PetscStrncpy(mach,machine,sizeof(mach));
446: }
448: MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);
449: if (!rank) {
450: PetscStrcmp(mach,"server",&tflg);
451: if (tflg) {
452: int listenport;
453: PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);
454: PetscSocketEstablish(port,&listenport);
455: PetscSocketListen(listenport,&vmatlab->port);
456: close(listenport);
457: } else {
458: PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);
459: PetscOpenSocket(mach,port,&vmatlab->port);
460: }
461: }
462: return(0);
463: }
465: /* ---------------------------------------------------------------------*/
466: /*
467: The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
468: is attached to a communicator, in this case the attribute is a PetscViewer.
469: */
470: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
473: /*@C
474: PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
476: Collective
478: Input Parameter:
479: . comm - the MPI communicator to share the socket PetscViewer
481: Level: intermediate
483: Options Database Keys:
484: For use with the default PETSC_VIEWER_SOCKET_WORLD or if
485: NULL is passed for machine or PETSC_DEFAULT is passed for port
486: $ -viewer_socket_machine <machine>
487: $ -viewer_socket_port <port>
489: Environmental variables:
490: + PETSC_VIEWER_SOCKET_PORT - portnumber
491: - PETSC_VIEWER_SOCKET_MACHINE - machine name
493: Notes:
494: Unlike almost all other PETSc routines, Petsc_VIEWER_SOCKET_ does not return
495: an error code, it returns NULL if it fails. The socket PetscViewer is usually used in the form
496: $ XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
498: Currently the only socket client available is MATLAB. See
499: src/dm/tests/ex12.c and ex12.m for an example of usage.
501: Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
503: Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for writing output to a
504: .mat file. Use PetscMatlabEngineCreate() or PETSC_MATLAB_ENGINE_(), PETSC_MATLAB_ENGINE_SELF, or PETSC_MATLAB_ENGINE_WORLD
505: for communicating with a MATLAB Engine
507: .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
508: PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
509: PetscViewerBinaryWriteStringArray(), PetscViewerBinaryGetDescriptor(), PETSC_VIEWER_MATLAB_()
510: @*/
511: PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
512: {
514: PetscBool flg;
515: PetscViewer viewer;
516: MPI_Comm ncomm;
519: PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
520: if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
521: MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,NULL);
522: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
523: }
524: MPI_Comm_get_attr(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
525: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
526: if (!flg) { /* PetscViewer not yet created */
527: PetscViewerSocketOpen(ncomm,NULL,0,&viewer);
528: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
529: PetscObjectRegisterDestroy((PetscObject)viewer);
530: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
531: MPI_Comm_set_attr(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
532: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
533: }
534: PetscCommDestroy(&ncomm);
535: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
536: PetscFunctionReturn(viewer);
537: }