1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1998-2016. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  *
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #ifdef __WIN32__
27 #include <winsock2.h>
28 #include <direct.h>
29 #include <windows.h>
30 #include <winbase.h>
31 #else /* not __WIN32__ */
32 #include <errno.h>
33 #include <unistd.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <netdb.h>
38 #endif
39 #include "rmod_random__s.h"
40 #include "ei_connect.h"
41 
42 /* Used functions */
43 extern int gethostname(char *buf, int buflen);
44 static int getport(int sockd);
45 static int getlisten(int port);
46 static int init(ei_cnode *ec, int *sd, int *portnr, int *epmd_fd);
47 void terminate(int *fd, int *sd, int *epmd_fd);
48 static void server_loop(ei_cnode *ec, int fd, int sd);
49 
50 /* change these, or even better, make command-line args to program... */
51 #define COOKIE "flash"
52 #define SERVER "babbis"
53 #define NODENAMESZ 512
54 #define HOSTNAMESZ 256
55 #define INBUFSZ 1024
56 #define OUTBUFSZ 1024
57 
58 
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61     int sd;
62     int portnr;
63     int epmd_fd;
64     ei_cnode ec;
65 
66     /* crate file descriptors */
67     if (init(&ec, &sd, &portnr, &epmd_fd) < 0)
68 	return -1;
69 
70     /* start server loop */
71     server_loop(&ec, sd, epmd_fd);
72 
73     return 0;
74 }
75 
76 
77 
server_loop(ei_cnode * ec,int sd,int epmd_fd)78 static void server_loop(ei_cnode *ec, int sd, int epmd_fd)
79 {
80     ErlConnect conn;
81     erlang_msg msg;
82     int status=1;
83     CORBA_Environment *env;
84 
85     /* Create and init CORBA_Environment */
86     env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ);
87 
88     while (status >= 0) {
89 	status = 1;
90 
91 	if ((env->_fd = ei_accept(ec, sd, &conn)) < 0) {
92 	    /* error */
93 	    fprintf(stderr,"Accept failed: %s\n",strerror(errno));
94 	} else {
95 	    /* connection */
96 	    fprintf(stderr,"Accepted connection from %s\n",conn.nodename);
97 
98 	    while (status >= 0) {
99 
100 		/* write message to buffer */
101 		status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, &msg, &env->_iin);
102 		switch(status) {
103 		case ERL_SEND:
104 		case ERL_REG_SEND :
105 		    /* do transaction with fd */
106 		    rmod_random__switch(NULL,env);
107 
108 		    switch(env->_major) {
109 		    case CORBA_NO_EXCEPTION: /* Success */
110 			break;
111 		    case CORBA_SYSTEM_EXCEPTION: /* System exception */
112 			printf("Request failure, reason : %s\n",(char *) CORBA_exception_value(env));
113 			CORBA_exception_free(env);
114 			break;
115 		    default:	/* Should not come here */
116 			CORBA_exception_free(env);
117 			break;
118 		    }
119 
120 		    /* send outdata */
121 		    if (env->_iout > 0)
122 			ei_send_encoded(env->_fd,&env->_caller,env->_outbuf,env->_iout);
123 		    break;
124 
125 		case ERL_TICK :
126 		    break;
127 		default :	/* < 0 */
128 		    printf("Connection terminated\n");
129 		    break;
130 		}
131 	    }
132 	}
133 	status=0;		/* restart */
134     }
135 
136     /* close file descriptors */
137     terminate(&env->_fd, &sd, &epmd_fd);
138 
139     /* Free env & buffers */
140     CORBA_free(env->_inbuf);
141     CORBA_free(env->_outbuf);
142     CORBA_free(env);
143 }
144 
145 
146 
init(int * sd,int * portnr,int * epmd_fd)147 static int init(int *sd, int *portnr, int *epmd_fd)
148 {
149     char host[HOSTNAMESZ];
150     char servernode[NODENAMESZ];
151     struct hostent *h;
152 
153     /* get the host name */
154     if ((gethostname(host,HOSTNAMESZ)))
155 	fprintf(stderr,"can't find own hostname\n");
156     else {
157 	/* identify host */
158 	if (!(h = erl_gethostbyname(host)))
159 	    fprintf(stdout,"can't find own ip address\n");
160 	else {
161 
162 	    /* get a listen port. 0 means let system choose port number */
163 	    *sd = getlisten(0);
164 
165 	    /* what port did we get? */
166 	    /* this call not necessary if we specified port in call to getlisten() */
167 	    *portnr = getport(*sd);
168 
169 	    /* make the nodename server@host */
170 	    sprintf(servernode,"%s@%s",SERVER,host);
171 
172 	    /* initiate */
173 	    /* cnode, host, alive, alive@host, addr, cookie, creation */
174 	    if (ei_connect_xinit(ec, host, SERVER, servernode,
175 				 (Erl_IpAddr)(h->h_addr_list[0]),
176 				 COOKIE, 0) == 0) {
177 		/* let epmd know we are here */
178 		*epmd_fd = ei_publish(ec, *portnr);
179 		if (*epmd_fd >= 0)
180 		    return 0;
181 	    }
182 	}
183     }
184     return -1;
185 }
186 
187 
terminate(int * fd,int * sd,int * epmd_fd)188 void terminate(int *fd, int *sd, int *epmd_fd) {
189 
190     close(*fd);
191 
192     /* remove info from epnd */
193     close(*epmd_fd);
194 
195     /* return socket */
196     close(*sd);
197 
198 }
199 
200 
201 
202 /* tells you what port you are using on given socket */
getport(int sockd)203 static int getport(int sockd)
204 {
205     struct sockaddr_in addr;
206     int namelen = sizeof(addr);
207     int i;
208 
209     memset(&addr,0,sizeof(addr));
210 
211     if ((i = getsockname(sockd,(struct sockaddr *)&addr,&namelen))<0)
212 	return i;
213 
214     return ntohs(addr.sin_port);
215 }
216 
217 
218 
219 /* return a listen socket, bound to given port */
220 /* specify port = 0 to let system assign port */
getlisten(int port)221 static int getlisten(int port)
222 {
223     int sockd;
224     struct sockaddr_in inaddr;
225     int opt = 1;
226     int i;
227 
228     /* get listen socket */
229     if ((sockd = socket(AF_INET,SOCK_STREAM,0)) < 0) return sockd;
230 
231     if ((i=setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)))<0)
232 	return i;
233 
234     /* bind to requested port */
235     memset(&inaddr,0,sizeof(inaddr));
236     inaddr.sin_family = AF_INET;
237     inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
238     inaddr.sin_port = htons(port);
239 
240     if ((i = bind(sockd,(struct sockaddr*) &inaddr, sizeof(inaddr))) < 0)
241 	return i;
242 
243     listen(sockd,5);
244 
245     return sockd;
246 }
247