1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1996-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  * Purpose: Connect to any node at any host.
22  */
23 
24 /***************************************************************************
25  *
26  *  'erl_interface' node connection handling is to use 'ei' for all
27  *  operations without access to the internal structure of saved data,
28  *  e.i. it should use the public interface functions. The connection
29  *  handling can be seen as a restricted node interface where only one
30  *  node can be used in one operating system process.
31  *
32  ***************************************************************************/
33 
34 #include "eidef.h"
35 
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 
40 #ifdef __WIN32__
41 #include <winsock2.h>
42 #include <windows.h>
43 #include <winbase.h>
44 
45 #elif VXWORKS
46 #include <vxWorks.h>
47 #include <hostLib.h>
48 #include <selectLib.h>
49 #include <ifLib.h>
50 #include <sockLib.h>
51 #include <taskLib.h>
52 #include <inetLib.h>
53 
54 #include <unistd.h>
55 #include <sys/types.h>
56 #include <sys/times.h>
57 #include <unistd.h>
58 #include <sys/types.h>
59 #include <sys/socket.h>
60 #include <netinet/in.h>
61 #include <netinet/tcp.h>
62 #include <timers.h>
63 
64 #include "erl_error.h"
65 
66 #else /* some other unix */
67 #include <unistd.h>
68 #include <sys/types.h>
69 #include <sys/times.h>
70 
71 #if TIME_WITH_SYS_TIME
72 # include <sys/time.h>
73 # include <time.h>
74 #else
75 # if HAVE_SYS_TIME_H
76 #  include <sys/time.h>
77 # else
78 #  include <time.h>
79 # endif
80 #endif
81 
82 #include <sys/socket.h>
83 #include <netinet/in.h>
84 #include <netinet/tcp.h>
85 #include <arpa/inet.h>
86 #include <netdb.h>
87 #include <sys/utsname.h>  /* for gen_challenge (NEED FIX?) */
88 #endif
89 
90 /* common includes */
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <errno.h>
95 
96 /* FIXME include less */
97 #include "erl_interface.h"
98 #include "erl_connect.h"
99 #include "erl_eterm.h"
100 #include "erl_malloc.h"
101 #include "putget.h"
102 #include "ei.h"
103 #include "ei_connect_int.h"
104 #include "ei_locking.h"
105 #include "ei_epmd.h"
106 #include "ei_internal.h"
107 
108 /* rpc_from() uses a buffer this size */
109 #ifndef MAX_RECEIVE_BUF
110 #define MAX_RECEIVE_BUF 32*1024
111 #endif
112 
113 /* This is the global state of the old erl_* API */
114 
115 static ei_cnode erl_if_ec;
116 
117 /***************************************************************************
118  *
119  *  API: erl_connect_init()
120  *  API: erl_connect_xinit()
121  *
122  *  Returns 1 on success and 0 on failure.
123  *  Not documented to set erl_errno.
124  *
125  ***************************************************************************/
126 
erl_connect_init(int this_node_number,char * cookie,short creation)127 int erl_connect_init(int this_node_number, char *cookie, short creation)
128 {
129     char nn[MAXATOMLEN];
130 
131     sprintf(nn, "c%d", this_node_number);
132 
133     return ei_connect_init(&erl_if_ec, nn, cookie, creation) == 0;
134 }
135 
136 /* FIXME documented to use struct in_addr as addr */
137 
erl_connect_xinit(char * thishostname,char * thisalivename,char * thisnodename,struct in_addr * thisipaddr,char * cookie,short creation)138 int erl_connect_xinit(char *thishostname,
139 		      char *thisalivename,
140 		      char *thisnodename,
141 		      struct in_addr *thisipaddr,
142 		      char *cookie,
143 		      short creation)
144 {
145     return ei_connect_xinit(&erl_if_ec, thishostname, thisalivename,
146 			    thisnodename, thisipaddr, cookie, creation) >= 0;
147 }
148 
149 /***************************************************************************
150  *
151  *  API: erl_connect()
152  *  API: erl_xconnect()
153  *
154  *  Set up a connection to a given Node, and interchange hand shake
155  *  messages with it.
156  *
157  *  Returns valid file descriptor on success and < 0 on failure.
158  *  Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2)
159  *  or connect(2).
160  *
161  ***************************************************************************/
162 
erl_connect(char * nodename)163 int erl_connect(char *nodename)
164 {
165   int res = ei_connect(&erl_if_ec, nodename);
166   if (res < 0) erl_errno = EIO;
167   return res;
168 }
169 
170 /* FIXME documented to use struct in_addr as addr */
171 
erl_xconnect(Erl_IpAddr addr,char * alivename)172 int erl_xconnect(Erl_IpAddr addr, char *alivename)
173 {
174     return ei_xconnect(&erl_if_ec, addr, alivename);
175 }
176 
177 
178 /***************************************************************************
179  *
180  *  API: erl_close_connection()
181  *
182  *  Returns 0 on success and -1 on failure.
183  *
184  ***************************************************************************/
185 
erl_close_connection(int fd)186 int erl_close_connection(int fd)
187 {
188     return ei_close_connection(fd);
189 }
190 
191 /*
192  * Accept and initiate a connection from another
193  * Erlang node. Return a file descriptor at success,
194  * otherwise -1;
195  */
erl_accept(int lfd,ErlConnect * conp)196 int erl_accept(int lfd, ErlConnect *conp)
197 {
198     return ei_accept(&erl_if_ec, lfd, conp);
199 }
200 
201 
202 /* Receives a message from an Erlang socket.
203  * If the message was a TICK it is immediately
204  * answered. Returns: ERL_ERROR, ERL_TICK or
205  * the number of bytes read.
206  */
erl_receive(int s,unsigned char * bufp,int bufsize)207 int erl_receive(int s, unsigned char *bufp, int bufsize)
208 {
209     return ei_receive(s, bufp, bufsize);
210 }
211 
212 /*
213  * Send an Erlang message to a registered process
214  * at the Erlang node, connected with a socket.
215  */
erl_reg_send(int fd,char * server_name,ETERM * msg)216 int erl_reg_send(int fd, char *server_name, ETERM *msg)
217 {
218     ei_x_buff x;
219     int r;
220 
221     if (ei_x_new_with_version(&x) < 0) {
222         erl_errno = ENOMEM;
223         return 0;
224     }
225     if (ei_x_encode_term(&x, msg) < 0) {
226 	erl_errno = EINVAL;
227 	r = 0;
228     } else {
229 	r = ei_reg_send(&erl_if_ec, fd, server_name, x.buff, x.index);
230     }
231     ei_x_free(&x);
232     return r == 0;
233 }
234 
235 /*
236  * Sends an Erlang message to a process at an Erlang node
237  */
erl_send(int fd,ETERM * to,ETERM * msg)238 int erl_send(int fd, ETERM *to ,ETERM *msg)
239 {
240     erlang_pid topid;
241     ei_x_buff x;
242     int r;
243 
244     ei_x_new_with_version(&x);
245     ei_x_encode_term(&x, msg);
246     /* make the to-pid */
247     if (!ERL_IS_PID(to)) {
248 	ei_x_free(&x);
249 	erl_errno = EINVAL;
250 	return -1;
251     }
252 
253     if (to->uval.pidval.node.latin1) {
254 	strcpy(topid.node, to->uval.pidval.node.latin1);
255     }
256     else {
257 	strcpy(topid.node, to->uval.pidval.node.utf8);
258     }
259     topid.num = ERL_PID_NUMBER(to);
260     topid.serial = ERL_PID_SERIAL(to);
261     topid.creation = ERL_PID_CREATION(to);
262     r = ei_send(fd, &topid, x.buff, x.index);
263     ei_x_free(&x);
264     return r == 0;
265 }
266 
erl_do_receive_msg(int fd,ei_x_buff * x,ErlMessage * emsg)267 static int erl_do_receive_msg(int fd, ei_x_buff* x, ErlMessage* emsg)
268 {
269     erlang_msg msg;
270 
271     int r;
272     msg.from.node[0] = msg.to.node[0] = msg.toname[0] = '\0';
273     r = ei_do_receive_msg(fd, 0, &msg, x, 0);
274 
275     if (r == ERL_MSG) {
276 	int index = 0;
277 	emsg->type = msg.msgtype;
278 
279 	/*
280 	  We can't call ei_decode_term for cases where there are no
281 	  data following the type information. If there are other
282 	  types added later where there are data this case has to be
283 	  extended.
284 	*/
285 
286 	switch (msg.msgtype) {
287 	case ERL_SEND:
288 	case ERL_REG_SEND:
289 	case ERL_EXIT:
290 	case ERL_EXIT2:
291 	  if (ei_decode_term(x->buff, &index, &emsg->msg) < 0)
292 	    r = ERL_ERROR;
293 	  break;
294 	default:
295 	  emsg->msg = NULL;	/* Not needed but may avoid problems for unsafe caller  */
296 	  break;
297 	}
298     } else
299 	emsg->msg = NULL;
300     if (msg.from.node[0] != '\0')
301 	emsg->from = erl_mk_pid(msg.from.node, msg.from.num, msg.from.serial, msg.from.creation);
302     else
303 	emsg->from = NULL;
304     if (msg.to.node[0] != '\0')
305 	emsg->to = erl_mk_pid(msg.to.node, msg.to.num, msg.to.serial, msg.to.creation);
306     else
307 	emsg->to = NULL;
308     strcpy(emsg->to_name, msg.toname);
309     return r;
310 }
311 
erl_receive_msg(int fd,unsigned char * buf,int bufsize,ErlMessage * emsg)312 int erl_receive_msg(int fd, unsigned char *buf, int bufsize, ErlMessage *emsg)
313 {
314     ei_x_buff x;
315     int r;
316 
317     ei_x_new(&x);
318     r = erl_do_receive_msg(fd, &x, emsg);
319     /* FIXME what is this about? */
320     if (bufsize > x.index)
321 	bufsize = x.index;
322     memcpy(buf, x.buff, bufsize);
323     ei_x_free(&x);
324     return r;
325 }
326 
erl_xreceive_msg(int fd,unsigned char ** buf,int * bufsize,ErlMessage * emsg)327 int erl_xreceive_msg(int fd, unsigned char **buf, int *bufsize,
328 		  ErlMessage *emsg)
329 {
330     ei_x_buff x;
331     int r;
332 
333     ei_x_new(&x);
334     r = erl_do_receive_msg(fd, &x, emsg);
335     if (*bufsize < x.index)
336 	*buf = erl_realloc(*buf, x.index);
337     *bufsize = x.index;
338     memcpy(*buf, x.buff, *bufsize);
339     ei_x_free(&x);
340     return r;
341 }
342 
343 /*
344  * The RPC consists of two parts, send and receive.
345  * Here is the send part !
346  * { PidFrom, { call, Mod, Fun, Args, user }}
347  */
348 /*
349  * Now returns non-negative number for success, negative for failure.
350  */
erl_rpc_to(int fd,char * mod,char * fun,ETERM * args)351 int erl_rpc_to(int fd, char *mod, char *fun, ETERM *args)
352 {
353     int r;
354     ei_x_buff x;
355 
356     ei_x_new(&x);
357     ei_x_encode_term(&x, args);
358     r = ei_rpc_to(&erl_if_ec, fd, mod, fun, x.buff, x.index);
359     ei_x_free(&x);
360     return r;
361 } /* rpc_to */
362 
363   /*
364   * And here is the rpc receiving part. A negative
365   * timeout means 'infinity'. Returns either of: ERL_MSG,
366   * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
367 */
erl_rpc_from(int fd,int timeout,ErlMessage * emsg)368 int erl_rpc_from(int fd, int timeout, ErlMessage *emsg)
369 {
370     fd_set readmask;
371     struct timeval tv;
372     struct timeval *t = NULL;
373     unsigned char rbuf[MAX_RECEIVE_BUF];
374 
375     if (timeout >= 0) {
376 	tv.tv_sec = timeout / 1000;
377 	tv.tv_usec = (timeout % 1000) * 1000;
378 	t = &tv;
379     }
380 
381     FD_ZERO(&readmask);
382     FD_SET(fd,&readmask);
383 
384     switch (select(fd+1, &readmask, NULL, NULL, t)) {
385     case -1:
386 	erl_errno = EIO;
387 	return ERL_ERROR;
388     case 0:
389 	erl_errno = ETIMEDOUT;
390 	return ERL_TIMEOUT;
391     default:
392 	if (FD_ISSET(fd, &readmask))
393 	    return erl_receive_msg(fd, rbuf, MAX_RECEIVE_BUF, emsg);
394 	else {
395 	    erl_errno = EIO;
396 	    return ERL_ERROR;
397 	}
398     }
399 } /* rpc_from */
400 
401 /*
402  * A true RPC. It return a NULL pointer
403  * in case of failure, otherwise a valid
404  * (ETERM *) pointer containing the reply
405  */
erl_rpc(int fd,char * mod,char * fun,ETERM * args)406 ETERM *erl_rpc(int fd, char *mod, char *fun, ETERM *args)
407 {
408     int i;
409     ETERM *ep;
410     ErlMessage emsg;
411 
412     if (erl_rpc_to(fd, mod, fun, args) < 0) {
413 	return NULL; }
414     while ((i=erl_rpc_from(fd, ERL_NO_TIMEOUT, &emsg)) == ERL_TICK);
415 
416     if (i == ERL_ERROR)  return NULL;
417 
418     ep = erl_element(2,emsg.msg); /* {RPC_Tag, RPC_Reply} */
419     erl_free_term(emsg.msg);
420     erl_free_term(emsg.to);
421     return ep;
422 } /* rpc */
423 
424 
425 /*
426  ** Handshake
427  */
428 
erl_publish(int port)429 int erl_publish(int port)
430 {
431     return ei_publish(&erl_if_ec, port);
432 }
433 
erl_unpublish(const char * alive)434 int erl_unpublish(const char *alive)
435 {
436     return ei_unpublish_tmo(alive,0);
437 }
438 
erl_self(void)439 erlang_pid *erl_self(void)
440 {
441     return ei_self(&erl_if_ec);
442 }
443 
erl_thisnodename(void)444 const char *erl_thisnodename(void)
445 {
446     return ei_thisnodename(&erl_if_ec);
447 }
448 
erl_thishostname(void)449 const char *erl_thishostname(void)
450 {
451     return ei_thishostname(&erl_if_ec);
452 }
453 
erl_thisalivename(void)454 const char *erl_thisalivename(void)
455 {
456     return ei_thisalivename(&erl_if_ec);
457 }
458 
erl_thiscookie(void)459 const char *erl_thiscookie(void)
460 {
461     return ei_thiscookie(&erl_if_ec);
462 }
463 
erl_thiscreation(void)464 short erl_thiscreation(void)
465 {
466     return ei_thiscreation(&erl_if_ec);
467 }
468