summaryrefslogtreecommitdiff
path: root/lib/erl_interface
diff options
context:
space:
mode:
Diffstat (limited to 'lib/erl_interface')
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c123
-rw-r--r--lib/erl_interface/src/epmd/ei_epmd.h1
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE.erl47
3 files changed, 141 insertions, 30 deletions
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 4280b8f62e..90ddac5dd3 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -103,6 +103,8 @@ static int recv_challenge(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
int pkt_sz, unsigned char digest[16],
unsigned challenge, unsigned ms);
+static int recv_complement(ei_socket_callbacks *cbs, void *ctx,
+ int pkt_sz, DistFlags *flags, unsigned ms);
static int recv_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
int pkt_sz, unsigned our_challenge,
char cookie[],
@@ -115,7 +117,7 @@ static int recv_challenge_ack(ei_socket_callbacks *cbs, void *ctx,
char cookie[], unsigned ms);
static int send_name(ei_cnode *ec, void *ctx, int pkt_sz, unsigned ms);
static int recv_name(ei_socket_callbacks *cbs, void *ctx, int pkt_sz,
- DistFlags *flags,
+ char* send_name_tag, DistFlags *flags,
char *namebuf, unsigned ms);
static int ei_connect_helper(ei_cnode* ec,
Erl_IpAddr ip_addr,
@@ -1531,6 +1533,7 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
int fd;
DistFlags her_flags;
char tmp_nodename[MAXNODELEN+1];
+ char send_name_tag;
char *her_name;
int pkt_sz, err;
struct sockaddr_in addr;
@@ -1605,7 +1608,8 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote");
- if (recv_name(cbs, ctx, pkt_sz, &her_flags, her_name, tmo)) {
+ if (recv_name(cbs, ctx, pkt_sz, &send_name_tag, &her_flags,
+ her_name, tmo)) {
EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed");
goto error;
}
@@ -1620,6 +1624,10 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
our_challenge = gen_challenge();
if (send_challenge(ec, ctx, pkt_sz, our_challenge, her_flags, tmo))
goto error;
+ if (send_name_tag == 'n') {
+ if (recv_complement(cbs, ctx, pkt_sz, &her_flags, tmo))
+ goto error;
+ }
if (recv_challenge_reply(cbs, ctx, pkt_sz, our_challenge,
ec->ei_connect_cookie, &her_challenge, tmo))
goto error;
@@ -2517,6 +2525,63 @@ static int send_challenge_reply(ei_socket_callbacks *cbs, void *ctx,
return 0;
}
+static int recv_complement(ei_socket_callbacks *cbs,
+ void *ctx,
+ int pkt_sz,
+ DistFlags *flags,
+ unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+ char *s;
+ char tag;
+ unsigned int creation;
+
+ erl_errno = EIO; /* Default */
+
+ if ((rlen = read_hs_package(cbs, ctx, pkt_sz, &buf, &buflen, &is_static, ms)) != 21) {
+ EI_TRACE_ERR1("recv_complement",
+ "<- RECV_COMPLEMENT socket read failed (%d)",rlen);
+ goto error;
+ }
+
+ s = buf;
+ if ((tag = get8(s)) != 'c') {
+ EI_TRACE_ERR2("recv_complement",
+ "<- RECV_COMPLEMENT incorrect tag, "
+ "expected 'c' got '%c' (%u)",tag,tag);
+ goto error;
+ }
+ *flags |= (DistFlags)get32be(s) << 32;
+
+ if ((~*flags) & (DFLAG_DIST_MANDATORY | DFLAG_HANDSHAKE_23)) {
+ EI_TRACE_ERR0("recv_complement","<- RECV_COMPLEMENT peer cannot "
+ "handle all mandatory capabilities");
+ goto error;
+ }
+
+ creation = get32be(s);
+ if (!is_static)
+ free(buf);
+
+ if (ei_tracelevel >= 3) {
+ EI_TRACE_CONN1("recv_complement",
+ "<- RECV_COMPLEMENT (ok) creation = %u",
+ creation);
+ }
+ /* We don't have any use for 'creation' of other node, so we drop it */
+ erl_errno = 0;
+ return 0;
+
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
static int recv_challenge_reply(ei_socket_callbacks *cbs,
void *ctx,
int pkt_sz,
@@ -2673,7 +2738,7 @@ error:
}
static int recv_name(ei_socket_callbacks *cbs, void *ctx,
- int pkt_sz,
+ int pkt_sz, char *send_name_tag,
DistFlags *flags, char *namebuf, unsigned ms)
{
char dbuf[DEFBUF_SIZ];
@@ -2685,6 +2750,7 @@ static int recv_name(ei_socket_callbacks *cbs, void *ctx,
char *s;
char tmp_nodename[MAXNODELEN+1];
char tag;
+ DistFlags flag_mask;
erl_errno = EIO; /* Default */
@@ -2695,25 +2761,46 @@ static int recv_name(ei_socket_callbacks *cbs, void *ctx,
}
s = buf;
tag = get8(s);
- if (tag != 'N') {
+ *send_name_tag = tag;
+ if (tag != 'n' && tag != 'N') {
EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "
- "expected 'N', got '%c' (%u)",tag,tag);
+ "expected 'n' or 'N', got '%c' (%u)",tag,tag);
goto error;
}
- if (rlen < 1+8+4+2) {
- EI_TRACE_ERR1("recv_name","<- RECV_NAME 'N' packet too short (%d)",
- rlen)
- goto error;
+ if (tag == 'n') {
+ unsigned int version;
+ if (rlen < 1+2+4) {
+ EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' packet too short (%d)",
+ rlen)
+ goto error;
+ }
+ version = get16be(s);
+ if (version < EI_DIST_5) {
+ EI_TRACE_ERR1("recv_name","<- RECV_NAME 'n' invalid version=%d",
+ version)
+ goto error;
+ }
+ *flags = get32be(s);
+ flag_mask = ((DistFlags)1 << 32) - 1;
+ namelen = rlen - (1+2+4);
+ }
+ else { /* tag == 'N' */
+ if (rlen < 1+8+4+2) {
+ EI_TRACE_ERR1("recv_name","<- RECV_NAME 'N' packet too short (%d)",
+ rlen)
+ goto error;
+ }
+ *flags = get64be(s);
+ flag_mask = ~(DistFlags)0;
+ s += 4; /* ignore peer 'creation' */
+ namelen = get16be(s);
}
- *flags = get64be(s);
- s += 4; /* ignore peer 'creation' */
- namelen = get16be(s);
if (*flags & DFLAG_MANDATORY_25_DIGEST) {
*flags |= DFLAG_DIST_MANDATORY_25;
}
- if ((*flags & DFLAG_DIST_MANDATORY) != DFLAG_DIST_MANDATORY) {
+ if ((~*flags) & flag_mask & (DFLAG_DIST_MANDATORY | DFLAG_HANDSHAKE_23)) {
EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
"handle all mandatory capabilities");
erl_errno = EIO;
@@ -2724,8 +2811,8 @@ static int recv_name(ei_socket_callbacks *cbs, void *ctx,
namebuf = &tmp_nodename[0];
if (namelen > MAXNODELEN || s+namelen > buf+rlen) {
- EI_TRACE_ERR1("recv_name","<- RECV_NAME nodename too long (%d)",
- namelen);
+ EI_TRACE_ERR2("recv_name","<- RECV_NAME '%c' nodename too long (%d)",
+ tag, namelen);
goto error;
}
@@ -2734,9 +2821,9 @@ static int recv_name(ei_socket_callbacks *cbs, void *ctx,
if (!is_static)
free(buf);
- EI_TRACE_CONN2("recv_name",
- "<- RECV_NAME (ok) node = %s, flags = %u",
- namebuf, *flags);
+ EI_TRACE_CONN3("recv_name",
+ "<- RECV_NAME (ok) node = %s, tag = %c, flags = %u",
+ namebuf,tag,*flags);
erl_errno = 0;
return 0;
diff --git a/lib/erl_interface/src/epmd/ei_epmd.h b/lib/erl_interface/src/epmd/ei_epmd.h
index a6363119f1..f3b01abe35 100644
--- a/lib/erl_interface/src/epmd/ei_epmd.h
+++ b/lib/erl_interface/src/epmd/ei_epmd.h
@@ -24,6 +24,7 @@
#define INADDR_LOOPBACK ((u_long) 0x7F000001)
#endif
+#define EI_DIST_5 5 /* OTP R4 - 22 */
#define EI_DIST_6 6 /* OTP 23 and later */
#ifndef EI_DIST_HIGH
diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl
index d0e5f4514a..7be5d38f0a 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE.erl
+++ b/lib/erl_interface/test/ei_tmo_SUITE.erl
@@ -146,6 +146,10 @@ do_one_recv_failure(Config,CNode) ->
-define(EI_DIST_LOW, 6).
-define(EI_DIST_HIGH, 6).
+%% An OTP-23 or 24 node may connect assuming 5 or higher.
+-define(EI_DIST_LOWEST_ASSUMED, 5).
+
+
%% Check send with timeouts.
ei_send_tmo(Config) when is_list(Config) ->
register(ei_send_tmo_1,self()),
@@ -303,6 +307,15 @@ ei_connect_tmo(Config) when is_list(Config) ->
%% Check accept with timeouts.
ei_accept_tmo(Config) when is_list(Config) ->
+ [begin
+ io:format("Test assumed ver=~p\n",
+ [AssumedVer]),
+ do_ei_accept_tmo(Config, AssumedVer)
+ end
+ || AssumedVer <- lists:seq(?EI_DIST_LOWEST_ASSUMED, ?EI_DIST_HIGH)],
+ ok.
+
+do_ei_accept_tmo(Config, AssumedVer) ->
Flags = ?COMPULSORY_DFLAGS bor ?DFLAG_MANDATORY_25_DIGEST,
P = runner:start(Config, ?accept_tmo),
@@ -323,11 +336,11 @@ ei_accept_tmo(Config) when is_list(Config) ->
runner:recv_eot(P2),
true = is_integer(X),
- normal_accept(Config, Flags),
+ normal_accept(Config, AssumedVer, Flags),
ok.
-normal_accept(Config, Flags) ->
+normal_accept(Config, AssumedVer, Flags) ->
P = runner:start(Config, ?accept_tmo),
runner:send_term(P,{c_nod_som_vi_kontaktar_2,
erlang:get_cookie(),
@@ -341,7 +354,7 @@ normal_accept(Config, Flags) ->
{ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketA, OurName, Flags),
+ send_name(SocketA, OurName, AssumedVer, Flags),
ok = recv_status(SocketA),
{hidden,_Node,HisChallengeA} = recv_challenge(SocketA), % See 1)
_OurChallengeA = gen_challenge(),
@@ -401,13 +414,18 @@ make_and_check_dummy() ->
%% Test that erl_interface sets the appropriate distributions flags.
ei_dflags(Config) ->
+ AssumedVer = 5,
+ OurVer = 6,
+
%% Test compatibility with OTP 24 and earlier.
normal_connect(Config, ?COMPULSORY_DFLAGS),
- normal_accept(Config, ?COMPULSORY_DFLAGS),
+ normal_accept(Config, AssumedVer, ?COMPULSORY_DFLAGS),
+ normal_accept(Config, OurVer, ?COMPULSORY_DFLAGS),
%% Test compatibility with future versions.
normal_connect(Config, ?DFLAG_MANDATORY_25_DIGEST),
- normal_accept(Config, ?DFLAG_MANDATORY_25_DIGEST),
+ normal_accept(Config, AssumedVer, ?DFLAG_MANDATORY_25_DIGEST),
+ normal_accept(Config, OurVer, ?DFLAG_MANDATORY_25_DIGEST),
ok.
@@ -558,14 +576,19 @@ send_challenge_ack(Socket, Digest) ->
% ?shutdown(bad_challenge_ack)
% end.
-send_name(Socket, MyNode, Flags) ->
+send_name(Socket, MyNode, AssumedVer, Flags0) ->
+ Flags = Flags0 bor?DFLAG_HANDSHAKE_23,
NodeName = atom_to_binary(MyNode, latin1),
- Creation = erts_internal:get_creation(),
- ?to_port(Socket, [$N,
- <<Flags:64,
- Creation:32,
- (byte_size(NodeName)):16>>,
- NodeName]).
+ if AssumedVer =:= 5 ->
+ ?to_port(Socket, [$n,?int16(?EI_DIST_HIGH),?int32(Flags),NodeName]);
+ AssumedVer >= 6 ->
+ Creation = erts_internal:get_creation(),
+ ?to_port(Socket, [$N,
+ <<Flags:64,
+ Creation:32,
+ (byte_size(NodeName)):16>>,
+ NodeName])
+ end.
recv_name(Socket) ->
case gen_tcp:recv(Socket, 0) of