1b75c6efcSBarry Smith /*
2b75c6efcSBarry Smith Usage: A = sopen(portnumber); [ 5000 < portnumber < 5010 ]
3b75c6efcSBarry Smith
4b75c6efcSBarry Smith Written by Barry Smith, bsmith@mcs.anl.gov 4/14/92
5b75c6efcSBarry Smith Updated by Richard Katz, katz@ldeo.columbia.edu 9/28/03
6b75c6efcSBarry Smith Updated by Barry Smith, bsmith@mcs.anl.gov 8/11/06
7b75c6efcSBarry Smith
8b75c6efcSBarry Smith Similar to MATLAB's sopen() only does not take file name, instead optional
9b75c6efcSBarry Smith port to listen at.
10b75c6efcSBarry Smith
11b75c6efcSBarry Smith Only compiles as C code.
12b75c6efcSBarry Smith */
13b75c6efcSBarry Smith
14b75c6efcSBarry Smith #include <petscsys.h>
15b75c6efcSBarry Smith
16b75c6efcSBarry Smith #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
17b75c6efcSBarry Smith /* Some systems have inconsistent include files that use but don't
18b75c6efcSBarry Smith ensure that the following definitions are made */
19b75c6efcSBarry Smith typedef unsigned char u_char;
20b75c6efcSBarry Smith typedef unsigned short u_short;
21b75c6efcSBarry Smith typedef unsigned int u_int;
22b75c6efcSBarry Smith typedef unsigned long u_long;
23b75c6efcSBarry Smith #endif
24b75c6efcSBarry Smith
25b75c6efcSBarry Smith #include <errno.h>
26b75c6efcSBarry Smith #include <ctype.h>
27b75c6efcSBarry Smith #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
28b75c6efcSBarry Smith #include <machine/endian.h>
29b75c6efcSBarry Smith #endif
30b75c6efcSBarry Smith #if defined(PETSC_HAVE_UNISTD_H)
31b75c6efcSBarry Smith #include <unistd.h>
32b75c6efcSBarry Smith #endif
33b75c6efcSBarry Smith #if defined(PETSC_HAVE_SYS_SOCKET_H)
34b75c6efcSBarry Smith #include <sys/socket.h>
35b75c6efcSBarry Smith #endif
36b75c6efcSBarry Smith #if defined(PETSC_HAVE_SYS_WAIT_H)
37b75c6efcSBarry Smith #include <sys/wait.h>
38b75c6efcSBarry Smith #endif
39b75c6efcSBarry Smith #if defined(PETSC_HAVE_NETINET_IN_H)
40b75c6efcSBarry Smith #include <netinet/in.h>
41b75c6efcSBarry Smith #endif
42b75c6efcSBarry Smith #if defined(PETSC_HAVE_NETDB_H)
43b75c6efcSBarry Smith #include <netdb.h>
44b75c6efcSBarry Smith #endif
45b75c6efcSBarry Smith #if defined(PETSC_HAVE_FCNTL_H)
46b75c6efcSBarry Smith #include <fcntl.h>
47b75c6efcSBarry Smith #endif
48b75c6efcSBarry Smith #if defined(PETSC_HAVE_IO_H)
49b75c6efcSBarry Smith #include <io.h>
50b75c6efcSBarry Smith #endif
51b75c6efcSBarry Smith #if defined(PETSC_HAVE_SYS_UTSNAME_H)
52b75c6efcSBarry Smith #include <sys/utsname.h>
53b75c6efcSBarry Smith #endif
54b75c6efcSBarry Smith #if defined(PETSC_HAVE_WINSOCK2_H)
55b75c6efcSBarry Smith #include <Winsock2.h>
56b75c6efcSBarry Smith #endif
57b75c6efcSBarry Smith #if defined(PETSC_HAVE_WS2TCPIP_H)
58b75c6efcSBarry Smith #include <Ws2tcpip.h>
59b75c6efcSBarry Smith #endif
60b75c6efcSBarry Smith #include <../src/sys/classes/viewer/impls/socket/socket.h>
61b75c6efcSBarry Smith #include <mex.h>
62b75c6efcSBarry Smith
63b75c6efcSBarry Smith #define PETSC_MEX_ERROR(a) \
64b75c6efcSBarry Smith { \
65b75c6efcSBarry Smith mexErrMsgTxt(a); \
66b75c6efcSBarry Smith return; \
67b75c6efcSBarry Smith }
68b75c6efcSBarry Smith #define PETSC_MEX_ERRORQ(a) \
69b75c6efcSBarry Smith { \
70b75c6efcSBarry Smith mexErrMsgTxt(a); \
71b75c6efcSBarry Smith return -1; \
72b75c6efcSBarry Smith }
73b75c6efcSBarry Smith
74b75c6efcSBarry Smith /* The listenport variable is an ugly hack. If the user hits a */
75b75c6efcSBarry Smith /* control c while we are listening then we stop listening */
76b75c6efcSBarry Smith /* but do not close the listen. Therefore if we try to bind again */
77b75c6efcSBarry Smith /* and get an address in use, close the listen which was left */
78b75c6efcSBarry Smith /* hanging; the problem is if the user uses several portnumbers */
79b75c6efcSBarry Smith /* and control c we may not be able to close the correct listener. */
80b75c6efcSBarry Smith static int listenport;
81b75c6efcSBarry Smith extern int establish(u_short);
SOCKConnect_Private(int portnumber)8266976f2fSJacob Faibussowitsch static int SOCKConnect_Private(int portnumber)
83b75c6efcSBarry Smith {
84b75c6efcSBarry Smith struct sockaddr_in isa;
85b75c6efcSBarry Smith #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
86b75c6efcSBarry Smith size_t i;
87b75c6efcSBarry Smith #else
88b75c6efcSBarry Smith int i;
89b75c6efcSBarry Smith #endif
90b75c6efcSBarry Smith int t;
91b75c6efcSBarry Smith
92b75c6efcSBarry Smith /* open port*/
93b75c6efcSBarry Smith listenport = establish((u_short)portnumber);
94b75c6efcSBarry Smith if (listenport == -1) PETSC_MEX_ERRORQ("RECEIVE: unable to establish port\n");
95b75c6efcSBarry Smith
96b75c6efcSBarry Smith /* wait for someone to try to connect */
97b75c6efcSBarry Smith i = sizeof(struct sockaddr_in);
98b75c6efcSBarry Smith if ((t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) < 0) PETSC_MEX_ERRORQ("RECEIVE: error from accept\n");
99b75c6efcSBarry Smith close(listenport);
1004ad8454bSPierre Jolivet return t;
101b75c6efcSBarry Smith }
102b75c6efcSBarry Smith #define MAXHOSTNAME 100
establish(u_short portnum)103b75c6efcSBarry Smith int establish(u_short portnum)
104b75c6efcSBarry Smith {
105b75c6efcSBarry Smith char myname[MAXHOSTNAME + 1];
106b75c6efcSBarry Smith int s;
107b75c6efcSBarry Smith struct sockaddr_in sa;
108b75c6efcSBarry Smith struct hostent *hp;
109b75c6efcSBarry Smith #if defined(PETSC_HAVE_UNAME)
110b75c6efcSBarry Smith struct utsname utname;
111b75c6efcSBarry Smith #elif defined(PETSC_HAVE_GETCOMPUTERNAME)
112b75c6efcSBarry Smith int namelen = MAXHOSTNAME;
113b75c6efcSBarry Smith #endif
114b75c6efcSBarry Smith
115b75c6efcSBarry Smith /* Note we do not use gethostname since that is not POSIX */
116b75c6efcSBarry Smith #if defined(PETSC_HAVE_GETCOMPUTERNAME)
117b75c6efcSBarry Smith GetComputerName((LPTSTR)myname, (LPDWORD)&namelen);
118b75c6efcSBarry Smith #elif defined(PETSC_HAVE_UNAME)
119b75c6efcSBarry Smith uname(&utname);
120b75c6efcSBarry Smith strncpy(myname, utname.nodename, MAXHOSTNAME);
121b75c6efcSBarry Smith #endif
122b75c6efcSBarry Smith #if defined(PETSC_HAVE_BZERO)
123b75c6efcSBarry Smith bzero(&sa, sizeof(struct sockaddr_in));
124b75c6efcSBarry Smith #else
125b75c6efcSBarry Smith memset(&sa, 0, sizeof(struct sockaddr_in));
126b75c6efcSBarry Smith #endif
127b75c6efcSBarry Smith hp = gethostbyname(myname);
128b75c6efcSBarry Smith if (!hp) PETSC_MEX_ERRORQ("RECEIVE: error from gethostbyname\n");
129b75c6efcSBarry Smith
130*66218dbdSBarry Smith sa.sin_family = (sa_family_t)hp->h_addrtype;
131b75c6efcSBarry Smith sa.sin_port = htons(portnum);
132b75c6efcSBarry Smith
133b75c6efcSBarry Smith if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) PETSC_MEX_ERRORQ("RECEIVE: error from socket\n");
134b75c6efcSBarry Smith
135b75c6efcSBarry Smith {
136b75c6efcSBarry Smith int optval = 1; /* Turn on the option */
137b75c6efcSBarry Smith (void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
138b75c6efcSBarry Smith }
139b75c6efcSBarry Smith
140b75c6efcSBarry Smith while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
141b75c6efcSBarry Smith #if defined(PETSC_HAVE_WSAGETLASTERROR)
142b75c6efcSBarry Smith PetscErrorCode ierr;
143b75c6efcSBarry Smith ierr = WSAGetLastError();
144b75c6efcSBarry Smith if (ierr != WSAEADDRINUSE) {
145b75c6efcSBarry Smith #else
146b75c6efcSBarry Smith if (errno != EADDRINUSE) {
147b75c6efcSBarry Smith #endif
148b75c6efcSBarry Smith close(s);
149b75c6efcSBarry Smith PETSC_MEX_ERRORQ("RECEIVE: error from bind\n");
1504ad8454bSPierre Jolivet return -1;
151b75c6efcSBarry Smith }
152b75c6efcSBarry Smith close(listenport);
153b75c6efcSBarry Smith }
154b75c6efcSBarry Smith listen(s, 0);
1554ad8454bSPierre Jolivet return s;
156b75c6efcSBarry Smith }
157b75c6efcSBarry Smith
158b75c6efcSBarry Smith PETSC_EXTERN void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
159b75c6efcSBarry Smith {
160b75c6efcSBarry Smith int t, portnumber;
161b75c6efcSBarry Smith
162b75c6efcSBarry Smith /* check output parameters */
163b75c6efcSBarry Smith if (nlhs != 1) PETSC_MEX_ERROR("Open requires one output argument.");
164b75c6efcSBarry Smith
165b75c6efcSBarry Smith /* figure out portnumber user wants to use; default to 5005 */
166b75c6efcSBarry Smith if (!nrhs) {
167b75c6efcSBarry Smith char *str;
168b75c6efcSBarry Smith str = getenv("PETSC_VIEWER_SOCKET_PORT");
169b75c6efcSBarry Smith if (str) portnumber = atoi(str);
170b75c6efcSBarry Smith else portnumber = PETSCSOCKETDEFAULTPORT;
171b75c6efcSBarry Smith } else portnumber = (int)*mxGetPr(prhs[0]);
172b75c6efcSBarry Smith
173b75c6efcSBarry Smith /* open connection */
174b75c6efcSBarry Smith t = SOCKConnect_Private(portnumber);
175b75c6efcSBarry Smith if (t == -1) PETSC_MEX_ERROR("opening socket");
176b75c6efcSBarry Smith
177b75c6efcSBarry Smith plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
178b75c6efcSBarry Smith
179b75c6efcSBarry Smith *mxGetPr(plhs[0]) = t;
180b75c6efcSBarry Smith return;
181b75c6efcSBarry Smith }
182b75c6efcSBarry Smith
183b75c6efcSBarry Smith int main(int argc, char **argv)
184b75c6efcSBarry Smith {
185b75c6efcSBarry Smith return 0;
186b75c6efcSBarry Smith }
187