diff options
| author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 | 
|---|---|---|
| committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 | 
| commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
| tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/legacy/erl_connect.c | |
| download | otp-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.c | 457 | 
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); +} | 
