diff options
Diffstat (limited to 'lib/erl_interface')
-rw-r--r-- | lib/erl_interface/src/connect/ei_connect.c | 123 | ||||
-rw-r--r-- | lib/erl_interface/src/epmd/ei_epmd.h | 1 | ||||
-rw-r--r-- | lib/erl_interface/test/ei_tmo_SUITE.erl | 47 |
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 |