xref: /petsc/src/sys/classes/viewer/impls/socket/mex-scripts/sopen.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
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 /*-----------------------------------------------------------------*/
75b75c6efcSBarry Smith /* The listenport variable is an ugly hack. If the user hits a         */
76b75c6efcSBarry Smith /* control c while we are listening then we stop listening         */
77b75c6efcSBarry Smith /* but do not close the listen. Therefore if we try to bind again  */
78b75c6efcSBarry Smith /* and get an address in use, close the listen which was left      */
79b75c6efcSBarry Smith /* hanging; the problem is if the user uses several portnumbers    */
80b75c6efcSBarry Smith /* and control c we may not be able to close the correct listener. */
81b75c6efcSBarry Smith static int listenport;
82b75c6efcSBarry Smith /*-----------------------------------------------------------------*/
83b75c6efcSBarry Smith extern int establish(u_short);
8466976f2fSJacob Faibussowitsch static int SOCKConnect_Private(int portnumber)
85b75c6efcSBarry Smith {
86b75c6efcSBarry Smith   struct sockaddr_in isa;
87b75c6efcSBarry Smith #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
88b75c6efcSBarry Smith   size_t i;
89b75c6efcSBarry Smith #else
90b75c6efcSBarry Smith   int i;
91b75c6efcSBarry Smith #endif
92b75c6efcSBarry Smith   int t;
93b75c6efcSBarry Smith 
94b75c6efcSBarry Smith   /* open port*/
95b75c6efcSBarry Smith   listenport = establish((u_short)portnumber);
96b75c6efcSBarry Smith   if (listenport == -1) PETSC_MEX_ERRORQ("RECEIVE: unable to establish port\n");
97b75c6efcSBarry Smith 
98b75c6efcSBarry Smith   /* wait for someone to try to connect */
99b75c6efcSBarry Smith   i = sizeof(struct sockaddr_in);
100b75c6efcSBarry Smith   if ((t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) < 0) PETSC_MEX_ERRORQ("RECEIVE: error from accept\n");
101b75c6efcSBarry Smith   close(listenport);
102*4ad8454bSPierre Jolivet   return t;
103b75c6efcSBarry Smith }
104b75c6efcSBarry Smith /*-----------------------------------------------------------------*/
105b75c6efcSBarry Smith #define MAXHOSTNAME 100
106b75c6efcSBarry Smith int establish(u_short portnum)
107b75c6efcSBarry Smith {
108b75c6efcSBarry Smith   char               myname[MAXHOSTNAME + 1];
109b75c6efcSBarry Smith   int                s;
110b75c6efcSBarry Smith   struct sockaddr_in sa;
111b75c6efcSBarry Smith   struct hostent    *hp;
112b75c6efcSBarry Smith #if defined(PETSC_HAVE_UNAME)
113b75c6efcSBarry Smith   struct utsname utname;
114b75c6efcSBarry Smith #elif defined(PETSC_HAVE_GETCOMPUTERNAME)
115b75c6efcSBarry Smith   int namelen = MAXHOSTNAME;
116b75c6efcSBarry Smith #endif
117b75c6efcSBarry Smith 
118b75c6efcSBarry Smith   /* Note we do not use gethostname since that is not POSIX */
119b75c6efcSBarry Smith #if defined(PETSC_HAVE_GETCOMPUTERNAME)
120b75c6efcSBarry Smith   GetComputerName((LPTSTR)myname, (LPDWORD)&namelen);
121b75c6efcSBarry Smith #elif defined(PETSC_HAVE_UNAME)
122b75c6efcSBarry Smith   uname(&utname);
123b75c6efcSBarry Smith   strncpy(myname, utname.nodename, MAXHOSTNAME);
124b75c6efcSBarry Smith #endif
125b75c6efcSBarry Smith #if defined(PETSC_HAVE_BZERO)
126b75c6efcSBarry Smith   bzero(&sa, sizeof(struct sockaddr_in));
127b75c6efcSBarry Smith #else
128b75c6efcSBarry Smith   memset(&sa, 0, sizeof(struct sockaddr_in));
129b75c6efcSBarry Smith #endif
130b75c6efcSBarry Smith   hp = gethostbyname(myname);
131b75c6efcSBarry Smith   if (!hp) PETSC_MEX_ERRORQ("RECEIVE: error from gethostbyname\n");
132b75c6efcSBarry Smith 
133b75c6efcSBarry Smith   sa.sin_family = hp->h_addrtype;
134b75c6efcSBarry Smith   sa.sin_port   = htons(portnum);
135b75c6efcSBarry Smith 
136b75c6efcSBarry Smith   if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) PETSC_MEX_ERRORQ("RECEIVE: error from socket\n");
137b75c6efcSBarry Smith 
138b75c6efcSBarry Smith   {
139b75c6efcSBarry Smith     int optval = 1; /* Turn on the option */
140b75c6efcSBarry Smith     (void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
141b75c6efcSBarry Smith   }
142b75c6efcSBarry Smith 
143b75c6efcSBarry Smith   while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
144b75c6efcSBarry Smith #if defined(PETSC_HAVE_WSAGETLASTERROR)
145b75c6efcSBarry Smith     PetscErrorCode ierr;
146b75c6efcSBarry Smith     ierr = WSAGetLastError();
147b75c6efcSBarry Smith     if (ierr != WSAEADDRINUSE) {
148b75c6efcSBarry Smith #else
149b75c6efcSBarry Smith     if (errno != EADDRINUSE) {
150b75c6efcSBarry Smith #endif
151b75c6efcSBarry Smith       close(s);
152b75c6efcSBarry Smith       PETSC_MEX_ERRORQ("RECEIVE: error from bind\n");
153*4ad8454bSPierre Jolivet       return -1;
154b75c6efcSBarry Smith     }
155b75c6efcSBarry Smith     close(listenport);
156b75c6efcSBarry Smith   }
157b75c6efcSBarry Smith   listen(s, 0);
158*4ad8454bSPierre Jolivet   return s;
159b75c6efcSBarry Smith }
160b75c6efcSBarry Smith 
161b75c6efcSBarry Smith /*-----------------------------------------------------------------*/
162b75c6efcSBarry Smith /*                                                                 */
163b75c6efcSBarry Smith /*-----------------------------------------------------------------*/
164b75c6efcSBarry Smith PETSC_EXTERN void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
165b75c6efcSBarry Smith {
166b75c6efcSBarry Smith   int t, portnumber;
167b75c6efcSBarry Smith 
168b75c6efcSBarry Smith   /* check output parameters */
169b75c6efcSBarry Smith   if (nlhs != 1) PETSC_MEX_ERROR("Open requires one output argument.");
170b75c6efcSBarry Smith 
171b75c6efcSBarry Smith   /* figure out portnumber user wants to use; default to 5005 */
172b75c6efcSBarry Smith   if (!nrhs) {
173b75c6efcSBarry Smith     char *str;
174b75c6efcSBarry Smith     str = getenv("PETSC_VIEWER_SOCKET_PORT");
175b75c6efcSBarry Smith     if (str) portnumber = atoi(str);
176b75c6efcSBarry Smith     else portnumber = PETSCSOCKETDEFAULTPORT;
177b75c6efcSBarry Smith   } else portnumber = (int)*mxGetPr(prhs[0]);
178b75c6efcSBarry Smith 
179b75c6efcSBarry Smith   /* open connection */
180b75c6efcSBarry Smith   t = SOCKConnect_Private(portnumber);
181b75c6efcSBarry Smith   if (t == -1) PETSC_MEX_ERROR("opening socket");
182b75c6efcSBarry Smith 
183b75c6efcSBarry Smith   plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
184b75c6efcSBarry Smith 
185b75c6efcSBarry Smith   *mxGetPr(plhs[0]) = t;
186b75c6efcSBarry Smith   return;
187b75c6efcSBarry Smith }
188b75c6efcSBarry Smith 
189b75c6efcSBarry Smith int main(int argc, char **argv)
190b75c6efcSBarry Smith {
191b75c6efcSBarry Smith   return 0;
192b75c6efcSBarry Smith }
193