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: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinarySetSkipHeader_C", NULL);
75: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetSkipHeader_C", NULL);
76: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetFlowControl_C", NULL);
77: return 0;
78: }
80: /*--------------------------------------------------------------*/
81: /*@C
82: PetscSocketOpen - handles connected to an open port where someone is waiting.
84: Input Parameters:
85: + url - for example www.mcs.anl.gov
86: - portnum - for example 80
88: Output Parameter:
89: . t - the socket number
91: Notes:
92: Use close() to close the socket connection
94: Use read() or `PetscHTTPRequest()` to read from the socket
96: Level: advanced
98: .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()`
99: @*/
100: PetscErrorCode PetscOpenSocket(const char hostname[], int portnum, int *t)
101: {
102: struct sockaddr_in sa;
103: struct hostent *hp;
104: int s = 0;
105: PetscBool flg = PETSC_TRUE;
106: static int refcnt = 0;
108: if (!(hp = gethostbyname(hostname))) {
109: perror("SEND: error gethostbyname: ");
110: SETERRQ(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");
120: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
121: }
122: if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
123: #if defined(PETSC_HAVE_WSAGETLASTERROR)
124: WSAGetLastError();
125: if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
126: else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
127: else if (ierr == WSAEISCONN) {
128: (*PetscErrorPrintf)("SEND: socket already connected\n");
129: Sleep((unsigned)1);
130: } else if (ierr == WSAECONNREFUSED) {
131: /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
132: Sleep((unsigned)1);
133: } else {
134: perror(NULL);
135: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
136: }
137: #else
138: if (errno == EADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
139: else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
140: else if (errno == EISCONN) {
141: (*PetscErrorPrintf)("SEND: socket already connected\n");
142: sleep((unsigned)1);
143: } else if (errno == ECONNREFUSED) {
144: refcnt++;
146: PetscInfo(NULL, "Connection refused in attaching socket, trying again\n");
147: sleep((unsigned)1);
148: } else {
149: perror(NULL);
150: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
151: }
152: #endif
153: flg = PETSC_TRUE;
154: #if defined(PETSC_HAVE_CLOSESOCKET)
155: closesocket(s);
156: #else
157: close(s);
158: #endif
159: } else flg = PETSC_FALSE;
160: }
161: *t = s;
162: return 0;
163: }
165: /*@C
166: PetscSocketEstablish - starts a listener on a socket
168: Input Parameters:
169: . portnumber - the port to wait at
171: Output Parameters:
172: . ss - the socket to be used with `PetscSocketListen()`
174: Level: advanced
176: .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
177: @*/
178: PETSC_INTERN PetscErrorCode PetscSocketEstablish(int portnum, int *ss)
179: {
180: static size_t MAXHOSTNAME = 100;
181: char myname[MAXHOSTNAME + 1];
182: int s;
183: struct sockaddr_in sa;
184: struct hostent *hp;
186: PetscGetHostName(myname, sizeof(myname));
188: PetscMemzero(&sa, sizeof(struct sockaddr_in));
190: hp = gethostbyname(myname);
193: sa.sin_family = hp->h_addrtype;
194: sa.sin_port = htons((u_short)portnum);
197: #if defined(PETSC_HAVE_SO_REUSEADDR)
198: {
199: int optval = 1; /* Turn on the option */
200: setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
201: }
202: #endif
204: while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
205: #if defined(PETSC_HAVE_WSAGETLASTERROR)
206: WSAGetLastError();
207: if (ierr != WSAEADDRINUSE) {
208: #else
209: if (errno != EADDRINUSE) {
210: #endif
211: close(s);
212: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "Error from bind()");
213: }
214: }
215: listen(s, 0);
216: *ss = s;
217: return 0;
218: }
220: /*@C
221: PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()`
223: Input Parameter:
224: . listenport - obtained with `PetscSocketEstablish()`
226: Output Parameter:
227: . t - pass this to read() to read what is passed to this connection
229: Level: advanced
231: .seealso: `PetscSocketEstablish()`
232: @*/
233: PETSC_INTERN PetscErrorCode PetscSocketListen(int listenport, int *t)
234: {
235: struct sockaddr_in isa;
236: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
237: size_t i;
238: #else
239: int i;
240: #endif
242: /* wait for someone to try to connect */
243: i = sizeof(struct sockaddr_in);
245: return 0;
246: }
248: /*@C
249: PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.
251: Collective
253: Input Parameters:
254: + comm - the MPI communicator
255: . machine - the machine the server is running on, use NULL for the local machine, use "server" to passively wait for
256: a connection from elsewhere
257: - port - the port to connect to, use `PETSC_DEFAULT` for the default
259: Output Parameter:
260: . lab - a context to use when communicating with the server
262: Options Database Keys:
263: For use with `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`,
264: `PETSC_VIEWER_SOCKET_()` or if
265: NULL is passed for machine or PETSC_DEFAULT is passed for port
266: $ -viewer_socket_machine <machine>
267: $ -viewer_socket_port <port>
269: Environmental variables:
270: + `PETSC_VIEWER_SOCKET_PORT` - portnumber
271: - `PETSC_VIEWER_SOCKET_MACHINE` - machine name
273: Level: intermediate
275: Notes:
276: Most users should employ the following commands to access the
277: MATLAB `PetscViewer`
278: $
279: $ PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
280: $ MatView(Mat matrix,PetscViewer viewer)
281: $
282: $ or
283: $
284: $ PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
285: $ VecView(Vec vector,PetscViewer viewer)
287: Currently the only socket client available is MATLAB, PETSc must be configured with --with-matlab for this client. See
288: src/dm/tests/ex12.c and ex12.m for an example of usage.
290: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
291: use `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`, `PetscViewerBinarWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`.
293: Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
294: .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
295: for communicating with a MATLAB Engine
297: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSCVIEWERSOCKET`, `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`,
298: `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`,
299: `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`,
300: `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()`
301: @*/
302: PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm, const char machine[], int port, PetscViewer *lab)
303: {
304: PetscViewerCreate(comm, lab);
305: PetscViewerSetType(*lab, PETSCVIEWERSOCKET);
306: PetscViewerSocketSetConnection(*lab, machine, port);
307: return 0;
308: }
310: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems *PetscOptionsObject)
311: {
312: PetscInt def = -1;
313: char sdef[256];
314: PetscBool tflg;
316: /*
317: These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
318: are listed here for the GUI to display
319: */
320: PetscOptionsHeadBegin(PetscOptionsObject, "Socket PetscViewer Options");
321: PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", sdef, 16, &tflg);
322: if (tflg) {
323: PetscOptionsStringToInt(sdef, &def);
324: } else def = PETSCSOCKETDEFAULTPORT;
325: PetscOptionsInt("-viewer_socket_port", "Port number to use for socket", "PetscViewerSocketSetConnection", def, NULL, NULL);
327: PetscOptionsString("-viewer_socket_machine", "Machine to use for socket", "PetscViewerSocketSetConnection", sdef, NULL, sizeof(sdef), NULL);
328: PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", sdef, sizeof(sdef), &tflg);
329: if (!tflg) PetscGetHostName(sdef, sizeof(sdef));
330: PetscOptionsHeadEnd();
331: return 0;
332: }
334: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip)
335: {
336: PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
338: *skip = vsocket->skipheader;
339: return 0;
340: }
342: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip)
343: {
344: PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;
346: vsocket->skipheader = skip;
347: return 0;
348: }
350: PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *);
352: /*MC
353: PETSCVIEWERSOCKET - A viewer that writes to a Unix socket
355: Level: beginner
357: .seealso: [](sec_viewers), `PETSC_VIEWERBINARY`, `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()`
361: M*/
363: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
364: {
365: PetscViewer_Socket *vmatlab;
367: PetscNew(&vmatlab);
368: vmatlab->port = 0;
369: vmatlab->flowcontrol = 256; /* same default as in PetscViewerCreate_Binary() */
370: v->data = (void *)vmatlab;
371: v->ops->destroy = PetscViewerDestroy_Socket;
372: v->ops->flush = NULL;
373: v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
375: /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
376: PetscObjectChangeTypeName((PetscObject)v, PETSCVIEWERBINARY);
377: PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Socket);
378: PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Socket);
379: PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary);
381: return 0;
382: }
384: /*@C
385: PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
386: viewer is to use
388: Logically Collective
390: Input Parameters:
391: + v - viewer to connect
392: . machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
393: a connection from elsewhere
394: - port - the port on the machine one is connecting to, use `PETSC_DEFAULT` for default
396: Level: advanced
398: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PetscViewerSocketOpen()`
399: @*/
400: PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v, const char machine[], int port)
401: {
402: PetscMPIInt rank;
403: char mach[256];
404: PetscBool tflg;
405: PetscViewer_Socket *vmatlab;
409: vmatlab = (PetscViewer_Socket *)v->data;
411: if (port <= 0) {
412: char portn[16];
413: PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", portn, 16, &tflg);
414: if (tflg) {
415: PetscInt pport;
416: PetscOptionsStringToInt(portn, &pport);
417: port = (int)pport;
418: } else port = PETSCSOCKETDEFAULTPORT;
419: }
420: if (!machine) {
421: PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", mach, sizeof(mach), &tflg);
422: if (!tflg) PetscGetHostName(mach, sizeof(mach));
423: } else {
424: PetscStrncpy(mach, machine, sizeof(mach));
425: }
427: MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank);
428: if (rank == 0) {
429: PetscStrcmp(mach, "server", &tflg);
430: if (tflg) {
431: int listenport;
432: PetscInfo(v, "Waiting for connection from socket process on port %d\n", port);
433: PetscSocketEstablish(port, &listenport);
434: PetscSocketListen(listenport, &vmatlab->port);
435: close(listenport);
436: } else {
437: PetscInfo(v, "Connecting to socket process on port %d machine %s\n", port, mach);
438: PetscOpenSocket(mach, port, &vmatlab->port);
439: }
440: }
441: return 0;
442: }
444: /* ---------------------------------------------------------------------*/
445: /*
446: The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
447: is attached to a communicator, in this case the attribute is a PetscViewer.
448: */
449: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
451: /*@C
452: PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
454: Collective
456: Input Parameter:
457: . comm - the MPI communicator to share the `PETSCVIEWERSOCKET` `PetscViewer`
459: Level: intermediate
461: Options Database Keys:
462: For use with the default `PETSC_VIEWER_SOCKET_WORLD` or if
463: NULL is passed for machine or `PETSC_DEFAULT` is passed for port
464: + -viewer_socket_machine <machine> - machine to connect to
465: - -viewer_socket_port <port> - port to connect to
467: Environmental variables:
468: + `PETSC_VIEWER_SOCKET_PORT` - portnumber
469: - `PETSC_VIEWER_SOCKET_MACHINE` - machine name
471: Notes:
472: Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return
473: an error code, it returns NULL if it fails. The `PETSCVIEWERSOCKET` `PetscViewer` is usually used in the form
474: $ XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
476: Currently the only socket client available is MATLAB. See
477: src/dm/tests/ex12.c and ex12.m for an example of usage.
479: Connects to a waiting socket and stays connected until `PetscViewerDestroy()` is called.
481: Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
482: .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
483: for communicating with a MATLAB Engine
485: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`,
486: `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`,
487: `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()`
488: @*/
489: PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
490: {
492: PetscBool flg;
493: PetscViewer viewer;
494: MPI_Comm ncomm;
496: PetscCommDuplicate(comm, &ncomm, NULL);
497: if (ierr) {
498: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
499: return NULL;
500: }
501: if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
502: MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL);
503: if (ierr) {
504: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
505: return NULL;
506: }
507: }
508: MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg);
509: if (ierr) {
510: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
511: return NULL;
512: }
513: if (!flg) { /* PetscViewer not yet created */
514: PetscViewerSocketOpen(ncomm, NULL, 0, &viewer);
515: if (ierr) {
516: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
517: return NULL;
518: }
519: PetscObjectRegisterDestroy((PetscObject)viewer);
520: if (ierr) {
521: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
522: return NULL;
523: }
524: MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer);
525: if (ierr) {
526: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
527: return NULL;
528: }
529: }
530: PetscCommDestroy(&ncomm);
531: if (ierr) {
532: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_SOCKET_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
533: return NULL;
534: }
535: return viewer;
536: }