aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/legacy/erl_connect.c
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/legacy/erl_connect.c
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src/legacy/erl_connect.c')
-rw-r--r--lib/erl_interface/src/legacy/erl_connect.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c
new file mode 100644
index 0000000000..3c8c946506
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_connect.c
@@ -0,0 +1,457 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Purpose: Connect to any node at any host.
+ */
+
+/***************************************************************************
+ *
+ * 'erl_interface' node connection handling is to use 'ei' for all
+ * operations without access to the internal structure of saved data,
+ * e.i. it should use the public interface functions. The connection
+ * handling can be seen as a restricted node interface where only one
+ * node can be used in one operating system process.
+ *
+ ***************************************************************************/
+
+#include "eidef.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <timers.h>
+
+#include "erl_error.h"
+
+#else /* some other unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */
+#endif
+
+/* common includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* FIXME include less */
+#include "erl_interface.h"
+#include "erl_connect.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+#include "putget.h"
+#include "ei.h"
+#include "ei_connect_int.h"
+#include "ei_locking.h"
+#include "ei_epmd.h"
+#include "ei_internal.h"
+
+/* rpc_from() uses a buffer this size */
+#ifndef MAX_RECEIVE_BUF
+#define MAX_RECEIVE_BUF 32*1024
+#endif
+
+/* This is the global state of the old erl_* API */
+
+static ei_cnode erl_if_ec;
+
+/***************************************************************************
+ *
+ * API: erl_connect_init()
+ * API: erl_connect_xinit()
+ *
+ * Returns 1 on success and 0 on failure.
+ * Not documented to set erl_errno.
+ *
+ ***************************************************************************/
+
+int erl_connect_init(int this_node_number, char *cookie, short creation)
+{
+ char nn[MAXATOMLEN+1];
+
+ sprintf(nn, "c%d", this_node_number);
+
+ return ei_connect_init(&erl_if_ec, nn, cookie, creation) == 0;
+}
+
+/* FIXME documented to use struct in_addr as addr */
+
+int erl_connect_xinit(char *thishostname,
+ char *thisalivename,
+ char *thisnodename,
+ struct in_addr *thisipaddr,
+ char *cookie,
+ short creation)
+{
+ return ei_connect_xinit(&erl_if_ec, thishostname, thisalivename,
+ thisnodename, thisipaddr, cookie, creation) >= 0;
+}
+
+/***************************************************************************
+ *
+ * API: erl_connect()
+ * API: erl_xconnect()
+ *
+ * Set up a connection to a given Node, and interchange hand shake
+ * messages with it.
+ *
+ * Returns valid file descriptor on success and < 0 on failure.
+ * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2)
+ * or connect(2).
+ *
+ ***************************************************************************/
+
+int erl_connect(char *nodename)
+{
+ int res = ei_connect(&erl_if_ec, nodename);
+ if (res < 0) erl_errno = EIO;
+ return res;
+}
+
+/* FIXME documented to use struct in_addr as addr */
+
+int erl_xconnect(Erl_IpAddr addr, char *alivename)
+{
+ return ei_xconnect(&erl_if_ec, addr, alivename);
+}
+
+
+/***************************************************************************
+ *
+ * API: erl_close_connection()
+ *
+ * Close a connection. FIXME call ei_close_connection() later.
+ *
+ * Returns valid file descriptor on success and < 0 on failure.
+ * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2)
+ * or connect(2).
+ *
+ ***************************************************************************/
+
+int erl_close_connection(int fd)
+{
+ return closesocket(fd);
+}
+
+/*
+ * Accept and initiate a connection from an other
+ * Erlang node. Return a file descriptor at success,
+ * otherwise -1;
+ */
+int erl_accept(int lfd, ErlConnect *conp)
+{
+ return ei_accept(&erl_if_ec, lfd, conp);
+}
+
+
+/* Receives a message from an Erlang socket.
+ * If the message was a TICK it is immediately
+ * answered. Returns: ERL_ERROR, ERL_TICK or
+ * the number of bytes read.
+ */
+int erl_receive(int s, unsigned char *bufp, int bufsize)
+{
+ return ei_receive(s, bufp, bufsize);
+}
+
+/*
+ * Send an Erlang message to a registered process
+ * at the Erlang node, connected with a socket.
+ */
+int erl_reg_send(int fd, char *server_name, ETERM *msg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new_with_version(&x);
+ if (ei_x_encode_term(&x, msg) < 0) {
+ erl_errno = EINVAL;
+ r = 0;
+ } else {
+ r = ei_reg_send(&erl_if_ec, fd, server_name, x.buff, x.index);
+ }
+ ei_x_free(&x);
+ return r == 0;
+}
+
+/*
+ * Sends an Erlang message to a process at an Erlang node
+ */
+int erl_send(int fd, ETERM *to ,ETERM *msg)
+{
+ erlang_pid topid;
+ ei_x_buff x;
+ int r;
+
+ ei_x_new_with_version(&x);
+ ei_x_encode_term(&x, msg);
+ /* make the to-pid */
+ if (!ERL_IS_PID(to)) {
+ ei_x_free(&x);
+ erl_errno = EINVAL;
+ return -1;
+ }
+
+ strcpy(topid.node, (char *)ERL_PID_NODE(to));
+ topid.num = ERL_PID_NUMBER(to);
+ topid.serial = ERL_PID_SERIAL(to);
+ topid.creation = ERL_PID_CREATION(to);
+ r = ei_send(fd, &topid, x.buff, x.index);
+ ei_x_free(&x);
+ return r == 0;
+}
+
+static int erl_do_receive_msg(int fd, ei_x_buff* x, ErlMessage* emsg)
+{
+ erlang_msg msg;
+
+ int r;
+ msg.from.node[0] = msg.to.node[0] = '\0';
+ r = ei_do_receive_msg(fd, 0, &msg, x, 0);
+
+ if (r == ERL_MSG) {
+ int index = 0;
+ emsg->type = msg.msgtype;
+
+ /*
+ We can't call ei_decode_term for cases where there are no
+ data following the type information. If there are other
+ types added later where there are data this case has to be
+ extended.
+ */
+
+ switch (msg.msgtype) {
+ case ERL_SEND:
+ case ERL_REG_SEND:
+ case ERL_EXIT:
+ case ERL_EXIT2:
+ if (ei_decode_term(x->buff, &index, &emsg->msg) < 0)
+ r = ERL_ERROR;
+ break;
+ default:
+ emsg->msg = NULL; /* Not needed but may avoid problems for unsafe caller */
+ break;
+ }
+ } else
+ emsg->msg = NULL;
+ if (msg.from.node[0] != '\0')
+ emsg->from = erl_mk_pid(msg.from.node, msg.from.num, msg.from.serial, msg.from.creation);
+ if (msg.to.node[0] != '\0')
+ emsg->to = erl_mk_pid(msg.to.node, msg.to.num, msg.to.serial, msg.to.creation);
+ return r;
+}
+
+int erl_receive_msg(int fd, unsigned char *buf, int bufsize, ErlMessage *emsg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new(&x);
+ r = erl_do_receive_msg(fd, &x, emsg);
+ /* FIXME what is this about? */
+ if (bufsize > x.index)
+ bufsize = x.index;
+ memcpy(buf, x.buff, bufsize);
+ ei_x_free(&x);
+ return r;
+}
+
+int erl_xreceive_msg(int fd, unsigned char **buf, int *bufsize,
+ ErlMessage *emsg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new(&x);
+ r = erl_do_receive_msg(fd, &x, emsg);
+ if (*bufsize < x.index)
+ *buf = erl_realloc(*buf, x.index);
+ *bufsize = x.index;
+ memcpy(*buf, x.buff, *bufsize);
+ ei_x_free(&x);
+ return r;
+}
+
+/*
+ * The RPC consists of two parts, send and receive.
+ * Here is the send part !
+ * { PidFrom, { call, Mod, Fun, Args, user }}
+ */
+/*
+ * Now returns non-negative number for success, negative for failure.
+ */
+int erl_rpc_to(int fd, char *mod, char *fun, ETERM *args)
+{
+ int r;
+ ei_x_buff x;
+
+ ei_x_new(&x);
+ ei_x_encode_term(&x, args);
+ r = ei_rpc_to(&erl_if_ec, fd, mod, fun, x.buff, x.index);
+ ei_x_free(&x);
+ return r;
+} /* rpc_to */
+
+ /*
+ * And here is the rpc receiving part. A negative
+ * timeout means 'infinity'. Returns either of: ERL_MSG,
+ * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
+*/
+int erl_rpc_from(int fd, int timeout, ErlMessage *emsg)
+{
+ fd_set readmask;
+ struct timeval tv;
+ struct timeval *t = NULL;
+ unsigned char rbuf[MAX_RECEIVE_BUF];
+
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ t = &tv;
+ }
+
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+
+ switch (select(fd+1, &readmask, NULL, NULL, t)) {
+ case -1:
+ erl_errno = EIO;
+ return ERL_ERROR;
+ case 0:
+ erl_errno = ETIMEDOUT;
+ return ERL_TIMEOUT;
+ default:
+ if (FD_ISSET(fd, &readmask))
+ return erl_receive_msg(fd, rbuf, MAX_RECEIVE_BUF, emsg);
+ else {
+ erl_errno = EIO;
+ return ERL_ERROR;
+ }
+ }
+} /* rpc_from */
+
+/*
+ * A true RPC. It return a NULL pointer
+ * in case of failure, otherwise a valid
+ * (ETERM *) pointer containing the reply
+ */
+ETERM *erl_rpc(int fd, char *mod, char *fun, ETERM *args)
+{
+ int i;
+ ETERM *ep;
+ ErlMessage emsg;
+
+ if (erl_rpc_to(fd, mod, fun, args) < 0) {
+ return NULL; }
+ while ((i=erl_rpc_from(fd, ERL_NO_TIMEOUT, &emsg)) == ERL_TICK);
+
+ if (i == ERL_ERROR) return NULL;
+
+ ep = erl_element(2,emsg.msg); /* {RPC_Tag, RPC_Reply} */
+ erl_free_term(emsg.msg);
+ erl_free_term(emsg.to);
+ return ep;
+} /* rpc */
+
+
+/*
+ ** Handshake
+ */
+
+int erl_publish(int port)
+{
+ return ei_publish(&erl_if_ec, port);
+}
+
+int erl_unpublish(const char *alive)
+{
+ return ei_unpublish_tmo(alive,0);
+}
+
+erlang_pid *erl_self(void)
+{
+ return ei_self(&erl_if_ec);
+}
+
+const char *erl_thisnodename(void)
+{
+ return ei_thisnodename(&erl_if_ec);
+}
+
+const char *erl_thishostname(void)
+{
+ return ei_thishostname(&erl_if_ec);
+}
+
+const char *erl_thisalivename(void)
+{
+ return ei_thisalivename(&erl_if_ec);
+}
+
+const char *erl_thiscookie(void)
+{
+ return ei_thiscookie(&erl_if_ec);
+}
+
+short erl_thiscreation(void)
+{
+ return ei_thiscreation(&erl_if_ec);
+}