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