From afac3c7136c48d8630bd400c5454e146915e634f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 26 Oct 2015 14:46:54 +0100 Subject: erts: Add {line_delimiter, byte()} option to inet:setopts/2 A new {line_delimiter, byte()} option allows line-oriented TCP-based protocols to use a custom line delimiting character. It is to be used in conjunction with {packet, line}. This option also works with erlang:decode_packet/3 when its first argument is 'line'. --- lib/kernel/doc/src/inet.xml | 5 +++++ lib/kernel/src/inet.erl | 4 +++- lib/kernel/src/inet_int.hrl | 1 + lib/kernel/test/bif_SUITE.erl | 10 ++++++++++ lib/kernel/test/gen_tcp_api_SUITE.erl | 17 ++++++++++++++++- 5 files changed, 35 insertions(+), 2 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index e5d7ce048a..e6d418dc58 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -981,6 +981,11 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp indicated length are accepted and not considered invalid due to internal buffer limitations.

+ {line_delimiter, Char}(TCP/IP sockets) + +

Sets the line delimiting character for line oriented protocols + (line). Default value is $\n.

+
{priority, Priority}

Set the protocol-defined priority for all packets to be sent diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index da7f04089d..855c6377a3 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -671,7 +671,7 @@ stats() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% connect_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, - header, active, packet, packet_size, buffer, mode, deliver, + header, active, packet, packet_size, buffer, mode, deliver, line_delimiter, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw, show_econnreset]. @@ -721,6 +721,8 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) -> {active,N} when is_integer(N), N < 32768, N >= -32768 -> NOpts = lists:keydelete(active, 1, R#connect_opts.opts), con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As); + {line_delimiter,C} when is_integer(C), C >= 0, C =< 255 -> + con_add(line_delimiter, C, R, Opts, As); {Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As); _ -> {error, badarg} end; diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index bfe4c9ec8c..e7c6cf8ae2 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -149,6 +149,7 @@ -define(INET_LOPT_MSGQ_LOWTRMRK, 37). -define(INET_LOPT_NETNS, 38). -define(INET_LOPT_TCP_SHOW_ECONNRESET, 39). +-define(INET_LOPT_LINE_DELIM, 40). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/test/bif_SUITE.erl b/lib/kernel/test/bif_SUITE.erl index c3840f3d16..dd3010567a 100644 --- a/lib/kernel/test/bif_SUITE.erl +++ b/lib/kernel/test/bif_SUITE.erl @@ -33,6 +33,7 @@ spawn_failures/1, run_fun/1, + decode_packet_delim/1, wilderness/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -516,6 +517,15 @@ fetch_proc_vals(Pid) -> {value,{heap_size,HS}} = lists:keysearch(heap_size, 1, PI), ?line {Ls, P, FA, HS}. +decode_packet_delim(doc) -> + ["Test erlang:packet_delim/3 with {line_delimiter,0} option"]; +decode_packet_delim(suite) -> + []; +decode_packet_delim(Config) when is_list(Config) -> + {ok,<<"abc",0>>,<<"efg",0>>} = + erlang:decode_packet(line, <<"abc",0,"efg",0>>, [{line_delimiter, 0}]), + {more, undefined} = erlang:decode_packet(line, <<"abc",0,"efg",0>>, []). + % This testcase should probably be moved somewhere else wilderness(doc) -> ["Test that memory allocation command line options affecting the" diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index a051d504b2..2febb1bd68 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -31,7 +31,7 @@ init_per_testcase/2, end_per_testcase/2, t_connect_timeout/1, t_accept_timeout/1, t_connect_bad/1, - t_recv_timeout/1, t_recv_eof/1, + t_recv_timeout/1, t_recv_eof/1, t_recv_delim/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, t_shutdown_async/1, t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1]). @@ -131,6 +131,21 @@ t_recv_eof(Config) when is_list(Config) -> ?line {error, closed} = gen_tcp:recv(Client, 0), ok. +t_recv_delim(doc) -> "Test using message delimiter $X"; +t_recv_delim(suite) -> []; +t_recv_delim(Config) when is_list(Config) -> + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + Opts = [{active,false},{packet,line},{line_delimiter,$X}], + {ok, Client} = gen_tcp:connect(localhost, Port, Opts), + {ok, A} = gen_tcp:accept(L), + ok = gen_tcp:send(A, "abcXefgX"), + {ok, "abcX"} = gen_tcp:recv(Client, 0, 0), + {ok, "efgX"} = gen_tcp:recv(Client, 0, 0), + ok = gen_tcp:close(Client), + ok = gen_tcp:close(A), + ok. + %%% gen_tcp:shutdown/2 t_shutdown_write(Config) when is_list(Config) -> -- cgit v1.2.3