From bfb350ecc30d44e64ed75512690a0e4fbbb6bc2a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 20 Sep 2011 09:27:02 +0200 Subject: erts,kernel: Rename operations common to TCP and SCTP --- lib/kernel/src/inet_int.hrl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 6f1688c6a2..9154e90e1f 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -83,15 +83,17 @@ -define(INET_REQ_IFSET, 23). -define(INET_REQ_SUBSCRIBE, 24). -define(INET_REQ_GETIFADDRS, 25). +-define(INET_REQ_ACCEPT, 26). +-define(INET_REQ_LISTEN, 27). %% TCP requests --define(TCP_REQ_ACCEPT, 40). --define(TCP_REQ_LISTEN, 41). +%%-define(TCP_REQ_ACCEPT, 40). MOVED +%%-define(TCP_REQ_LISTEN, 41). MERGED -define(TCP_REQ_RECV, 42). -define(TCP_REQ_UNRECV, 43). -define(TCP_REQ_SHUTDOWN, 44). %% UDP and SCTP requests -define(PACKET_REQ_RECV, 60). --define(SCTP_REQ_LISTEN, 61). +%%-define(SCTP_REQ_LISTEN, 61). MERGED -define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind %% subscribe codes, INET_REQ_SUBSCRIBE -- cgit v1.2.3 From faea8584311fcb5365c585280e5e9b2364ed121e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 2 Sep 2011 10:38:39 +0200 Subject: erts,kernel: Add type stream sockets to SCTP --- lib/kernel/doc/src/gen_sctp.xml | 16 ++++++++++------ lib/kernel/src/gen_sctp.erl | 14 ++++++++++++-- lib/kernel/src/inet.erl | 27 ++++++++++++++++----------- lib/kernel/src/inet6_sctp.erl | 6 +++--- lib/kernel/src/inet6_tcp.erl | 8 ++++---- lib/kernel/src/inet6_udp.erl | 6 +++--- lib/kernel/src/inet_int.hrl | 3 ++- lib/kernel/src/inet_sctp.erl | 6 +++--- lib/kernel/src/inet_tcp.erl | 8 ++++---- lib/kernel/src/inet_udp.erl | 4 ++-- 10 files changed, 59 insertions(+), 39 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 688cd0f78f..b9f23674f0 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -254,15 +254,19 @@ - + + Set up a socket to listen.

Sets up a socket to listen on the IP address and port number - it is bound to. IsServer must be true - or false. - In the contrast to TCP, in SCTP there is no listening queue length. - If IsServer is true the socket accepts new associations, i.e. - it will become an SCTP server socket.

+ it is bound to.

+

For type seqpacket sockets (the default) + IsServer must be true or false. + In the contrast to TCP, in SCTP there is no listening queue length. + If IsServer is true the socket accepts new associations, i.e. + it will become an SCTP server socket.

+

For type stream sockets Backlog defines + the backlog queue length just like in TCP.

diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 6cebb7ab97..3351796481 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -109,9 +109,11 @@ open() -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Opts) when is_list(Opts) -> @@ -134,9 +136,11 @@ open(X) -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Port, Opts) when is_integer(Port), is_list(Opts) -> @@ -161,12 +165,18 @@ close(S) -> -spec listen(Socket, IsServer) -> ok | {error, Reason} when Socket :: sctp_socket(), IsServer :: boolean(), + Reason :: term(); + (Socket, Backlog) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Backlog :: integer(), Reason :: term(). -listen(S, Flag) when is_port(S), is_boolean(Flag) -> +listen(S, Backlog) + when is_port(S), is_boolean(Backlog); + is_port(S), is_integer(Backlog) -> case inet_db:lookup_socket(S) of {ok,Mod} -> - Mod:listen(S, Flag); + Mod:listen(S, Backlog); Error -> Error end; listen(S, Flag) -> diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 48a6f3db65..22056e6974 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -36,7 +36,7 @@ -export([i/0, i/1, i/2]). --export([getll/1, getfd/1, open/7, fdopen/5]). +-export([getll/1, getfd/1, open/8, fdopen/6]). -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). @@ -115,7 +115,8 @@ 'mtu' | 'netmask' | 'flags' |'hwaddr'. -type address_family() :: 'inet' | 'inet6'. --type protocol_option() :: 'tcp' | 'udp' | 'sctp'. +-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. +-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. @@ -748,6 +749,8 @@ sctp_opt([Opt|Opts], Mod, R, As) -> sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As); Error -> Error end; + {type,Type} when Type =:= seqpacket; Type =:= stream -> + sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As); binary -> sctp_opt (Opts, Mod, R, As, mode, binary); list -> sctp_opt (Opts, Mod, R, As, mode, list); {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with @@ -996,13 +999,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> Addr :: ip_address(), Port :: port_number(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), - Family :: 'inet' | 'inet6', + Protocol :: socket_protocol(), + Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> - case prim_inet:open(Protocol, Family) of +open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> + case prim_inet:open(Protocol, Family, Type) of {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1029,18 +1033,19 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) -> - fdopen(Fd, Opts, Protocol, Family, Module). +open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) -> + fdopen(Fd, Opts, Protocol, Family, Type, Module). -spec fdopen(Fd :: non_neg_integer(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), + Protocol :: socket_protocol(), Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -fdopen(Fd, Opts, Protocol, Family, Module) -> - case prim_inet:fdopen(Protocol, Fd, Family) of +fdopen(Fd, Opts, Protocol, Family, Type, Module) -> + case prim_inet:fdopen(Protocol, Family, Type, Fd) of {ok, S} -> case prim_inet:setopts(S, Opts) of ok -> diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl index 5bf3fca647..f034535ba0 100644 --- a/lib/kernel/src/inet6_sctp.erl +++ b/lib/kernel/src/inet6_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 @@ -54,8 +54,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index cc45f6c7f6..c714b2bee0 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -93,7 +93,7 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when port=BPort, opts=SockOpts}} when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, Addr, Port, Time) of ok -> {ok,S}; @@ -115,7 +115,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -149,5 +149,5 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE). diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl index e81d417151..ca43c94211 100644 --- a/lib/kernel/src/inet6_udp.erl +++ b/lib/kernel/src/inet6_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -45,7 +45,7 @@ open(Port, Opts) -> port=BPort, opts=SockOpts}} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -84,4 +84,4 @@ controlling_process(Socket, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, udp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE). diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 9154e90e1f..735347b4b1 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -29,7 +29,7 @@ -define(INET_AF_ANY, 3). % Fake for ANY in any address family -define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family -%% type codes (gettype, INET_REQ_GETTYPE) +%% type codes to open and gettype - INET_REQ_GETTYPE -define(INET_TYPE_STREAM, 1). -define(INET_TYPE_DGRAM, 2). -define(INET_TYPE_SEQPACKET, 3). @@ -401,6 +401,7 @@ ifaddr, port = 0, fd = -1, + type = seqpacket, opts = [{mode, binary}, {buffer, ?SCTP_DEF_BUFSZ}, {sndbuf, ?SCTP_DEF_BUFSZ}, diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index de74b573bd..e670dcfdad 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. 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 @@ -53,8 +53,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index 6dadccd6a9..4c2db16ce3 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. 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 @@ -95,7 +95,7 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) -> port=BPort, opts=SockOpts}} when ?ip(Ab,Bb,Cb,Db), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, {A,B,C,D}, Port, Time) of ok -> {ok,S}; @@ -117,7 +117,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip(A,B,C,D), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -150,4 +150,4 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 60bd96f332..80d930fe10 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -52,7 +52,7 @@ open(Port, Opts) -> ifaddr=BAddr={A,B,C,D}, port=BPort, opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -93,7 +93,7 @@ controlling_process(Socket, NewOwner) -> fdopen(Fd, Opts) -> inet:fdopen(Fd, optuniquify([{recbuf, ?RECBUF} | Opts]), - udp, inet, ?MODULE). + udp, inet, dgram, ?MODULE). %% Remove all duplicate options from an option list. -- cgit v1.2.3 From 3b81d47f7f4415661d4371989637374567e2ab2a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 2 Sep 2011 10:37:08 +0200 Subject: kernel: Add tests for SCTP stream sockets Also fix tests for new prim_inet:open function. --- lib/kernel/test/erl_boot_server_SUITE.erl | 2 +- lib/kernel/test/gen_sctp_SUITE.erl | 100 ++++++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/erl_boot_server_SUITE.erl b/lib/kernel/test/erl_boot_server_SUITE.erl index cea3715ce4..bb64c01058 100644 --- a/lib/kernel/test/erl_boot_server_SUITE.erl +++ b/lib/kernel/test/erl_boot_server_SUITE.erl @@ -346,7 +346,7 @@ good_hosts(_Config) -> [GoodHost1, GoodHost2, GoodHost3]. open_udp() -> - ?line {ok, S} = prim_inet:open(udp, inet), + ?line {ok, S} = prim_inet:open(udp, inet, dgram), ?line ok = prim_inet:setopts(S, [{mode,list},{active,true}, {deliver,term},{broadcast,true}]), ?line {ok,_} = prim_inet:bind(S, {0,0,0,0}, 0), diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 1b534a5fc4..1cf3d659d4 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -30,14 +30,15 @@ -export( [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, - xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]). + xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, + basic_stream/1, xfer_stream_min/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, api_open_close, api_listen, api_connect_init, - api_opts, xfer_min, xfer_active, def_sndrcvinfo, - implicit_inet6]. + api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, + basic_stream, xfer_stream_min]. groups() -> []. @@ -96,7 +97,7 @@ xfer_min(Config) when is_list(Config) -> ?line Stream = 0, ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, ?line Loopback = {127,0,0,1}, - ?line {ok,Sb} = gen_sctp:open(), + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), @@ -654,6 +655,97 @@ implicit_inet6(S1, Addr) -> end, ?line ok = gen_sctp:close(S2). +basic_stream(doc) -> + "Hello world stream socket"; +basic_stream(suite) -> + []; +basic_stream(Config) when is_list(Config) -> + ?line {ok,S} = gen_sctp:open([{type,stream}]), + ?line ok = gen_sctp:listen(S, true), + ?line ok = + do_from_other_process( + fun () -> gen_sctp:listen(S, 10) end), + ?line ok = gen_sctp:close(S), + ok. + +xfer_stream_min(doc) -> + "Minimal data transfer"; +xfer_stream_min(suite) -> + []; +xfer_stream_min(Config) when is_list(Config) -> + ?line Stream = 0, + ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, + ?line Loopback = {127,0,0,1}, + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), + ?line {ok,Pb} = inet:port(Sb), + ?line ok = gen_sctp:listen(Sb, true), + + ?line {ok,Sa} = gen_sctp:open([{type,stream}]), + ?line {ok,Pa} = inet:port(Sa), + ?line {ok,#sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId}} = + gen_sctp:connect(Sa, Loopback, Pb, []), + ?line {ok,{Loopback, + Pa,[], + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=SbAssocId}}} = + gen_sctp:recv(Sb, infinity), + ?line SaOutboundStreams = SbInboundStreams, + ?line SbOutboundStreams = SaInboundStreams, + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), + ?line case gen_sctp:recv(Sb, infinity) of + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} -> ok; + {ok,{Loopback, + Pa,[], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_available, + error = 0, + assoc_id = SbAssocId}}} -> + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} = gen_sctp:recv(Sb, infinity) + end, + ?line ok = + do_from_other_process( + fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end), + ?line {ok,{Loopback, + Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data}} = + gen_sctp:recv(Sa, infinity), + %% + ?line ok = gen_sctp:close(Sa), + ?line {ok,{Loopback, + Pa,[], + #sctp_shutdown_event{assoc_id=SbAssocId}}} = + gen_sctp:recv(Sb, infinity), + ?line {ok,{Loopback, + Pa,[], + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}}} = + gen_sctp:recv(Sb, infinity), + ?line ok = gen_sctp:close(Sb), + + ?line receive + Msg -> test_server:fail({received,Msg}) + after 17 -> ok + end, + ok. + do_from_other_process(Fun) -> -- cgit v1.2.3 From 1cc7485467b1b4e9efd15259b58e1182d2e9723c Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 2 Sep 2011 10:29:58 +0200 Subject: erts,kernel: Implement gen_sctp:peeloff/2 --- lib/kernel/src/gen_sctp.erl | 18 +++++++++++++++++- lib/kernel/src/inet.erl | 16 ++++++++++++---- lib/kernel/src/inet6_sctp.erl | 11 ++++++++++- lib/kernel/src/inet_int.hrl | 3 ++- lib/kernel/src/inet_sctp.erl | 11 ++++++++++- 5 files changed, 51 insertions(+), 8 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 3351796481..77ca26b845 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -27,7 +27,8 @@ -include("inet_sctp.hrl"). -export([open/0,open/1,open/2,close/1]). --export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]). +-export([listen/2,peeloff/2]). +-export([connect/4,connect/5,connect_init/4,connect_init/5]). -export([eof/2,abort/2]). -export([send/3,send/4,recv/1,recv/2]). -export([error_string/1]). @@ -182,6 +183,21 @@ listen(S, Backlog) listen(S, Flag) -> erlang:error(badarg, [S,Flag]). +-spec peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{} | assoc_id(), + NewSocket :: sctp_socket(), + Reason :: term(). + +peeloff(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + peeloff(S, AssocId); +peeloff(S, AssocId) when is_port(S), is_integer(AssocId) -> + case inet_db:lookup_socket(S) of + {ok,Mod} -> + Mod:peeloff(S, AssocId); + Error -> Error + end. + -spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when Socket :: sctp_socket(), Addr :: inet:ip_address() | inet:hostname(), diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 22056e6974..b60c68e3a1 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1061,18 +1061,24 @@ fdopen(Fd, Opts, Protocol, Family, Type, Module) -> %% socket stat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -i() -> i(tcp), i(udp). +i() -> i(tcp), i(udp), i(sctp). i(Proto) -> i(Proto, [port, module, recv, sent, owner, - local_address, foreign_address, state]). + local_address, foreign_address, state, type]). i(tcp, Fs) -> ii(tcp_sockets(), Fs, tcp); i(udp, Fs) -> - ii(udp_sockets(), Fs, udp). + ii(udp_sockets(), Fs, udp); +i(sctp, Fs) -> + ii(sctp_sockets(), Fs, sctp). ii(Ss, Fs, Proto) -> - LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)], + LLs = + case info_lines(Ss, Fs, Proto) of + [] -> []; + InfoLines -> [h_line(Fs) | InfoLines] + end, Maxs = foldl( fun(Line,Max0) -> smax(Max0,Line) end, duplicate(length(Fs),0),LLs), @@ -1140,6 +1146,7 @@ info(S, F, Proto) -> case prim_inet:gettype(S) of {ok,{_,stream}} -> "STREAM"; {ok,{_,dgram}} -> "DGRAM"; + {ok,{_,seqpacket}} -> "SEQPACKET"; _ -> " " end; fd -> @@ -1191,6 +1198,7 @@ fmt_port(N, Proto) -> %% Return a list of all tcp sockets tcp_sockets() -> port_list("tcp_inet"). udp_sockets() -> port_list("udp_inet"). +sctp_sockets() -> port_list("sctp_inet"). %% Return all ports having the name 'Name' port_list(Name) -> diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl index f034535ba0..c47483bbdd 100644 --- a/lib/kernel/src/inet6_sctp.erl +++ b/lib/kernel/src/inet6_sctp.erl @@ -32,7 +32,8 @@ -define(FAMILY, inet6). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -65,6 +66,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + connect(S, Addr, Port, Opts, Timer) -> inet_sctp:connect(S, Addr, Port, Opts, Timer). diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 735347b4b1..f8984b13fe 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -95,6 +95,7 @@ -define(PACKET_REQ_RECV, 60). %%-define(SCTP_REQ_LISTEN, 61). MERGED -define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind +-define(SCTP_REQ_PEELOFF, 63). %% subscribe codes, INET_REQ_SUBSCRIBE -define(INET_SUBS_EMPTY_OUT_Q, 1). @@ -102,7 +103,7 @@ %% reply codes for *_REQ_* -define(INET_REP_ERROR, 0). -define(INET_REP_OK, 1). --define(INET_REP_SCTP, 2). +-define(INET_REP, 2). %% INET, TCP and UDP options: -define(INET_OPT_REUSEADDR, 0). diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index e670dcfdad..8482dd1b12 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -31,7 +31,8 @@ -define(FAMILY, inet). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -64,6 +65,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + %% A non-blocking connect is implemented when the initial call is to %% gen_sctp:connect_init which passes the value nowait as the Timer connect(S, Addr, Port, Opts, Timer) -> -- cgit v1.2.3 From 5895bb8d7bde52972f74f6b51748230982f762f7 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 2 Sep 2011 16:18:13 +0200 Subject: kernel: Add tests for gen_sctp:peeloff/2 --- lib/kernel/test/gen_sctp_SUITE.erl | 200 ++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 3 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 1cf3d659d4..f422ffe442 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -31,14 +31,14 @@ [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, - basic_stream/1, xfer_stream_min/1]). + basic_stream/1, xfer_stream_min/1, peeloff/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, api_open_close, api_listen, api_connect_init, api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, - basic_stream, xfer_stream_min]. + basic_stream, xfer_stream_min, peeloff]. groups() -> []. @@ -418,7 +418,11 @@ setopt(S, Opt, Val) -> inet:setopts(S, [{Opt,Val}]). ok({ok,X}) -> - io:format("OK: ~p~n", [X]), + io:format("OK[~w]: ~p~n", [self(),X]), + X. + +log(X) -> + io:format("LOG[~w]: ~p~n", [self(),X]), X. flush() -> @@ -773,3 +777,193 @@ do_from_other_process(Fun) -> {'DOWN',Mref,_,_,Reason} -> erlang:exit(Reason) end. + + + +peeloff(doc) -> + "Peel off an SCTP stream socket"; +peeloff(suite) -> + []; +peeloff(Config) when is_list(Config) -> + ?line Addr = {127,0,0,1}, + ?line Stream = 0, + ?line Timeout = 333, + ?line S1 = socket_start(Addr, Timeout), + ?line P1 = socket_call(S1, port), + ?line Socket1 = socket_call(S1, socket), + ?line ok = socket_call(S1, {listen,true}), + ?line S2 = socket_start(Addr, Timeout), + ?line P2 = socket_call(S2, port), + ?line Socket2 = socket_call(S2, socket), + %% + ?line H_a = socket_req(S1, recv_assoc), + ?line {S2Ai,Sa,Sb} = socket_call(S2, {connect,Addr,P1,[]}), + ?line {S1Ai,Sb,Sa,Addr,P2} = socket_resp(H_a), + %% + ?line H_b = socket_req(S1, recv), + ?line ok = socket_call(S2, {send,S2Ai,Stream,<<"Data H_b">>}), + ?line {Addr,P2,S1Ai,Stream,<<"Data H_b">>} = socket_resp(H_b), + ?line H_c = socket_req(S1, {recv,Socket2}), + ?line ok = + socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Data H_c">>}), + ?line {Addr,P1,S2Ai,Stream,<<"Data H_c">>} = socket_resp(H_c), + %% + ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), + ?line P3 = socket_call(S3, port), + ?line Socket3 = socket_call(S3, socket), + ?line S3Ai = S1Ai, + %% + ?line H_d = socket_req(S2, recv), + ?line ok = socket_call(S3, {send,S3Ai,Stream,<<"Data H_d">>}), + ?line {Addr,P3,S2Ai,Stream,<<"Data H_d">>} = socket_resp(H_d), + ?line ok = socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Data S2">>}), + ?line {Addr,P2,S3Ai,Stream,<<"Data S2">>} = socket_call(S2, {recv,Socket3}), + %% + ?line inet:i(sctp), + ?line ok = socket_stop(S1), + ?line ok = socket_stop(S2), + ?line {Addr,P2,[],#sctp_shutdown_event{assoc_id=S1Ai}} = + ok(socket_stop(S3)), + ok. + +%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% socket gen_server ultra light + +socket_peeloff(Socket, AssocId, Timeout) -> + Starter = + fun () -> + {ok,NewSocket} = + gen_sctp:peeloff(Socket, AssocId), + NewSocket + end, + socket_starter(Starter, Timeout). + +socket_start(Addr, Timeout) -> + Starter = + fun () -> + {ok,Socket} = + gen_sctp:open([{type,seqpacket},{ifaddr,Addr}]), + Socket + end, + socket_starter(Starter, Timeout). + +socket_starter(Starter, Timeout) -> + Parent = self(), + Owner = + spawn_link( + fun () -> + socket_starter(Starter(), Timeout, Parent) + end), + io:format("Started socket ~w.~n", [Owner]), + Owner. + +socket_starter(Socket, Timeout, Parent) -> + try + Handler = socket_handler(Socket, Timeout), + socket_loop(Socket, Timeout, Parent, Handler) + catch + Class:Reason -> + Stacktrace = erlang:get_stacktrace(), + io:format(?MODULE_STRING":socket exception ~w:~w at~n" + "~p.~n", [Class,Reason,Stacktrace]), + erlang:raise(Class, Reason, Stacktrace) + end. + +socket_loop(Socket, Timeout, Parent, Handler) -> + receive + {Parent,Ref} -> % socket_stop() + Result = + case log(gen_sctp:recv(Socket, Timeout)) of + {error,timeout} -> ok; + R -> R + end, + ok = gen_sctp:close(Socket), + Parent ! {self(),Ref, Result}; + {Parent,Ref,Msg} -> + Parent ! {self(),Ref,Handler(Msg)}, + socket_loop(Socket, Timeout, Parent, Handler) + end. + +socket_handler(Socket, Timeout) -> + fun ({listen,Listen}) -> + gen_sctp:listen(Socket, Listen); + (port) -> + ok(inet:port(Socket)); + (socket) -> + Socket; + (recv_assoc) -> + {AssocAddr,AssocPort,[], + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId}} = + ok(gen_sctp:recv(Socket, infinity)), + case log(gen_sctp:recv(Socket, Timeout)) of + {ok,AssocAddr,AssocPort,[], + #sctp_paddr_change{addr = {AssocAddr,AssocPort}, + state = addr_available, + error = 0, + assoc_id = AssocId}} -> ok; + {error,timeout} -> ok + end, + {AssocId,Os,Is,AssocAddr,AssocPort}; + ({connect,ConAddr,ConPort,ConOpts}) -> + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId} = + ok(gen_sctp:connect(Socket, ConAddr, ConPort, ConOpts)), + case log(gen_sctp:recv(Socket, Timeout)) of + {ok,ConAddr,ConPort,[], + #sctp_paddr_change{addr = {ConAddr,ConPort}, + state = addr_available, + error = 0, + assoc_id = AssocId}} -> ok; + {error,timeout} -> ok + end, + {AssocId,Os,Is}; + ({send,AssocId,Stream,Data}) -> + gen_sctp:send(Socket, AssocId, Stream, Data); + ({send,S,AssocId,Stream,Data}) -> + gen_sctp:send(S, AssocId, Stream, Data); + (recv) -> + {Addr,Port, + [#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}],Data} = + ok(gen_sctp:recv(Socket, infinity)), + {Addr,Port,AssocId,Stream,Data}; + ({recv,S}) -> + {Addr,Port, + [#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}],Data} = + ok(gen_sctp:recv(S, infinity)), + {Addr,Port,AssocId,Stream,Data} + end. + +socket_stop(Handler) -> + Mref = erlang:monitor(process, Handler), + Handler ! {self(),Mref}, + receive + {Handler,Mref,Result} -> + receive {'DOWN',Mref,_,_,_} -> Result end; + {'DOWN',Mref,_,_,Error} -> + exit(Error) + end. + +socket_call(Handler, Request) -> + socket_resp(socket_req(Handler, Request)). + +socket_req(Handler, Request) -> + Mref = erlang:monitor(process, Handler), + Handler ! {self(),Mref,Request}, + {Handler,Mref}. + +socket_resp({Handler,Mref}) -> + receive + {'DOWN',Mref,_,_,Error} -> + exit(Error); + {Handler,Mref,Reply} -> + erlang:demonitor(Mref), + receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end, + Reply + end. -- cgit v1.2.3 From 6dd80f3e9a556dc94ae59280f532e153e463b798 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 9 Sep 2011 17:40:29 +0200 Subject: erts,kernel: Bugfix - collect fragmented SCTP messages on recv --- lib/kernel/test/gen_sctp_SUITE.erl | 53 +++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index f422ffe442..9d12c629de 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -31,14 +31,14 @@ [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, - basic_stream/1, xfer_stream_min/1, peeloff/1]). + basic_stream/1, xfer_stream_min/1, peeloff/1, buffers/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, api_open_close, api_listen, api_connect_init, api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, - basic_stream, xfer_stream_min, peeloff]. + basic_stream, xfer_stream_min, peeloff, buffers]. groups() -> []. @@ -826,6 +826,49 @@ peeloff(Config) when is_list(Config) -> ok(socket_stop(S3)), ok. + + +buffers(doc) -> + ["Check sndbuf and recbuf behaviour"]; +buffers(suite) -> + []; +buffers(Config) when is_list(Config) -> + ?line Limit = 8192, + ?line Data = mk_data(Limit), + ?line Addr = {127,0,0,1}, + ?line Stream = 1, + ?line Timeout = 333, + ?line S1 = socket_start(Addr, Timeout), + ?line P1 = socket_call(S1, port), + ?line ok = socket_call(S1, {listen,true}), + ?line S2 = socket_start(Addr, Timeout), + ?line P2 = socket_call(S2, port), + %% + ?line H_a = socket_req(S1, recv_assoc), + ?line {S2Ai,Sa,Sb} = socket_call(S2, {connect,Addr,P1,[]}), + ?line {S1Ai,Sb,Sa,Addr,P2} = socket_resp(H_a), + %% + ?line ok = socket_call(S1, {setopts,[{recbuf,Limit}]}), + ?line case socket_call(S1, {getopts,[recbuf]}) of + {ok,[{recbuf,RB1}]} when RB1 >= Limit -> ok + end, + ?line H_b = socket_req(S1, recv), + ?line ok = socket_call(S2, {send,S2Ai,Stream,Data}), + ?line {Addr,P2,S1Ai,Stream,Data} = socket_resp(H_b), + %% + ?line ok = socket_stop(S1), + ?line {Addr,P1,[],#sctp_shutdown_event{assoc_id=S2Ai}} = + ok(socket_stop(S2)), + ok. + +mk_data(Words) -> + mk_data(0, Words, <<>>). +%% +mk_data(Words, Words, Bin) -> + Bin; +mk_data(N, Words, Bin) -> + mk_data(N+1, Words, <>). + %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light @@ -937,7 +980,11 @@ socket_handler(Socket, Timeout) -> {Addr,Port, [#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}],Data} = ok(gen_sctp:recv(S, infinity)), - {Addr,Port,AssocId,Stream,Data} + {Addr,Port,AssocId,Stream,Data}; + ({setopts,Opts}) -> + inet:setopts(Socket, Opts); + ({getopts,Optnames}) -> + inet:getopts(Socket, Optnames) end. socket_stop(Handler) -> -- cgit v1.2.3 From 2831667add272eab3915bcecd9b8f3c89aad78f3 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 20 Sep 2011 15:56:59 +0000 Subject: kernel: Bugfix - SCTP connect with sndrcvinfo in assoc_change event On some platforms (FreeBSD) the #sctp_assoc_change{state=comm_up} event arriving during gen_sctp:connect/4,5 contains ancillary data #sctp_sndrcvinfo{}. That was not expected by the code. --- lib/kernel/src/inet_sctp.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index 8482dd1b12..2d799d79fa 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -111,7 +111,7 @@ connect(S, Addr, Port, Opts, Timer) -> connect_get_assoc(S, Addr, Port, false, Timer) -> case recv(S, inet:timeout(Timer)) of - {ok, {Addr, Port, [], #sctp_assoc_change{state=St}=Ev}} -> + {ok, {Addr, Port, _, #sctp_assoc_change{state=St}=Ev}} -> if St =:= comm_up -> %% Yes, successfully connected, return the whole %% sctp_assoc_change event (containing, in particular, @@ -132,7 +132,7 @@ connect_get_assoc(S, Addr, Port, false, Timer) -> connect_get_assoc(S, Addr, Port, Active, Timer) -> Timeout = inet:timeout(Timer), receive - {sctp,S,Addr,Port,{[],#sctp_assoc_change{state=St}=Ev}} -> + {sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} -> case Active of once -> prim_inet:setopt(S, active, once); -- cgit v1.2.3 From 4ef92bf4416c988a459a361e71e402c286e889b5 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 20 Sep 2011 16:01:29 +0000 Subject: kernel: Fix SCTP tests for the FreeBSD protocol stack --- lib/kernel/test/gen_sctp_SUITE.erl | 506 ++++++++++++++++++++++++------------- 1 file changed, 337 insertions(+), 169 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 9d12c629de..8011c22ce5 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -109,29 +109,44 @@ xfer_min(Config) when is_list(Config) -> inbound_streams=SaInboundStreams, assoc_id=SaAssocId}=SaAssocChange} = gen_sctp:connect(Sa, Loopback, Pb, []), - ?line {ok,{Loopback, - Pa,[], + ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = + case recv_event(ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, outbound_streams=SbOutboundStreams, inbound_streams=SbInboundStreams, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line SaOutboundStreams = SbInboundStreams, - ?line SbOutboundStreams = SaInboundStreams, + assoc_id=AssocId}} -> + {AssocId,SbInboundStreams,SbOutboundStreams}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AssocId}} -> + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=AssocId}} = + ?line recv_event(ok(gen_sctp:recv(Sb, infinity))), + {AssocId,SbInboundStreams,SbOutboundStreams} + end, + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case gen_sctp:recv(Sb, infinity) of - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok; - {ok,{Loopback, - Pa,[], + ?line case ok(gen_sctp:recv(Sb, infinity)) of + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} -> ok; + Event1 -> + {Loopback,Pa, #sctp_paddr_change{addr = {Loopback,_}, state = addr_available, error = 0, - assoc_id = SbAssocId}}} -> + assoc_id = SbAssocId}} = + recv_event(Event1), {ok,{Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, @@ -139,30 +154,40 @@ xfer_min(Config) when is_list(Config) -> Data}} = gen_sctp:recv(Sb, infinity) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), - ?line {ok,{Loopback, - Pb, + ?line case ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], - Data}} = - gen_sctp:recv(Sa, infinity), + Data} -> + ok; + Event2 -> + {Loopback,Pb, + #sctp_paddr_change{addr={_,Pb}, + state=addr_confirmed, + error=0, + assoc_id=SaAssocId}} = + ?line recv_event(Event2), + ?line {Loopback, + Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + ok(gen_sctp:recv(Sa, infinity)) + end, %% ?line ok = gen_sctp:eof(Sa, SaAssocChange), - ?line {ok,{Loopback, - Pa,[], - #sctp_shutdown_event{assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line {ok,{Loopback, - Pb,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SaAssocId}}} = - gen_sctp:recv(Sa, infinity), - ?line {ok,{Loopback, - Pa,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), + ?line {Loopback,Pa,#sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pb, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SaAssocId}} = + recv_event(ok(gen_sctp:recv(Sa, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), @@ -187,32 +212,51 @@ xfer_active(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open([{active,true}]), ?line {ok,Pa} = inet:port(Sa), - ?line {ok,#sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SaOutboundStreams, - inbound_streams=SaInboundStreams, - assoc_id=SaAssocId}=SaAssocChange} = - gen_sctp:connect(Sa, Loopback, Pb, []), + ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId} = SaAssocChange = + recv_assoc_change(Sa, Loopback, Pb, Timeout), ?line io:format("Sa=~p, Pa=~p, Sb=~p, Pb=~p, SaAssocId=~p, " "SaOutboundStreams=~p, SaInboundStreams=~p~n", [Sa,Pa,Sb,Pb,SaAssocId, SaOutboundStreams,SaInboundStreams]), - ?line SbAssocId = - receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=SBAI}}} -> - ?line SaOutboundStreams = SbInboundStreams, - ?line SaInboundStreams = SbOutboundStreams, - SBAI - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=SbAssocId} = + recv_assoc_change(Sb, Loopback, Pa, Timeout), + ?line SbOutboundStreams = SaInboundStreams, + ?line SbInboundStreams = SaOutboundStreams, ?line io:format("SbAssocId=~p~n", [SbAssocId]), + + ?line case recv_paddr_change(Sa, Loopback, Pb, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + timeout -> ok + end, + ?line case recv_paddr_change(Sb, Loopback, Pa, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=SbAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={Loopback,Pa}, + error=0, + assoc_id=SbAssocId} -> ok; + timeout -> ok + end, + ?line [] = flush(), + ?line ok = do_from_other_process( fun () -> gen_sctp:send(Sa, SaAssocId, 0, Data) end), @@ -220,19 +264,7 @@ xfer_active(Config) when is_list(Config) -> {sctp,Sb,Loopback,Pa, {[#sctp_sndrcvinfo{stream=Stream, assoc_id=SbAssocId}], - Data}} -> ok; - {sctp,Sb,Loopback,Pa, - {[], - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}}} -> - ?line receive - {sctp,Sb,Loopback,Pa, - {[#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok - end + Data}} -> ok after Timeout -> ?line test_server:fail({unexpected,flush()}) end, @@ -247,23 +279,19 @@ xfer_active(Config) when is_list(Config) -> end, %% ?line ok = gen_sctp:abort(Sa, SaAssocChange), - ?line receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SbAssocId}}} -> ok - after Timeout -> + ?line case recv_assoc_change(Sb, Loopback, Pa, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SbAssocId} -> ok; + timeout -> ?line test_server:fail({unexpected,flush()}) end, ?line ok = gen_sctp:close(Sb), - ?line receive - {sctp,Sa,Loopback,Pb, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SaAssocId}}} -> ok - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, + ?line case recv_assoc_change(Sa, Loopback, Pb, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SaAssocId} -> ok; + timeout -> + ?line test_server:fail({unexpected,flush()}) + end, ?line receive {sctp_error,Sa,enotconn} -> ok % Solaris after 17 -> ok %% Only happens on Solaris @@ -276,6 +304,30 @@ xfer_active(Config) when is_list(Config) -> end, ok. +recv_assoc_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_assoc_change{}=AssocChange}} -> + AssocChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_assoc_change{assoc_id=AssocId}=AssocChange}} -> + AssocChange + after Timeout -> + timeout + end. + +recv_paddr_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_paddr_change{}=PaddrChange}} -> + PaddrChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_paddr_change{assoc_id=AssocId}=PaddrChange}} -> + PaddrChange + after Timeout -> + timeout + end. + def_sndrcvinfo(doc) -> "Test that #sctp_sndrcvinfo{} parameters set on a socket " "are used by gen_sctp:send/4"; @@ -312,20 +364,33 @@ def_sndrcvinfo(Config) when is_list(Config) -> assoc_id=S2AssocId} = S2AssocChange = ok(gen_sctp:connect(S2, Loopback, P1, [])), ?LOGVAR(S2AssocChange), - ?line case ok(gen_sctp:recv(S1)) of - {Loopback, P2,[], + ?line case recv_event(ok(gen_sctp:recv(S1))) of + {Loopback,P2, #sctp_assoc_change{ + state=comm_up, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId); + {Loopback,P2, + #sctp_paddr_change{ + state=addr_confirmed, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId), + {Loopback,P2, + #sctp_assoc_change{ state=comm_up, error=0, - assoc_id=S1AssocId}} -> - ?LOGVAR(S1AssocId) + assoc_id=S1AssocId}} = + recv_event(ok(gen_sctp:recv(S1))) end, + ?line #sctp_sndrcvinfo{ - ppid=17, context=0, timetolive=0, assoc_id=S1AssocId} = + ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} = getopt( S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}), ?line #sctp_sndrcvinfo{ - ppid=0, context=0, timetolive=0, assoc_id=S2AssocId} = + ppid=0, context=0, timetolive=0} = %, assoc_id=S2AssocId} = getopt( S2, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S2AssocId}), %% @@ -335,7 +400,19 @@ def_sndrcvinfo(Config) when is_list(Config) -> {Loopback,P1, [#sctp_sndrcvinfo{ stream=1, ppid=17, context=0, assoc_id=S2AssocId}], - <<"1: ",Data/binary>>} -> ok + <<"1: ",Data/binary>>} -> ok; + Event1 -> + ?line {Loopback,P1, + #sctp_paddr_change{state=addr_confirmed, + addr={_,P1}, + error=0, + assoc_id=S2AssocId}} = + recv_event(Event1), + ?line {Loopback,P1, + [#sctp_sndrcvinfo{ + stream=1, ppid=17, context=0, assoc_id=S2AssocId}], + <<"1: ",Data/binary>>} = + ok(gen_sctp:recv(S2)) end, %% ?line ok = @@ -368,10 +445,12 @@ def_sndrcvinfo(Config) when is_list(Config) -> [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, assoc_id=S1AssocId}], <<"3: ",Data/binary>>} -> ok; - {Loopback,P2,[], - #sctp_paddr_change{ - addr={Loopback,_}, state=addr_available, - error=0, assoc_id=S1AssocId}} -> + Event2 -> + {Loopback,P2, + #sctp_paddr_change{ + addr={Loopback,_}, state=addr_available, + error=0, assoc_id=S1AssocId}} = + recv_event(Event2), ?line case ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ @@ -525,7 +604,10 @@ api_listen(Config) when is_list(Config) -> #sctp_assoc_change{ state=comm_lost}}} = gen_sctp:recv(Sa, infinity); - {error,#sctp_assoc_change{state=cant_assoc}} -> ok + {error,#sctp_assoc_change{state=cant_assoc}} -> + ok%; + %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> + %% ok end, ?line ok = gen_sctp:listen(Sb, true), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -557,29 +639,41 @@ api_connect_init(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open(), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of {error,econnrefused} -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=comm_lost}}} = - gen_sctp:recv(Sa, infinity); + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_lost}} = + recv_event(ok(gen_sctp:recv(Sa, infinity))); ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=cant_assoc}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=cant_assoc}} = + recv_event(ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:listen(Sb, true), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{ - state = comm_up}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_up}} = + recv_event(ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), ok. +recv_event({Addr,Port,[],#sctp_assoc_change{}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_assoc_change{assoc_id=Assoc}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port,[],#sctp_paddr_change{}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_paddr_change{assoc_id=Assoc}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port,[],#sctp_shutdown_event{}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_shutdown_event{assoc_id=Assoc}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}. + api_opts(doc) -> "Test socket options"; api_opts(suite) -> @@ -645,9 +739,14 @@ implicit_inet6(S1, Addr) -> ?line P2 = ok(inet:port(S2)), ?line #sctp_assoc_change{state=comm_up} = ok(gen_sctp:connect(S2, Addr, P1, [])), - ?line case ok(gen_sctp:recv(S1)) of - {Addr,P2,[],#sctp_assoc_change{state=comm_up}} -> - ok + ?line case recv_event(ok(gen_sctp:recv(S1))) of + {Addr,P2,#sctp_assoc_change{state=comm_up}} -> + ok; + {Addr,P2,#sctp_paddr_change{state=addr_confirmed, + addr={Addr,P2}, + error=0}} -> + {Addr,P2,#sctp_assoc_change{state=comm_up}} = + recv_event(ok(gen_sctp:recv(S1))) end, ?line case ok(inet:sockname(S1)) of {Addr,P1} -> ok; @@ -692,14 +791,29 @@ xfer_stream_min(Config) when is_list(Config) -> inbound_streams=SaInboundStreams, assoc_id=SaAssocId}} = gen_sctp:connect(Sa, Loopback, Pb, []), - ?line {ok,{Loopback, - Pa,[], - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), + ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} = + case recv_event(ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} -> + {OS,IS,AI}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AI}} -> + {Loopback,Pa, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} = + recv_event(ok(gen_sctp:recv(Sb, infinity))), + {OS,IS,AI} + end, ?line SaOutboundStreams = SbInboundStreams, ?line SbOutboundStreams = SaInboundStreams, ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), @@ -724,24 +838,33 @@ xfer_stream_min(Config) when is_list(Config) -> ?line ok = do_from_other_process( fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end), - ?line {ok,{Loopback, - Pb, + ?line case ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], - Data}} = - gen_sctp:recv(Sa, infinity), - %% + Data} -> ok; + Event1 -> + ?line {Loopback,Pb, + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId}} = + recv_event(Event1), + ?line {Loopback,Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + ok(gen_sctp:recv(Sa, infinity)) + end, ?line ok = gen_sctp:close(Sa), - ?line {ok,{Loopback, - Pa,[], - #sctp_shutdown_event{assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line {ok,{Loopback, - Pa,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), + ?line {Loopback,Pa, + #sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sb), ?line receive @@ -822,8 +945,8 @@ peeloff(Config) when is_list(Config) -> ?line inet:i(sctp), ?line ok = socket_stop(S1), ?line ok = socket_stop(S2), - ?line {Addr,P2,[],#sctp_shutdown_event{assoc_id=S1Ai}} = - ok(socket_stop(S3)), + ?line {Addr,P2,#sctp_shutdown_event{assoc_id=S1Ai}} = + recv_event(ok(socket_stop(S3))), ok. @@ -857,8 +980,8 @@ buffers(Config) when is_list(Config) -> ?line {Addr,P2,S1Ai,Stream,Data} = socket_resp(H_b), %% ?line ok = socket_stop(S1), - ?line {Addr,P1,[],#sctp_shutdown_event{assoc_id=S2Ai}} = - ok(socket_stop(S2)), + ?line {Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}} = + recv_event(ok(socket_stop(S2))), ok. mk_data(Words) -> @@ -935,38 +1058,83 @@ socket_handler(Socket, Timeout) -> (socket) -> Socket; (recv_assoc) -> - {AssocAddr,AssocPort,[], - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId}} = - ok(gen_sctp:recv(Socket, infinity)), - case log(gen_sctp:recv(Socket, Timeout)) of - {ok,AssocAddr,AssocPort,[], - #sctp_paddr_change{addr = {AssocAddr,AssocPort}, - state = addr_available, - error = 0, - assoc_id = AssocId}} -> ok; - {error,timeout} -> ok - end, - {AssocId,Os,Is,AssocAddr,AssocPort}; + case recv_event(ok(gen_sctp:recv(Socket, Timeout))) of + {AssocAddr,AssocPort, + #sctp_paddr_change{state=addr_confirmed, + addr={_,AssocPort}, + error=0, + assoc_id=AssocId}} -> + {AssocAddr,AssocPort, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId}} = + recv_event(ok(gen_sctp:recv(Socket, infinity))), + {AssocId,Os,Is,AssocAddr,AssocPort}; + {AssocAddr,AssocPort, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId}} -> + {AssocId,Os,Is,AssocAddr,AssocPort} + end; + %% {AssocAddr,AssocPort,[], + %% #sctp_assoc_change{state=comm_up, + %% error=0, + %% outbound_streams=Os, + %% inbound_streams=Is, + %% assoc_id=AssocId}} = + %% ok(gen_sctp:recv(Socket, infinity)), + %% case log(gen_sctp:recv(Socket, Timeout)) of + %% {ok,AssocAddr,AssocPort,[], + %% #sctp_paddr_change{addr = {AssocAddr,AssocPort}, + %% state = addr_available, + %% error = 0, + %% assoc_id = AssocId}} -> ok; + %% {error,timeout} -> ok + %% end, + %% {AssocId,Os,Is,AssocAddr,AssocPort}; ({connect,ConAddr,ConPort,ConOpts}) -> - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId} = - ok(gen_sctp:connect(Socket, ConAddr, ConPort, ConOpts)), - case log(gen_sctp:recv(Socket, Timeout)) of - {ok,ConAddr,ConPort,[], - #sctp_paddr_change{addr = {ConAddr,ConPort}, - state = addr_available, - error = 0, - assoc_id = AssocId}} -> ok; - {error,timeout} -> ok - end, - {AssocId,Os,Is}; + ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts), + case recv_event(ok(gen_sctp:recv(Socket, Timeout))) of + {ConAddr,ConPort, + #sctp_paddr_change{state=addr_confirmed, + addr={_,ConPort}, + error=0, + assoc_id=AssocId}} -> + {ConAddr,ConPort, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId}} = + recv_event(ok(gen_sctp:recv(Socket, infinity))), + {AssocId,Os,Is}; + {ConAddr,ConPort, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=Os, + inbound_streams=Is, + assoc_id=AssocId}} -> + {AssocId,Os,Is} + end; + %% #sctp_assoc_change{state=comm_up, + %% error=0, + %% outbound_streams=Os, + %% inbound_streams=Is, + %% assoc_id=AssocId} = + %% ok(gen_sctp:connect(Socket, ConAddr, ConPort, ConOpts)), + %% case log(gen_sctp:recv(Socket, Timeout)) of + %% {ok,ConAddr,ConPort,[], + %% #sctp_paddr_change{addr = {ConAddr,ConPort}, + %% state = addr_available, + %% error = 0, + %% assoc_id = AssocId}} -> ok; + %% {error,timeout} -> ok + %% end, + %% {AssocId,Os,Is}; ({send,AssocId,Stream,Data}) -> gen_sctp:send(Socket, AssocId, Stream, Data); ({send,S,AssocId,Stream,Data}) -> -- cgit v1.2.3 From c501ca26c01d222af4b05b1732059a7a9684b1c3 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 22 Sep 2011 11:11:57 +0200 Subject: kernel: Rewrite SCTP test socket handler The socket handler needs more flexibility regarding which events are expected to be received. --- lib/kernel/test/gen_sctp_SUITE.erl | 603 ++++++++++++++++++++++--------------- 1 file changed, 360 insertions(+), 243 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 8011c22ce5..07434df8da 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -110,7 +110,7 @@ xfer_min(Config) when is_list(Config) -> assoc_id=SaAssocId}=SaAssocChange} = gen_sctp:connect(Sa, Loopback, Pb, []), ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = - case recv_event(ok(gen_sctp:recv(Sb, infinity))) of + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, @@ -129,12 +129,12 @@ xfer_min(Config) when is_list(Config) -> outbound_streams=SbOutboundStreams, inbound_streams=SbInboundStreams, assoc_id=AssocId}} = - ?line recv_event(ok(gen_sctp:recv(Sb, infinity))), + ?line recv_event(log_ok(gen_sctp:recv(Sb, infinity))), {AssocId,SbInboundStreams,SbOutboundStreams} end, ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case ok(gen_sctp:recv(Sb, infinity)) of + ?line case log_ok(gen_sctp:recv(Sb, infinity)) of {Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, @@ -154,7 +154,7 @@ xfer_min(Config) when is_list(Config) -> Data}} = gen_sctp:recv(Sb, infinity) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), - ?line case ok(gen_sctp:recv(Sa, infinity)) of + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], @@ -172,22 +172,22 @@ xfer_min(Config) when is_list(Config) -> [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], Data} = - ok(gen_sctp:recv(Sa, infinity)) + log_ok(gen_sctp:recv(Sa, infinity)) end, %% ?line ok = gen_sctp:eof(Sa, SaAssocChange), ?line {Loopback,Pa,#sctp_shutdown_event{assoc_id=SbAssocId}} = - recv_event(ok(gen_sctp:recv(Sb, infinity))), + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line {Loopback,Pb, #sctp_assoc_change{state=shutdown_comp, error=0, assoc_id=SaAssocId}} = - recv_event(ok(gen_sctp:recv(Sa, infinity))), + recv_event(log_ok(gen_sctp:recv(Sa, infinity))), ?line {Loopback,Pa, #sctp_assoc_change{state=shutdown_comp, error=0, assoc_id=SbAssocId}} = - recv_event(ok(gen_sctp:recv(Sb, infinity))), + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), @@ -338,11 +338,11 @@ def_sndrcvinfo(Config) when is_list(Config) -> ?line Data = <<"What goes up, must come down.">>, %% ?line S1 = - ok(gen_sctp:open( + log_ok(gen_sctp:open( 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), ?LOGVAR(S1), ?line P1 = - ok(inet:port(S1)), + log_ok(inet:port(S1)), ?LOGVAR(P1), ?line #sctp_sndrcvinfo{ppid=17, context=0, timetolive=0, assoc_id=0} = getopt(S1, sctp_default_send_param), @@ -350,10 +350,10 @@ def_sndrcvinfo(Config) when is_list(Config) -> gen_sctp:listen(S1, true), %% ?line S2 = - ok(gen_sctp:open()), + log_ok(gen_sctp:open()), ?LOGVAR(S2), ?line P2 = - ok(inet:port(S2)), + log_ok(inet:port(S2)), ?LOGVAR(P2), ?line #sctp_sndrcvinfo{ppid=0, context=0, timetolive=0, assoc_id=0} = getopt(S2, sctp_default_send_param), @@ -362,9 +362,9 @@ def_sndrcvinfo(Config) when is_list(Config) -> state=comm_up, error=0, assoc_id=S2AssocId} = S2AssocChange = - ok(gen_sctp:connect(S2, Loopback, P1, [])), + log_ok(gen_sctp:connect(S2, Loopback, P1, [])), ?LOGVAR(S2AssocChange), - ?line case recv_event(ok(gen_sctp:recv(S1))) of + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of {Loopback,P2, #sctp_assoc_change{ state=comm_up, @@ -382,7 +382,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> state=comm_up, error=0, assoc_id=S1AssocId}} = - recv_event(ok(gen_sctp:recv(S1))) + recv_event(log_ok(gen_sctp:recv(S1))) end, ?line #sctp_sndrcvinfo{ @@ -396,7 +396,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line ok = gen_sctp:send(S1, S1AssocId, 1, <<"1: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=1, ppid=17, context=0, assoc_id=S2AssocId}], @@ -412,7 +412,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> [#sctp_sndrcvinfo{ stream=1, ppid=17, context=0, assoc_id=S2AssocId}], <<"1: ",Data/binary>>} = - ok(gen_sctp:recv(S2)) + log_ok(gen_sctp:recv(S2)) end, %% ?line ok = @@ -432,7 +432,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line ok = gen_sctp:send(S1, S1AssocId, 0, <<"2: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=0, ppid=19, context=0, assoc_id=S2AssocId}], @@ -440,7 +440,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> end, ?line ok = gen_sctp:send(S2, S2AssocChange, 1, <<"3: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S1)) of + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, assoc_id=S1AssocId}], @@ -451,7 +451,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> addr={Loopback,_}, state=addr_available, error=0, assoc_id=S1AssocId}} = recv_event(Event2), - ?line case ok(gen_sctp:recv(S1)) of + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, @@ -467,7 +467,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> #sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId}, <<"4: ",Data/binary>>) end), - ?line case ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of + ?line case log_ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=0, ppid=20, context=0, assoc_id=S1AssocId}], @@ -496,9 +496,9 @@ getopt(S, Opt, Param) -> setopt(S, Opt, Val) -> inet:setopts(S, [{Opt,Val}]). -ok({ok,X}) -> - io:format("OK[~w]: ~p~n", [self(),X]), - X. +log_ok(X) -> log(ok(X)). + +ok({ok,X}) -> X. log(X) -> io:format("LOG[~w]: ~p~n", [self(),X]), @@ -640,16 +640,16 @@ api_connect_init(Config) when is_list(Config) -> ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of {error,econnrefused} -> ?line {Localhost,Pb,#sctp_assoc_change{state=comm_lost}} = - recv_event(ok(gen_sctp:recv(Sa, infinity))); + recv_event(log_ok(gen_sctp:recv(Sa, infinity))); ok -> ?line {Localhost,Pb,#sctp_assoc_change{state=cant_assoc}} = - recv_event(ok(gen_sctp:recv(Sa, infinity))) + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:listen(Sb, true), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of ok -> ?line {Localhost,Pb,#sctp_assoc_change{state=comm_up}} = - recv_event(ok(gen_sctp:recv(Sa, infinity))) + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), @@ -699,7 +699,7 @@ api_opts(Config) when is_list(Config) -> end. implicit_inet6(Config) when is_list(Config) -> - ?line Hostname = ok(inet:gethostname()), + ?line Hostname = log_ok(inet:gethostname()), ?line case gen_sctp:open(0, [inet6]) of {ok,S1} -> @@ -712,16 +712,16 @@ implicit_inet6(Config) when is_list(Config) -> ?line ok = gen_sctp:close(S1), %% ?line Localhost = - ok(inet:getaddr("localhost", inet6)), + log_ok(inet:getaddr("localhost", inet6)), ?line io:format("~s ~p~n", ["localhost",Localhost]), ?line S2 = - ok(gen_sctp:open(0, [{ip,Localhost}])), + log_ok(gen_sctp:open(0, [{ip,Localhost}])), ?line implicit_inet6(S2, Localhost), ?line ok = gen_sctp:close(S2), %% ?line io:format("~s ~p~n", [Hostname,Host]), ?line S3 = - ok(gen_sctp:open(0, [{ifaddr,Host}])), + log_ok(gen_sctp:open(0, [{ifaddr,Host}])), ?line implicit_inet6(S3, Host), ?line ok = gen_sctp:close(S1); {error,eafnosupport} -> @@ -734,25 +734,25 @@ implicit_inet6(Config) when is_list(Config) -> implicit_inet6(S1, Addr) -> ?line ok = gen_sctp:listen(S1, true), - ?line P1 = ok(inet:port(S1)), - ?line S2 = ok(gen_sctp:open(0, [inet6])), - ?line P2 = ok(inet:port(S2)), + ?line P1 = log_ok(inet:port(S1)), + ?line S2 = log_ok(gen_sctp:open(0, [inet6])), + ?line P2 = log_ok(inet:port(S2)), ?line #sctp_assoc_change{state=comm_up} = - ok(gen_sctp:connect(S2, Addr, P1, [])), - ?line case recv_event(ok(gen_sctp:recv(S1))) of + log_ok(gen_sctp:connect(S2, Addr, P1, [])), + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of {Addr,P2,#sctp_assoc_change{state=comm_up}} -> ok; {Addr,P2,#sctp_paddr_change{state=addr_confirmed, addr={Addr,P2}, error=0}} -> {Addr,P2,#sctp_assoc_change{state=comm_up}} = - recv_event(ok(gen_sctp:recv(S1))) + recv_event(log_ok(gen_sctp:recv(S1))) end, - ?line case ok(inet:sockname(S1)) of + ?line case log_ok(inet:sockname(S1)) of {Addr,P1} -> ok; {{0,0,0,0,0,0,0,0},P1} -> ok end, - ?line case ok(inet:sockname(S2)) of + ?line case log_ok(inet:sockname(S2)) of {Addr,P2} -> ok; {{0,0,0,0,0,0,0,0},P2} -> ok end, @@ -792,7 +792,7 @@ xfer_stream_min(Config) when is_list(Config) -> assoc_id=SaAssocId}} = gen_sctp:connect(Sa, Loopback, Pb, []), ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} = - case recv_event(ok(gen_sctp:recv(Sb, infinity))) of + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, @@ -811,7 +811,7 @@ xfer_stream_min(Config) when is_list(Config) -> outbound_streams=OS, inbound_streams=IS, assoc_id=AI}} = - recv_event(ok(gen_sctp:recv(Sb, infinity))), + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), {OS,IS,AI} end, ?line SaOutboundStreams = SbInboundStreams, @@ -838,7 +838,7 @@ xfer_stream_min(Config) when is_list(Config) -> ?line ok = do_from_other_process( fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end), - ?line case ok(gen_sctp:recv(Sa, infinity)) of + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], @@ -854,17 +854,17 @@ xfer_stream_min(Config) when is_list(Config) -> [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], Data} = - ok(gen_sctp:recv(Sa, infinity)) + log_ok(gen_sctp:recv(Sa, infinity)) end, ?line ok = gen_sctp:close(Sa), ?line {Loopback,Pa, #sctp_shutdown_event{assoc_id=SbAssocId}} = - recv_event(ok(gen_sctp:recv(Sb, infinity))), + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line {Loopback,Pa, #sctp_assoc_change{state=shutdown_comp, error=0, assoc_id=SbAssocId}} = - recv_event(ok(gen_sctp:recv(Sb, infinity))), + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sb), ?line receive @@ -911,42 +911,97 @@ peeloff(Config) when is_list(Config) -> ?line Addr = {127,0,0,1}, ?line Stream = 0, ?line Timeout = 333, - ?line S1 = socket_start(Addr, Timeout), - ?line P1 = socket_call(S1, port), - ?line Socket1 = socket_call(S1, socket), - ?line ok = socket_call(S1, {listen,true}), - ?line S2 = socket_start(Addr, Timeout), - ?line P2 = socket_call(S2, port), - ?line Socket2 = socket_call(S2, socket), + ?line S1 = socket_open([{ifaddr,Addr}], Timeout), + ?line ?LOGVAR(S1), + ?line P1 = socket_call(S1, get_port), + ?line ?LOGVAR(P1), + ?line Socket1 = socket_call(S1, get_socket), + ?line ?LOGVAR(Socket1), + ?line socket_call(S1, {listen,true}), + ?line S2 = socket_open([{ifaddr,Addr}], Timeout), + ?line ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), + ?line Socket2 = socket_call(S2, get_socket), + ?line ?LOGVAR(Socket2), %% - ?line H_a = socket_req(S1, recv_assoc), - ?line {S2Ai,Sa,Sb} = socket_call(S2, {connect,Addr,P1,[]}), - ?line {S1Ai,Sb,Sa,Addr,P2} = socket_resp(H_a), + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S2Ai), + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S1Ai), %% - ?line H_b = socket_req(S1, recv), - ?line ok = socket_call(S2, {send,S2Ai,Stream,<<"Data H_b">>}), - ?line {Addr,P2,S1Ai,Stream,<<"Data H_b">>} = socket_resp(H_b), - ?line H_c = socket_req(S1, {recv,Socket2}), - ?line ok = - socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Data H_c">>}), - ?line {Addr,P1,S2Ai,Stream,<<"Data H_c">>} = socket_resp(H_c), + ?line socket_call(S2, {send,S2Ai,Stream,<<"Number one">>}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}), + ?line + receive + {S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, %% ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), - ?line P3 = socket_call(S3, port), - ?line Socket3 = socket_call(S3, socket), + ?line ?LOGVAR(S3), + ?line P3 = socket_call(S3, get_port), + ?line ?LOGVAR(P3), ?line S3Ai = S1Ai, + ?line ?LOGVAR(S3Ai), %% - ?line H_d = socket_req(S2, recv), - ?line ok = socket_call(S3, {send,S3Ai,Stream,<<"Data H_d">>}), - ?line {Addr,P3,S2Ai,Stream,<<"Data H_d">>} = socket_resp(H_d), - ?line ok = socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Data S2">>}), - ?line {Addr,P2,S3Ai,Stream,<<"Data S2">>} = socket_call(S2, {recv,Socket3}), + ?line socket_call(S3, {send,S3Ai,Stream,<<"Number three">>}), + ?line + receive + {S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, + ?line socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}), + ?line + receive + {S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, %% ?line inet:i(sctp), - ?line ok = socket_stop(S1), - ?line ok = socket_stop(S2), - ?line {Addr,P2,#sctp_shutdown_event{assoc_id=S1Ai}} = - recv_event(ok(socket_stop(S3))), + ?line socket_close_verbose(S1), + ?line socket_close_verbose(S2), + ?line + receive + {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai}}} -> ok + after Timeout -> + socket_bailout([S3]) + end, + ?line + receive + {S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S3Ai}}} -> ok + after Timeout -> + socket_bailout([S3]) + end, + ?line socket_close_verbose(S3), + ?line [] = flush(), ok. @@ -960,28 +1015,65 @@ buffers(Config) when is_list(Config) -> ?line Data = mk_data(Limit), ?line Addr = {127,0,0,1}, ?line Stream = 1, - ?line Timeout = 333, - ?line S1 = socket_start(Addr, Timeout), - ?line P1 = socket_call(S1, port), + ?line Timeout = 1333, + ?line S1 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S1), + ?line P1 = socket_call(S1, get_port), + ?line ?LOGVAR(P1), ?line ok = socket_call(S1, {listen,true}), - ?line S2 = socket_start(Addr, Timeout), - ?line P2 = socket_call(S2, port), + ?line S2 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), %% - ?line H_a = socket_req(S1, recv_assoc), - ?line {S2Ai,Sa,Sb} = socket_call(S2, {connect,Addr,P1,[]}), - ?line {S1Ai,Sb,Sa,Addr,P2} = socket_resp(H_a), + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, %% - ?line ok = socket_call(S1, {setopts,[{recbuf,Limit}]}), + ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), ?line case socket_call(S1, {getopts,[recbuf]}) of - {ok,[{recbuf,RB1}]} when RB1 >= Limit -> ok + [{recbuf,RB1}] when RB1 >= Limit -> ok end, - ?line H_b = socket_req(S1, recv), - ?line ok = socket_call(S2, {send,S2Ai,Stream,Data}), - ?line {Addr,P2,S1Ai,Stream,Data} = socket_resp(H_b), + ?line socket_call(S2, {send,S2Ai,Stream,Data}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,Data}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, %% - ?line ok = socket_stop(S1), - ?line {Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}} = - recv_event(ok(socket_stop(S2))), + ?line socket_close_verbose(S1), + ?line + receive + {S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line + receive + {S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line socket_close_verbose(S2), + ?line [] = flush(), ok. mk_data(Words) -> @@ -995,38 +1087,101 @@ mk_data(N, Words, Bin) -> %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light +socket_open(SocketOpts, Timeout) -> + Opts = [{type,seqpacket},{active,once},binary|SocketOpts], + Starter = + fun () -> + {ok,Socket} = + gen_sctp:open(Opts), + Socket + end, + s_start(Starter, Timeout). + socket_peeloff(Socket, AssocId, Timeout) -> + Opts = [{active,once},binary], Starter = fun () -> {ok,NewSocket} = gen_sctp:peeloff(Socket, AssocId), + ok = inet:setopts(NewSocket, Opts), NewSocket end, - socket_starter(Starter, Timeout). + s_start(Starter, Timeout). + +socket_close_verbose(S) -> + History = socket_history(socket_close(S)), + io:format("socket_close ~p:~n ~p.~n", [S,History]), + History. + +socket_close(S) -> + s_req(S, close). + +socket_call(S, Request) -> + s_req(S, {Request}). + +%% socket_get(S, Key) -> +%% s_req(S, {get,Key}). + +socket_bailout([S|Ss]) -> + History = socket_history(socket_close(S)), + io:format("bailout ~p:~n ~p.~n", [S,History]), + socket_bailout(Ss); +socket_bailout([]) -> + io:format("flush: ~p.~n", [flush()]), + test_server:fail(socket_bailout). + +socket_history({State,Flush}) -> + {lists:keysort( + 2, + lists:flatten( + [[{Key,Val} || Val <- Vals] + || {Key,Vals} <- gb_trees:to_list(State)])), + Flush}. + +s_handler(Socket) -> + fun ({listen,Listen}) -> + ok = gen_sctp:listen(Socket, Listen); + (get_port) -> + ok(inet:port(Socket)); + (get_socket) -> + Socket; + ({connect_init,ConAddr,ConPort,ConOpts}) -> + ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts); + ({send,AssocId,Stream,Data}) -> + ok = gen_sctp:send(Socket, AssocId, Stream, Data); + ({send,OtherSocket,AssocId,Stream,Data}) -> + ok = gen_sctp:send(OtherSocket, AssocId, Stream, Data); + ({setopts,Opts}) -> + ok = inet:setopts(Socket, Opts); + ({getopts,Optnames}) -> + ok(inet:getopts(Socket, Optnames)) + end. -socket_start(Addr, Timeout) -> - Starter = - fun () -> - {ok,Socket} = - gen_sctp:open([{type,seqpacket},{ifaddr,Addr}]), - Socket - end, - socket_starter(Starter, Timeout). +s_req(S, Req) -> + Mref = erlang:monitor(process, S), + S ! {self(),Mref,Req}, + receive + {'DOWN',Mref,_,_,Error} -> + exit(Error); + {S,Mref,Reply} -> + erlang:demonitor(Mref), + receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end, + Reply + end. -socket_starter(Starter, Timeout) -> +s_start(Starter, Timeout) -> Parent = self(), Owner = spawn_link( fun () -> - socket_starter(Starter(), Timeout, Parent) + s_start(Starter(), Timeout, Parent) end), - io:format("Started socket ~w.~n", [Owner]), Owner. -socket_starter(Socket, Timeout, Parent) -> +s_start(Socket, Timeout, Parent) -> + Handler = s_handler(Socket), try - Handler = socket_handler(Socket, Timeout), - socket_loop(Socket, Timeout, Parent, Handler) + s_loop(Socket, Timeout, Parent, Handler, gb_trees:empty()) catch Class:Reason -> Stacktrace = erlang:get_stacktrace(), @@ -1035,150 +1190,112 @@ socket_starter(Socket, Timeout, Parent) -> erlang:raise(Class, Reason, Stacktrace) end. -socket_loop(Socket, Timeout, Parent, Handler) -> +s_loop(Socket, Timeout, Parent, Handler, State) -> receive - {Parent,Ref} -> % socket_stop() - Result = - case log(gen_sctp:recv(Socket, Timeout)) of - {error,timeout} -> ok; - R -> R - end, + {Parent,Ref,close} -> % socket_close() + erlang:send_after(Timeout, self(), {Parent,Ref,exit}), + s_loop(Socket, Timeout, Parent, Handler, State); + {Parent,Ref,exit} -> ok = gen_sctp:close(Socket), - Parent ! {self(),Ref, Result}; - {Parent,Ref,Msg} -> - Parent ! {self(),Ref,Handler(Msg)}, - socket_loop(Socket, Timeout, Parent, Handler) + Key = exit, + Val = {now(),Socket}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,{NewState,flush()}}; + {Parent,Ref,{Msg}} -> + Result = Handler(Msg), + Key = req, + Val = {now(),{Msg,Result}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,Result}, + s_loop(Socket, Timeout, Parent, Handler, NewState); + %% {Parent,Ref,{get,Key}} -> + %% Parent ! {self(),Ref,gb_get(Key, State)}, + %% s_loop(Socket, Timeout, Parent, Handler, State); + {sctp,Socket,Addr,Port, + {[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}} + when not is_tuple(Data) -> + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port, + #sctp_assoc_change{ + state=comm_up, + inbound_streams=Is}}}|_] + when 0 =< Stream, Stream < Is-> ok; + [] -> ok + end, + Key = {msg,AssocId,Stream}, + Val = {now(),{Addr,Port,SRI,Data}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,AssocId,Stream,Data}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_assoc_change{assoc_id=AssocId,state=St}=SAC}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + Key = {assoc_change,AssocId}, + Val = {now(),{Addr,Port,SAC}}, + case {gb_get(Key, State),St} of + {[],_} -> ok; + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} + when St =:= comm_lost; St =:= shutdown_comp -> ok + end, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,SAC}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_paddr_change{assoc_id=AssocId, + addr={_,Port}, + state=St}=SPC}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case {gb_get({assoc_change,AssocId}, State),St} of + {[],_} when St =:= addr_confirmed -> ok + end, + Key = {paddr_change,AssocId}, + Val = {now(),{Addr,Port,SPC}}, + NewState = gb_push(Key, Val, State), + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_shutdown_event{assoc_id=AssocId}=SSE}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok; + [] -> ok + end, + Key = {shutdown_event,AssocId}, + Val = {now(),{Addr,Port}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(), {Addr,Port,SSE}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + Unexpected -> + erlang:error({unexpected,Unexpected}) end. -socket_handler(Socket, Timeout) -> - fun ({listen,Listen}) -> - gen_sctp:listen(Socket, Listen); - (port) -> - ok(inet:port(Socket)); - (socket) -> - Socket; - (recv_assoc) -> - case recv_event(ok(gen_sctp:recv(Socket, Timeout))) of - {AssocAddr,AssocPort, - #sctp_paddr_change{state=addr_confirmed, - addr={_,AssocPort}, - error=0, - assoc_id=AssocId}} -> - {AssocAddr,AssocPort, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId}} = - recv_event(ok(gen_sctp:recv(Socket, infinity))), - {AssocId,Os,Is,AssocAddr,AssocPort}; - {AssocAddr,AssocPort, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId}} -> - {AssocId,Os,Is,AssocAddr,AssocPort} - end; - %% {AssocAddr,AssocPort,[], - %% #sctp_assoc_change{state=comm_up, - %% error=0, - %% outbound_streams=Os, - %% inbound_streams=Is, - %% assoc_id=AssocId}} = - %% ok(gen_sctp:recv(Socket, infinity)), - %% case log(gen_sctp:recv(Socket, Timeout)) of - %% {ok,AssocAddr,AssocPort,[], - %% #sctp_paddr_change{addr = {AssocAddr,AssocPort}, - %% state = addr_available, - %% error = 0, - %% assoc_id = AssocId}} -> ok; - %% {error,timeout} -> ok - %% end, - %% {AssocId,Os,Is,AssocAddr,AssocPort}; - ({connect,ConAddr,ConPort,ConOpts}) -> - ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts), - case recv_event(ok(gen_sctp:recv(Socket, Timeout))) of - {ConAddr,ConPort, - #sctp_paddr_change{state=addr_confirmed, - addr={_,ConPort}, - error=0, - assoc_id=AssocId}} -> - {ConAddr,ConPort, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId}} = - recv_event(ok(gen_sctp:recv(Socket, infinity))), - {AssocId,Os,Is}; - {ConAddr,ConPort, - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=Os, - inbound_streams=Is, - assoc_id=AssocId}} -> - {AssocId,Os,Is} - end; - %% #sctp_assoc_change{state=comm_up, - %% error=0, - %% outbound_streams=Os, - %% inbound_streams=Is, - %% assoc_id=AssocId} = - %% ok(gen_sctp:connect(Socket, ConAddr, ConPort, ConOpts)), - %% case log(gen_sctp:recv(Socket, Timeout)) of - %% {ok,ConAddr,ConPort,[], - %% #sctp_paddr_change{addr = {ConAddr,ConPort}, - %% state = addr_available, - %% error = 0, - %% assoc_id = AssocId}} -> ok; - %% {error,timeout} -> ok - %% end, - %% {AssocId,Os,Is}; - ({send,AssocId,Stream,Data}) -> - gen_sctp:send(Socket, AssocId, Stream, Data); - ({send,S,AssocId,Stream,Data}) -> - gen_sctp:send(S, AssocId, Stream, Data); - (recv) -> - {Addr,Port, - [#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}],Data} = - ok(gen_sctp:recv(Socket, infinity)), - {Addr,Port,AssocId,Stream,Data}; - ({recv,S}) -> - {Addr,Port, - [#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}],Data} = - ok(gen_sctp:recv(S, infinity)), - {Addr,Port,AssocId,Stream,Data}; - ({setopts,Opts}) -> - inet:setopts(Socket, Opts); - ({getopts,Optnames}) -> - inet:getopts(Socket, Optnames) - end. +again(Socket) -> + inet:setopts(Socket, [{active,once}]). -socket_stop(Handler) -> - Mref = erlang:monitor(process, Handler), - Handler ! {self(),Mref}, - receive - {Handler,Mref,Result} -> - receive {'DOWN',Mref,_,_,_} -> Result end; - {'DOWN',Mref,_,_,Error} -> - exit(Error) +gb_push(Key, Val, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + gb_trees:insert(Key, [Val], GBT); + {value,V} -> + gb_trees:update(Key, [Val|V], GBT) end. -socket_call(Handler, Request) -> - socket_resp(socket_req(Handler, Request)). - -socket_req(Handler, Request) -> - Mref = erlang:monitor(process, Handler), - Handler ! {self(),Mref,Request}, - {Handler,Mref}. - -socket_resp({Handler,Mref}) -> - receive - {'DOWN',Mref,_,_,Error} -> - exit(Error); - {Handler,Mref,Reply} -> - erlang:demonitor(Mref), - receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end, - Reply +gb_get(Key, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + []; + {value,V} -> + V end. -- cgit v1.2.3 From 3be53d45e394dab127563d7a8d6da109cd9bc108 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 28 Sep 2011 10:19:17 +0200 Subject: kernel: Adjust SCTP tests to Solaris quirks --- lib/kernel/test/gen_sctp_SUITE.erl | 94 +++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 31 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 07434df8da..301f69ce09 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -250,9 +250,10 @@ xfer_active(Config) when is_list(Config) -> error=0, assoc_id=SbAssocId} -> ok; #sctp_paddr_change{state=addr_available, - addr={Loopback,Pa}, + addr={Loopback,P}, error=0, - assoc_id=SbAssocId} -> ok; + assoc_id=SbAssocId} -> + ?line match_unless_solaris(Pa, P); timeout -> ok end, ?line [] = flush(), @@ -266,7 +267,7 @@ xfer_active(Config) when is_list(Config) -> assoc_id=SbAssocId}], Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), ?line receive @@ -275,7 +276,7 @@ xfer_active(Config) when is_list(Config) -> assoc_id=SaAssocId}], Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, %% ?line ok = gen_sctp:abort(Sa, SaAssocChange), @@ -283,19 +284,20 @@ xfer_active(Config) when is_list(Config) -> #sctp_assoc_change{state=comm_lost, assoc_id=SbAssocId} -> ok; timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:close(Sb), ?line case recv_assoc_change(Sa, Loopback, Pb, Timeout) of #sctp_assoc_change{state=comm_lost, assoc_id=SaAssocId} -> ok; timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line io:format("timeout waiting for comm_lost on Sa~n"), + ?line match_unless_solaris(ok, {timeout,flush()}) end, ?line receive - {sctp_error,Sa,enotconn} -> ok % Solaris - after 17 -> ok %% Only happens on Solaris - end, + {sctp_error,Sa,enotconn} -> ok % Solaris + after 17 -> ok + end, ?line ok = gen_sctp:close(Sa), %% ?line receive @@ -780,17 +782,28 @@ xfer_stream_min(Config) when is_list(Config) -> ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, ?line Loopback = {127,0,0,1}, ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), + ?line ?LOGVAR(Sb), ?line {ok,Pb} = inet:port(Sb), + ?line ?LOGVAR(Pb), ?line ok = gen_sctp:listen(Sb, true), ?line {ok,Sa} = gen_sctp:open([{type,stream}]), + ?line ?LOGVAR(Sa), ?line {ok,Pa} = inet:port(Sa), - ?line {ok,#sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SaOutboundStreams, - inbound_streams=SaInboundStreams, - assoc_id=SaAssocId}} = - gen_sctp:connect(Sa, Loopback, Pb, []), + ?line ?LOGVAR(Pa), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId_X} = + log_ok(gen_sctp:connect(Sa, Loopback, Pb, [])), + ?line ?LOGVAR(SaAssocId_X), + ?line [{_,#sctp_paddrinfo{assoc_id=SaAssocId,state=active}}] = + log_ok(inet:getopts(Sa, [{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Loopback,Pb}}}])), + ?line ?LOGVAR(SaAssocId), + ?line match_unless_solaris(SaAssocId_X, SaAssocId), + ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} = case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of {Loopback,Pa, @@ -814,8 +827,11 @@ xfer_stream_min(Config) when is_list(Config) -> recv_event(log_ok(gen_sctp:recv(Sb, infinity))), {OS,IS,AI} end, + ?line ?LOGVAR(SbAssocId), ?line SaOutboundStreams = SbInboundStreams, + ?line ?LOGVAR(SaOutboundStreams), ?line SbOutboundStreams = SaInboundStreams, + ?line ?LOGVAR(SbOutboundStreams), ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), ?line case gen_sctp:recv(Sb, infinity) of {ok,{Loopback, @@ -966,7 +982,11 @@ peeloff(Config) when is_list(Config) -> ?line ?LOGVAR(S3), ?line P3 = socket_call(S3, get_port), ?line ?LOGVAR(P3), - ?line S3Ai = S1Ai, + ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = + socket_call(S3, + {getopts,[{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Addr,P2}}}]}), + %%?line S3Ai = S1Ai, ?line ?LOGVAR(S3Ai), %% ?line socket_call(S3, {send,S3Ai,Stream,<<"Number three">>}), @@ -989,7 +1009,8 @@ peeloff(Config) when is_list(Config) -> ?line socket_close_verbose(S2), ?line receive - {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai}}} -> ok + {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} -> + ?line match_unless_solaris(S3Ai, S3Ai_X) after Timeout -> socket_bailout([S3]) end, @@ -1011,11 +1032,10 @@ buffers(doc) -> buffers(suite) -> []; buffers(Config) when is_list(Config) -> - ?line Limit = 8192, - ?line Data = mk_data(Limit), + ?line Limit = 4096, ?line Addr = {127,0,0,1}, ?line Stream = 1, - ?line Timeout = 1333, + ?line Timeout = 3333, ?line S1 = socket_open([{ip,Addr}], Timeout), ?line ?LOGVAR(S1), ?line P1 = socket_call(S1, get_port), @@ -1047,9 +1067,12 @@ buffers(Config) when is_list(Config) -> end, %% ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), - ?line case socket_call(S1, {getopts,[recbuf]}) of - [{recbuf,RB1}] when RB1 >= Limit -> ok - end, + ?line Recbuf = + case socket_call(S1, {getopts,[recbuf]}) of + [{recbuf,RB1}] when RB1 >= Limit -> RB1 + end, + ?line Data = mk_data(Recbuf+Limit), + ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}), ?line socket_call(S2, {send,S2Ai,Stream,Data}), ?line receive @@ -1076,13 +1099,13 @@ buffers(Config) when is_list(Config) -> ?line [] = flush(), ok. -mk_data(Words) -> - mk_data(0, Words, <<>>). +mk_data(Bytes) -> + mk_data(0, Bytes, <<>>). %% -mk_data(Words, Words, Bin) -> - Bin; -mk_data(N, Words, Bin) -> - mk_data(N+1, Words, <>). +mk_data(N, Bytes, Bin) when N < Bytes -> + mk_data(N+4, Bytes, <>); +mk_data(_, _, Bin) -> + Bin. %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light @@ -1247,14 +1270,17 @@ s_loop(Socket, Timeout, Parent, Handler, State) -> s_loop(Socket, Timeout, Parent, Handler, NewState); {sctp,Socket,Addr,Port, {SRI,#sctp_paddr_change{assoc_id=AssocId, - addr={_,Port}, + addr={_,P}, state=St}=SPC}} -> + match_unless_solaris(Port, P), case SRI of [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; [] -> ok end, case {gb_get({assoc_change,AssocId}, State),St} of - {[],_} when St =:= addr_confirmed -> ok + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_], + addr_available} -> ok; + {[],addr_confirmed} -> ok end, Key = {paddr_change,AssocId}, Val = {now(),{Addr,Port,SPC}}, @@ -1299,3 +1325,9 @@ gb_get(Key, GBT) -> {value,V} -> V end. + +match_unless_solaris(A, B) -> + case os:type() of + {unix,sunos} -> B; + _ -> A = B + end. -- cgit v1.2.3 From 4f8e3e94357cd4730c9e3135f2bafd9b6d4fd13e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 28 Sep 2011 11:48:08 +0200 Subject: erts,kernel: Return eprotonosupport when SCTP is not supported It is better that gen_sctp:open/0-2 returns the informative Posix return code {error,eprotonosupport} than previously {error,badarg} when SCTP is not supported since it is so platform dependent. --- lib/kernel/test/gen_sctp_SUITE.erl | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 301f69ce09..d0b0bdf4d4 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -44,17 +44,12 @@ groups() -> []. init_per_suite(Config) -> - try gen_sctp:open() of + case gen_sctp:open() of {ok,Socket} -> gen_sctp:close(Socket), []; - _ -> - [] - catch - error:badarg -> - {skip,"SCTP not supported on this machine"}; - _:_ -> - Config + {error,eprotonosupport} -> + {skip,"SCTP not supported on this machine"} end. end_per_suite(_Conifig) -> -- cgit v1.2.3 From 3d4c4eaf917e92c52c6533e17c98aeab81125f3b Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 18 Oct 2011 16:27:00 +0200 Subject: kernel: Adjust SCTP test to SuSE quirk inet:port/1 on peeled off socket returns 0. Bug? Who's? --- lib/kernel/test/gen_sctp_SUITE.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index d0b0bdf4d4..300152ddce 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -43,7 +43,7 @@ all() -> groups() -> []. -init_per_suite(Config) -> +init_per_suite(_Config) -> case gen_sctp:open() of {ok,Socket} -> gen_sctp:close(Socket), @@ -52,7 +52,7 @@ init_per_suite(Config) -> {skip,"SCTP not supported on this machine"} end. -end_per_suite(_Conifig) -> +end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> @@ -975,8 +975,9 @@ peeloff(Config) when is_list(Config) -> %% ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), ?line ?LOGVAR(S3), - ?line P3 = socket_call(S3, get_port), - ?line ?LOGVAR(P3), + ?line P3_X = socket_call(S3, get_port), + ?line ?LOGVAR(P3_X), + ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end, ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = socket_call(S3, {getopts,[{sctp_get_peer_addr_info, -- cgit v1.2.3 From d6d9371d50e7e9ad8708e914b72fa755ce5a5385 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 21 Oct 2011 17:51:34 +0200 Subject: kernel: Documented gen_sctp:peeloff/2 --- lib/kernel/doc/src/gen_sctp.xml | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'lib/kernel') diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index b9f23674f0..418bfae4b8 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -45,7 +45,15 @@ SUSE Linux Enterprise Server 10 (x86_64) kernel 2.6.16.27-0.6-smp, with lksctp-tools-1.0.6, briefly on Solaris 10, and later on SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64) - kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7.

+ kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7, + and later also on FreeBSD 8.2. +

+

+ This module was written for one-to-many style sockets + (type seqpacket). With the addition of + peeloff/2, one-to-one style + sockets (type stream) were introduced. +

Record definitions for the gen_sctp module can be found using:

  -include_lib("kernel/include/inet_sctp.hrl").    

These record definitions use the "new" spelling 'adaptation', @@ -299,11 +307,39 @@ is used. In particular, the socket is opened in binary and passive mode, + with SockType seqpacket, and with reasonably large kernel and driver buffers.

+ + + + Peel off a type stream socket from a type seqpacket one + + +

+ Branch off an existing association Assoc + in a socket Socket of type seqpacket + (one-to-may style) into + a new socket NewSocket of type stream + (one-to-one style). +

+

+ The existing association argument Assoc + can be either a + + #sctp_assoc_change{} + + record as returned from e.g + recv/*, + connect/* or + from a listening socket in active mode. Or it can be just + the field assoc_id integer from such a record. +

+
+
-- cgit v1.2.3