xref: /petsc/src/sys/classes/viewer/impls/socket/mex-scripts/sopen.c (revision 03047865b8d8757cf1cf9cda45785c1537b01dc1)
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