Compare commits
16 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94ed2172da | ||
|
|
4627cfdff1 | ||
|
|
6515854c29 | ||
|
|
9f08c84c22 | ||
|
|
db107ef77c | ||
|
|
7704629233 | ||
|
|
52781ec84e | ||
|
|
92d16c1e81 | ||
|
|
686f250c6f | ||
|
|
961faf17fa | ||
|
|
03a198125b | ||
|
|
e73e8a3d3f | ||
|
|
2a4618920d | ||
|
|
a92942722d | ||
|
|
2dbf73fdba | ||
|
|
6f09315364 |
18 changed files with 5612 additions and 120 deletions
308
erlang.spec
308
erlang.spec
|
|
@ -17,13 +17,6 @@
|
|||
|
||||
%bcond_without doc
|
||||
|
||||
# No fop for EPEL5, and only for x86/x86_64 in EPEL6, so just disable there too
|
||||
%if 0%{?el5}%{?el6}
|
||||
%global use_prebuilt_docs 1
|
||||
%else
|
||||
%global use_prebuilt_docs 0
|
||||
%endif
|
||||
|
||||
%ifarch %{arm} %{ix86} x86_64 ppc %{power64}
|
||||
%global __with_hipe 1
|
||||
%endif
|
||||
|
|
@ -32,18 +25,16 @@
|
|||
|
||||
Name: erlang
|
||||
Version: %{upstream_ver}
|
||||
Release: %{upstream_rel_for_rpm}.7%{?dist}
|
||||
Release: %{upstream_rel_for_rpm}.18%{?dist}
|
||||
Summary: General-purpose programming language and runtime environment
|
||||
|
||||
Group: Development/Languages
|
||||
License: ERPL
|
||||
URL: http://www.erlang.org
|
||||
Source0: http://www.erlang.org/download/otp_src_%{upstream_ver}%{upstream_rel}-1.tar.gz
|
||||
%if %{use_prebuilt_docs}
|
||||
Source1: http://erlang.org/download/otp_doc_html_%{upstream_ver}%{upstream_rel}-1.tar.gz
|
||||
Source2: http://erlang.org/download/otp_doc_man_%{upstream_ver}%{upstream_rel}-1.tar.gz
|
||||
%if 0%{?el7}%{?fedora}
|
||||
VCS: scm:git:https://github.com/erlang/otp
|
||||
%endif
|
||||
Source4: http://www.erlang.org/download/otp_src_%{upstream_ver}%{upstream_rel}-1.readme
|
||||
Source0: http://www.erlang.org/download/otp_src_%{upstream_ver}%{upstream_rel}-1.tar.gz
|
||||
Source5: epmd.service
|
||||
Source6: epmd.socket
|
||||
Source7: epmd@.service
|
||||
|
|
@ -104,11 +95,56 @@ Patch12: otp-0012-Add-systemd-support-to-epmd.patch
|
|||
# Fedora specific patch
|
||||
# Added systemd notify support to EPMD
|
||||
Patch13: otp-0013-Added-systemd-notify-support-to-EPMD.patch
|
||||
# Fedora specific patch
|
||||
# Install internal hrl files when necessary
|
||||
Patch14: otp-0014-Install-internal-hrl-files-when-necessary.patch
|
||||
# Fedora specific patch
|
||||
# Expose NIF version
|
||||
Patch15: otp-0015-Expose-NIF-version.patch
|
||||
# Fedora specific patch
|
||||
# Split off webtool dependency from tools
|
||||
Patch16: otp-0016-Split-off-webtool-dependency-from-tools.patch
|
||||
# Fedora specific patch
|
||||
# lib/inets/src/ftp/ftp.erl: Check the filenames, usernames,
|
||||
Patch17: otp-0017-lib-inets-src-ftp-ftp.erl-Check-the-filenames-userna.patch
|
||||
# Fedora specific patch
|
||||
# Introduce os:getenv/2
|
||||
Patch18: otp-0018-Introduce-os-getenv-2.patch
|
||||
# Fedora specific patch
|
||||
# Patch removes support for SSLv3 protocol because it is proved
|
||||
Patch19: otp-0019-Patch-removes-support-for-SSLv3-protocol-because-it-.patch
|
||||
# Fedora specific patch
|
||||
# R16B03-1 backport of TLS-1.0 padding check
|
||||
Patch20: otp-0020-R16B03-1-backport-of-TLS-1.0-padding-check.patch
|
||||
# Fedora specific patch
|
||||
# Add patch to crash dump on large distribution
|
||||
Patch21: otp-0021-Add-patch-to-crash-dump-on-large-distribution.patch
|
||||
# Fedora specific patch
|
||||
# kernel: inet6_tcp_dist: reuse inet_tcp_dist code
|
||||
Patch22: otp-0022-kernel-inet6_tcp_dist-reuse-inet_tcp_dist-code.patch
|
||||
# Fedora specific patch
|
||||
# epmd: support IPv6 node registration
|
||||
Patch23: otp-0023-epmd-support-IPv6-node-registration.patch
|
||||
# Fedora specific patch
|
||||
# Remove unused code in error logger handlers
|
||||
Patch24: otp-0024-Remove-unused-code-in-error-logger-handlers.patch
|
||||
# Fedora specific patch
|
||||
# Teach sasl_report to limit crash reports
|
||||
Patch25: otp-0025-Teach-sasl_report-to-limit-crash-reports.patch
|
||||
# Fedora specific patch
|
||||
# Revert "Remove unused code in error logger handlers"
|
||||
Patch26: otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch
|
||||
# Fedora specific patch
|
||||
# Respect -proto_dist switch while connection to EPMD
|
||||
Patch27: otp-0027-Respect-proto_dist-switch-while-connection-to-EPMD.patch
|
||||
# Fedora specific patch
|
||||
# mnesia: Send mnesia_down messages to waiting transactions
|
||||
Patch28: otp-0028-mnesia-Send-mnesia_down-messages-to-waiting-transact.patch
|
||||
# Fedora specific patch
|
||||
# Fix a few javadoc errors
|
||||
Patch29: otp-0029-Fix-a-few-javadoc-errors.patch
|
||||
# end of autogenerated patch tag list
|
||||
|
||||
# BuildRoot not strictly needed since F10, but keep it for spec file robustness
|
||||
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||
|
||||
BuildRequires: lksctp-tools-devel
|
||||
BuildRequires: ncurses-devel
|
||||
BuildRequires: openssl-devel
|
||||
|
|
@ -116,8 +152,7 @@ BuildRequires: zlib-devel
|
|||
BuildRequires: flex
|
||||
BuildRequires: m4
|
||||
%if %{with doc}
|
||||
%if %{use_prebuilt_docs}
|
||||
%else
|
||||
# BEWARE. No fop for EPEL5, and only for x86/x86_64 in EPEL6, so we cannot regenerate docs here
|
||||
BuildRequires: fop
|
||||
BuildRequires: libxslt
|
||||
|
||||
|
|
@ -126,14 +161,11 @@ BuildRequires: libxslt
|
|||
BuildRequires: erlang
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?el6}%{?fedora}
|
||||
BuildRequires: emacs
|
||||
BuildRequires: xemacs
|
||||
BuildRequires: emacs-el
|
||||
BuildRequires: xemacs-packages-extra-el
|
||||
%endif
|
||||
|
||||
%if 0%{?el7}%{?fedora}
|
||||
# for <systemd/sd-daemon.h>
|
||||
|
|
@ -144,63 +176,64 @@ Requires(postun):systemd
|
|||
Requires: systemd
|
||||
%endif
|
||||
|
||||
Requires: erlang-appmon%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-asn1%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-common_test%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-compiler%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosEvent%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosEventDomain%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosFileTransfer%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosNotification%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosProperty%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosTime%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-cosTransactions%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-crypto%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-debugger%{?_isa} = %{version}-%{release}
|
||||
BuildRequires: erlang-rpm-macros
|
||||
|
||||
Requires: erlang-dialyzer%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-diameter%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-edoc%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-eldap%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-erl_docgen%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-erl_interface%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-erts%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-et%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-eunit%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-examples%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-gs%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-hipe%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-ic%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-inets%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-jinterface%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-kernel%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-megaco%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-mnesia%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-observer%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-odbc%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-orber%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-os_mon%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-otp_mibs%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-parsetools%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-percept%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-pman%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-public_key%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-reltool%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-runtime_tools%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-sasl%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-snmp%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-ssh%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-ssl%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-stdlib%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-syntax_tools%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-test_server%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-toolbar%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-tools%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-tv%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-typer%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-webtool%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-wx%{?_isa} = %{version}-%{release}
|
||||
Requires: erlang-xmerl%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-appmon%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-asn1%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-common_test%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-compiler%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosEvent%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosEventDomain%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosFileTransfer%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosNotification%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosProperty%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosTime%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-cosTransactions%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-crypto%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-debugger%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-dialyzer%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-diameter%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-edoc%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-eldap%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-erl_docgen%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-erl_interface%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-erts%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-et%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-eunit%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-examples%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-gs%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-hipe%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-ic%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-inets%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-jinterface%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-kernel%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-megaco%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-mnesia%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-observer%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-odbc%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-orber%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-os_mon%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-otp_mibs%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-parsetools%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-percept%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-pman%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-public_key%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-reltool%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-runtime_tools%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-sasl%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-snmp%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-ssh%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-ssl%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-stdlib%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-syntax_tools%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-test_server%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-toolbar%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-tools%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-tv%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-typer%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-webtool%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-wx%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-xmerl%{?_isa} = %{version}-%{release}
|
||||
Obsoletes: erlang-docbuilder
|
||||
Obsoletes: erlang-inviso
|
||||
|
||||
|
|
@ -405,15 +438,15 @@ Requires: %{name}-syntax_tools%{?_isa} = %{version}-%{release}
|
|||
%description diameter
|
||||
Diameter (RFC 3588) library
|
||||
|
||||
%if %{with doc}
|
||||
%package doc
|
||||
Summary: Erlang documentation
|
||||
Group: Development/Languages
|
||||
%if 0%{?el6}%{?el7}%{?fedora}
|
||||
BuildArch: noarch
|
||||
%endif
|
||||
|
||||
%description doc
|
||||
Documentation for Erlang.
|
||||
%endif
|
||||
|
||||
%package edoc
|
||||
Summary: A utility used to generate documentation out of tags in source files
|
||||
|
|
@ -462,10 +495,16 @@ Low level interface to C.
|
|||
%package erts
|
||||
Summary: Functionality necessary to run the Erlang System itself
|
||||
Group: Development/Languages
|
||||
# epmd user, epmd group
|
||||
Requires(pre): shadow-utils
|
||||
Requires: %{name}-kernel%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-stdlib%{?_isa} = %{version}-%{release}
|
||||
# This library is dlopened so it can't be picked up automatically by the RPM
|
||||
# dependency checker
|
||||
Requires: lksctp-tools
|
||||
# See erts/emulator/beam/erl_driver.h or call erlang:system_info(driver_version).
|
||||
Provides: erlang(erl_drv_version) = 2.2
|
||||
# See erts/emulator/beam/erl_nif.h or call erlang:system_info(nif_version).
|
||||
Provides: erlang(erl_nif_version) = 2.4
|
||||
|
||||
%description erts
|
||||
|
|
@ -558,7 +597,7 @@ Group: Development/Languages
|
|||
Requires: %{name}-erts%{?_isa} = %{version}-%{release}
|
||||
# FIXME see erlang-ic also
|
||||
#Requires: jpackage-utils
|
||||
%if 0%{?fedora}%{?el7}
|
||||
%if 0%{?el7}%{?fedora}
|
||||
BuildRequires: java-devel
|
||||
%else
|
||||
%ifarch %{ix86} x86_64
|
||||
|
|
@ -788,7 +827,6 @@ Secure Shell application with sftp and ssh support.
|
|||
%package ssl
|
||||
Summary: Secure Socket Layer support
|
||||
Group: Development/Languages
|
||||
#Requires: %{name}-asn1%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-crypto%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-erts%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-kernel%{?_isa} = %{version}-%{release}
|
||||
|
|
@ -828,7 +866,6 @@ Requires: %{name}-inets%{?_isa} = %{version}-%{release}
|
|||
Requires: %{name}-kernel%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-observer%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-runtime_tools%{?_isa} = %{version}-%{release}
|
||||
#Requires: %{name}-sasl%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-stdlib%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-tools%{?_isa} = %{version}-%{release}
|
||||
|
||||
|
|
@ -855,7 +892,12 @@ Requires: %{name}-inets%{?_isa} = %{version}-%{release}
|
|||
Requires: %{name}-kernel%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-runtime_tools%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-stdlib%{?_isa} = %{version}-%{release}
|
||||
Requires: %{name}-webtool%{?_isa} = %{version}-%{release}
|
||||
# This is a weak dependency triggered by the "cover_web" application.
|
||||
# Unfortunately Recommends/Suggests tags are supported only in Fedora 21+ and
|
||||
# RHEL 8+ (eventually)
|
||||
%if 0%{?fedora} >= 21 || 0%{?rhel} >= 8
|
||||
Suggests: %{name}-webtool%{?_isa} = %{version}-%{release}
|
||||
%endif
|
||||
Provides: emacs-common-erlang = %{version}-%{release}
|
||||
|
||||
%description tools
|
||||
|
|
@ -922,7 +964,6 @@ Requires: %{name}-stdlib%{?_isa} = %{version}-%{release}
|
|||
%description xmerl
|
||||
Provides support for XML 1.0.
|
||||
|
||||
%if 0%{?el6}%{?fedora}
|
||||
%package -n emacs-erlang
|
||||
Summary: Compiled elisp files for erlang-mode under GNU Emacs
|
||||
Requires: emacs-common-erlang = %{version}-%{release}
|
||||
|
|
@ -960,7 +1001,6 @@ BuildArch: noarch
|
|||
|
||||
%description -n xemacs-erlang-el
|
||||
Erlang mode for XEmacs (source lisp files).
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%setup -q -n otp_src_%{upstream_ver}%{upstream_rel}-1
|
||||
|
|
@ -983,6 +1023,22 @@ Erlang mode for XEmacs (source lisp files).
|
|||
%patch11 -p1 -b .Add_systemd_option_to_empd_Check_for_include_system
|
||||
%patch12 -p1 -b .Add_systemd_support_to_epmd
|
||||
%patch13 -p1 -b .Added_systemd_notify_support_to_EPMD
|
||||
%patch14 -p1 -b .Install_internal_hrl_files_when_necessary
|
||||
%patch15 -p1 -b .Expose_NIF_version
|
||||
%patch16 -p1 -b .Split_off_webtool_dependency_from_tools
|
||||
%patch17 -p1 -b .lib_inets_src_ftp_ftp_erl_Check_the_filenames_userna
|
||||
%patch18 -p1 -b .Introduce_os_getenv_2
|
||||
%patch19 -p1 -b .Patch_removes_support_for_SSLv3_protocol_because_it_
|
||||
%patch20 -p1 -b .R16B03_1_backport_of_TLS_1_0_padding_check
|
||||
%patch21 -p1 -b .Add_patch_to_crash_dump_on_large_distribution
|
||||
%patch22 -p1 -b .kernel_inet6_tcp_dist_reuse_inet_tcp_dist_code
|
||||
%patch23 -p1 -b .epmd_support_IPv6_node_registration
|
||||
%patch24 -p1 -b .Remove_unused_code_in_error_logger_handlers
|
||||
%patch25 -p1 -b .Teach_sasl_report_to_limit_crash_reports
|
||||
%patch26 -p1 -b .Revert_Remove_unused_code_in_error_logger_handlers
|
||||
%patch27 -p1 -b .Respect_proto_dist_switch_while_connection_to_EPMD
|
||||
%patch28 -p1 -b .mnesia_Send_mnesia_down_messages_to_waiting_transact
|
||||
%patch29 -p1 -b .Fix_a_few_javadoc_errors
|
||||
# end of autogenerated prep patch list
|
||||
|
||||
# FIXME we should come up with a better solution
|
||||
|
|
@ -1005,9 +1061,9 @@ rm -f lib/ssl/examples/certs/etc/erlangCA/index.txt.old
|
|||
|
||||
%build
|
||||
%ifarch sparcv9 sparc64
|
||||
CFLAGS="$RPM_OPT_FLAGS -mcpu=ultrasparc -fno-strict-aliasing" %configure --enable-shared-zlib --enable-sctp %{?__with_hipe:--enable-hipe}
|
||||
CFLAGS="$RPM_OPT_FLAGS -mcpu=ultrasparc -fno-strict-aliasing" %configure --enable-shared-zlib --enable-sctp --enable-systemd %{?__with_hipe:--enable-hipe}
|
||||
%else
|
||||
CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" %configure --enable-shared-zlib --enable-sctp %{?__with_hipe:--enable-hipe}
|
||||
CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" %configure --enable-shared-zlib --enable-sctp --enable-systemd %{?__with_hipe:--enable-hipe}
|
||||
%endif
|
||||
|
||||
# Remove pre-built BEAM files
|
||||
|
|
@ -1016,7 +1072,6 @@ make clean
|
|||
# GNU Emacs/XEmacs related stuff
|
||||
erlang_tools_vsn="$(sed -n 's/TOOLS_VSN = //p' lib/tools/vsn.mk)"
|
||||
|
||||
%if 0%{?el6}%{?fedora}
|
||||
# GNU Emacs related stuff
|
||||
cat > emacs-erlang-init.el << EOF
|
||||
(setq load-path (cons "%{_emacs_sitelispdir}/erlang" load-path))
|
||||
|
|
@ -1043,12 +1098,10 @@ rm -f xemacs-erlang/erlang-flymake.el
|
|||
pushd xemacs-erlang
|
||||
%{_xemacs_bytecompile} *.el
|
||||
popd
|
||||
%endif
|
||||
|
||||
make
|
||||
|
||||
%if %{with doc}
|
||||
%if %{use_prebuilt_docs}
|
||||
%else
|
||||
# should use FOP_OPTS after #832323 is resolved
|
||||
%ifnarch ppc %{power64}
|
||||
export BASE_OPTIONS=-Xmx1024m
|
||||
|
|
@ -1057,13 +1110,9 @@ export BASE_OPTIONS=-Xmx1536m
|
|||
%endif
|
||||
make docs
|
||||
%endif
|
||||
%endif
|
||||
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%if 0%{?el6}%{?fedora}
|
||||
# GNU Emacs/XEmacs related stuff
|
||||
erlang_tools_vsn="$(sed -n 's/TOOLS_VSN = //p' lib/tools/vsn.mk)"
|
||||
|
||||
|
|
@ -1089,25 +1138,12 @@ for f in lib/tools/emacs/{README,*.el}; do
|
|||
done
|
||||
rm -f "$RPM_BUILD_ROOT%{_xemacs_sitelispdir}/erlang/erlang-flymake.el"
|
||||
install -m 0644 xemacs-erlang/*.elc "$RPM_BUILD_ROOT%{_xemacs_sitelispdir}/erlang/"
|
||||
%endif
|
||||
|
||||
make DESTDIR=$RPM_BUILD_ROOT install
|
||||
|
||||
%if %{with doc}
|
||||
%if %{use_prebuilt_docs}
|
||||
# extract prebuilt docs and man-pages
|
||||
tar xf %{SOURCE1} -C $RPM_BUILD_ROOT%{_libdir}/erlang
|
||||
tar xf %{SOURCE2} -C $RPM_BUILD_ROOT%{_libdir}/erlang
|
||||
# rm Win32-specific functionality
|
||||
rm -f $RPM_BUILD_ROOT%{_libdir}/erlang/man/man3/nteventlog.*
|
||||
# rm VxWorks specific
|
||||
rm -f $RPM_BUILD_ROOT%{_libdir}/erlang/man/man3/erl_set_memory_block.*
|
||||
# rm unneeded files
|
||||
rm -f $RPM_BUILD_ROOT%{_libdir}/erlang/erts-*/info
|
||||
rm -f $RPM_BUILD_ROOT%{_libdir}/erlang/lib/*-*/info
|
||||
%else
|
||||
env ERL_LIBS="$RPM_BUILD_ROOT%{_libdir}/erlang/lib" make DESTDIR=$RPM_BUILD_ROOT install-docs
|
||||
%endif
|
||||
%endif
|
||||
|
||||
# Do not install info files - they are almost empty and useless
|
||||
find $RPM_BUILD_ROOT%{_libdir}/erlang -type f -name info -exec rm -f {} \;
|
||||
|
|
@ -1194,10 +1230,6 @@ useradd -r -g epmd -d /tmp -s /sbin/nologin \
|
|||
-c "Erlang Port Mapper Daemon" epmd 2>/dev/null || :
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%files
|
||||
%if %{with doc}
|
||||
%dir %{_docdir}/%{n_uvr}/
|
||||
|
|
@ -1410,8 +1442,8 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%{_libdir}/erlang/man/man4/diameter_dict.*
|
||||
%endif
|
||||
|
||||
%files doc
|
||||
%if %{with doc}
|
||||
%files doc
|
||||
%doc %{_docdir}/%{n_uvr}/doc
|
||||
%doc %{_docdir}/%{n_uvr}/erts-*/
|
||||
%doc %{_docdir}/%{n_uvr}/lib/
|
||||
|
|
@ -1436,7 +1468,9 @@ rm -rf $RPM_BUILD_ROOT
|
|||
|
||||
%files erl_docgen
|
||||
%{_libdir}/erlang/lib/erl_docgen-*/
|
||||
%if %{with doc}
|
||||
%{_libdir}/erlang/man/man6/erl_docgen.*
|
||||
%endif
|
||||
|
||||
%files erl_interface
|
||||
%{_libdir}/erlang/lib/erl_interface-*/
|
||||
|
|
@ -1455,7 +1489,9 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%endif
|
||||
|
||||
%files erts
|
||||
# TODO these directories should be packaged separately
|
||||
# TODO
|
||||
# In order to have a parallel-installable Erlang packages these directories
|
||||
# should be packaged separately
|
||||
%dir %{_libdir}/erlang/
|
||||
%dir %{_libdir}/erlang/bin/
|
||||
%dir %{_libdir}/erlang/lib/
|
||||
|
|
@ -1556,6 +1592,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%dir %{_libdir}/erlang/lib/eunit-*/
|
||||
%{_libdir}/erlang/lib/eunit-*/ebin
|
||||
%{_libdir}/erlang/lib/eunit-*/include
|
||||
%{_libdir}/erlang/lib/eunit-*/src
|
||||
%if %{with doc}
|
||||
%{_libdir}/erlang/man/man3/eunit.*
|
||||
%{_libdir}/erlang/man/man3/eunit_surefire.*
|
||||
|
|
@ -2313,7 +2350,6 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%{_libdir}/erlang/man/man3/xmerl_xsd.*
|
||||
%endif
|
||||
|
||||
%if 0%{?el6}%{?fedora}
|
||||
%files -n emacs-erlang
|
||||
%dir %{_emacs_sitelispdir}/erlang
|
||||
%doc %{_emacs_sitelispdir}/erlang/README
|
||||
|
|
@ -2331,10 +2367,48 @@ rm -rf $RPM_BUILD_ROOT
|
|||
|
||||
%files -n xemacs-erlang-el
|
||||
%{_xemacs_sitelispdir}/erlang/*.el
|
||||
%endif
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Nov 9 2016 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.18
|
||||
- Respect -proto_dist switch while connecting to EPMD
|
||||
- Cherry-picked fix for OTP-13423. Mnesia transactions could hang while waiting
|
||||
on a response from a node who had stopped.
|
||||
- Fix for doc generation with OpenJDK 1.8.0
|
||||
|
||||
* Thu Apr 7 2016 John Eckersberg <eck@redhat.com> - R16B-03.17
|
||||
- Revert "Enable error_logger depth fine tuning" (rhbz#1324922)
|
||||
|
||||
* Sun Feb 28 2016 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.16
|
||||
- Fixed issue with nodes registration over IPv6
|
||||
|
||||
* Fri Feb 19 2016 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.15
|
||||
- Add missing dependency
|
||||
|
||||
* Wed Jan 27 2016 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.14
|
||||
- Enable error_logger depth fine tuning
|
||||
|
||||
* Sun Jan 17 2016 John Eckersberg <eck@redhat.com> - R16B-03.13
|
||||
- Fix inet_dist_listen_{min,max} for ipv6 (rhbz#1299251)
|
||||
- Add patch for epmd ipv6 support (rhbz#1299253)
|
||||
|
||||
* Mon Jan 11 2016 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.12
|
||||
- Enable crash dump creation during a large distrubution error
|
||||
|
||||
* Fri Aug 7 2015 John Eckersberg <eck@redhat.com> - R16B-03.11
|
||||
- Add patch for CVE-2015-2774 - TLS-1.0 POODLE vulnerability (rhbz#1206712)
|
||||
|
||||
* Mon Dec 01 2014 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.10
|
||||
- Disable SSLv3 (see rhbz #1169375)
|
||||
- Backport useful os:getenv/2 from master (see https://github.com/erlang/otp/pull/535 )
|
||||
|
||||
* Mon Nov 17 2014 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.9
|
||||
- Fixed CVE-2014-1693 (backported fix from ver. 17.x.x, see patch no. 17)
|
||||
|
||||
* Tue Nov 11 2014 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.8
|
||||
- Trimmed dependency chain
|
||||
- Cleaned up spec-file
|
||||
|
||||
* Wed Jun 11 2014 Peter Lemenkov <lemenkov@gmail.com> - R16B-03.7
|
||||
- Added missing template for epmd@.socket
|
||||
|
||||
|
|
|
|||
97
otp-0014-Install-internal-hrl-files-when-necessary.patch
Normal file
97
otp-0014-Install-internal-hrl-files-when-necessary.patch
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Tue, 26 Aug 2014 13:53:49 +0400
|
||||
Subject: [PATCH] Install internal hrl files when necessary
|
||||
|
||||
Sometimes we install *.erl files. Some these files include a private
|
||||
*.hrl files, so in order to make these *.erl files usable we have to
|
||||
install these private includes as well.
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
Conflicts:
|
||||
lib/eunit/src/Makefile
|
||||
lib/percept/src/Makefile
|
||||
lib/test_server/src/Makefile
|
||||
|
||||
diff --git a/lib/debugger/src/Makefile b/lib/debugger/src/Makefile
|
||||
index 5a6f298..b40ef23 100644
|
||||
--- a/lib/debugger/src/Makefile
|
||||
+++ b/lib/debugger/src/Makefile
|
||||
@@ -77,7 +77,7 @@ MODULES= \
|
||||
|
||||
HRL_FILES=
|
||||
|
||||
-INTERNAL_HRL_FILES= dbg_ieval.hrl
|
||||
+INTERNAL_HRL_FILES= dbg_ieval.hrl dbg_wx_filedialog_win.hrl
|
||||
|
||||
ERL_FILES= $(MODULES:%=%.erl)
|
||||
|
||||
diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile
|
||||
index a5e147d..8483e28 100644
|
||||
--- a/lib/eunit/src/Makefile
|
||||
+++ b/lib/eunit/src/Makefile
|
||||
@@ -46,6 +46,8 @@ SOURCES= \
|
||||
|
||||
INCLUDE_FILES = eunit.hrl
|
||||
|
||||
+INTERNAL_HRL_FILES= eunit_internal.hrl
|
||||
+
|
||||
PARSE_TRANSFORM_BIN = $(PARSE_TRANSFORM:%.erl=$(EBIN)/%.$(EMULATOR))
|
||||
|
||||
TARGET_FILES= $(SOURCES:%.erl=$(EBIN)/%.$(EMULATOR))
|
||||
@@ -117,6 +119,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
|
||||
release_spec: opt
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
|
||||
$(INSTALL_DATA) $(PARSE_TRANSFORM_BIN) $(OBJECTS) "$(RELSYSDIR)/ebin"
|
||||
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
|
||||
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/include"
|
||||
$(INSTALL_DATA) $(INCLUDE_DELIVERABLES) "$(RELSYSDIR)/include"
|
||||
|
||||
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
|
||||
index dbda2a2..3e1792f 100644
|
||||
--- a/lib/kernel/src/Makefile
|
||||
+++ b/lib/kernel/src/Makefile
|
||||
@@ -122,6 +122,7 @@ HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl \
|
||||
../include/net_address.hrl
|
||||
|
||||
INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \
|
||||
+ erl_epmd.hrl hipe_ext_format.hrl \
|
||||
inet_dns.hrl inet_res.hrl \
|
||||
inet_boot.hrl inet_config.hrl inet_int.hrl \
|
||||
inet_dns_record_adts.hrl
|
||||
diff --git a/lib/percept/src/Makefile b/lib/percept/src/Makefile
|
||||
index e501539..5902da3 100644
|
||||
--- a/lib/percept/src/Makefile
|
||||
+++ b/lib/percept/src/Makefile
|
||||
@@ -50,6 +50,8 @@ MODULES= \
|
||||
|
||||
#HRL_FILES= ../include/
|
||||
|
||||
+INTERNAL_HRL_FILES= egd.hrl percept.hrl
|
||||
+
|
||||
ERL_FILES= $(MODULES:%=%.erl)
|
||||
|
||||
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
|
||||
@@ -93,6 +95,8 @@ docs:
|
||||
include $(ERL_TOP)/make/otp_release_targets.mk
|
||||
|
||||
release_spec: opt
|
||||
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
|
||||
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
|
||||
# $(INSTALL_DIR) "$(RELSYSDIR)/include"
|
||||
# $(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
|
||||
diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile
|
||||
index bcb1bc3..deb7caf 100644
|
||||
--- a/lib/test_server/src/Makefile
|
||||
+++ b/lib/test_server/src/Makefile
|
||||
@@ -123,7 +123,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
|
||||
|
||||
release_spec: opt
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/src"
|
||||
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) "$(RELSYSDIR)/src"
|
||||
+ $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(TS_HRL_FILES) "$(RELSYSDIR)/src"
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/include"
|
||||
$(INSTALL_DATA) $(HRL_FILES) "$(RELSYSDIR)/include"
|
||||
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
|
||||
90
otp-0015-Expose-NIF-version.patch
Normal file
90
otp-0015-Expose-NIF-version.patch
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Sun, 2 Nov 2014 19:49:55 +0300
|
||||
Subject: [PATCH] Expose NIF version
|
||||
|
||||
This patch allows checking for NIF API version in a way similar to
|
||||
driver version. E.g. by calling erlang:system_info(nif_version).
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
Conflicts:
|
||||
erts/emulator/test/driver_SUITE.erl
|
||||
|
||||
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
|
||||
index e3ef48a..b9d7230 100644
|
||||
--- a/erts/doc/src/erlang.xml
|
||||
+++ b/erts/doc/src/erlang.xml
|
||||
@@ -5903,6 +5903,11 @@ ok
|
||||
<seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and
|
||||
<seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p>
|
||||
</item>
|
||||
+ <tag><c>nif_version</c></tag>
|
||||
+ <item>
|
||||
+ <p>Returns a string containing the erlang NIF version
|
||||
+ used by the runtime system. It will be on the form "<major ver>.<minor ver>".</p>
|
||||
+ </item>
|
||||
<tag><marker id="system_info_otp_release"><c>otp_release</c></marker></tag>
|
||||
<item>
|
||||
<p>Returns a string containing the OTP release number.</p>
|
||||
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
|
||||
index d7f1e2d..7a7f23e 100755
|
||||
--- a/erts/emulator/beam/erl_bif_info.c
|
||||
+++ b/erts/emulator/beam/erl_bif_info.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "erl_process.h"
|
||||
#include "error.h"
|
||||
#include "erl_driver.h"
|
||||
+#include "erl_nif.h"
|
||||
#include "bif.h"
|
||||
#include "big.h"
|
||||
#include "erl_version.h"
|
||||
@@ -2428,6 +2429,13 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
|
||||
ERL_DRV_EXTENDED_MINOR_VERSION);
|
||||
hp = HAlloc(BIF_P, 2*n);
|
||||
BIF_RET(buf_to_intlist(&hp, buf, n, NIL));
|
||||
+ } else if (ERTS_IS_ATOM_STR("nif_version", BIF_ARG_1)) {
|
||||
+ char buf[42];
|
||||
+ int n = erts_snprintf(buf, 42, "%d.%d",
|
||||
+ ERL_NIF_MAJOR_VERSION,
|
||||
+ ERL_NIF_MINOR_VERSION);
|
||||
+ hp = HAlloc(BIF_P, 2*n);
|
||||
+ BIF_RET(buf_to_intlist(&hp, buf, n, NIL));
|
||||
} else if (ERTS_IS_ATOM_STR("smp_support", BIF_ARG_1)) {
|
||||
#ifdef ERTS_SMP
|
||||
BIF_RET(am_true);
|
||||
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
|
||||
index 2919265..c0f14ad 100644
|
||||
--- a/erts/preloaded/src/erlang.erl
|
||||
+++ b/erts/preloaded/src/erlang.erl
|
||||
@@ -2124,6 +2124,7 @@ tuple_to_list(_Tuple) ->
|
||||
(modified_timing_level) -> integer() | undefined;
|
||||
(multi_scheduling) -> disabled | blocked | enabled;
|
||||
(multi_scheduling_blockers) -> [PID :: pid()];
|
||||
+ (nif_version) -> string();
|
||||
(otp_release) -> string();
|
||||
(port_count) -> non_neg_integer();
|
||||
(port_limit) -> pos_integer();
|
||||
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
|
||||
index 1d4b878..64f1b82 100644
|
||||
--- a/lib/runtime_tools/src/system_information.erl
|
||||
+++ b/lib/runtime_tools/src/system_information.erl
|
||||
@@ -344,6 +344,7 @@ erlang_system_info() ->
|
||||
logical_processors_online,
|
||||
logical_processors_available,
|
||||
driver_version,
|
||||
+ nif_version,
|
||||
emu_args,
|
||||
ethread_info,
|
||||
beam_jump_table,
|
||||
diff --git a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
|
||||
index 0900ead..9ded5a1 100644
|
||||
--- a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
|
||||
+++ b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
|
||||
@@ -9720,6 +9720,7 @@
|
||||
{logical_processors_online,4},
|
||||
{logical_processors_available,4},
|
||||
{driver_version,"2.1"},
|
||||
+ {nif_version,"1.1"},
|
||||
{taints,[]}]},
|
||||
{erts_compile_info,
|
||||
[{ldflags,[]},
|
||||
40
otp-0016-Split-off-webtool-dependency-from-tools.patch
Normal file
40
otp-0016-Split-off-webtool-dependency-from-tools.patch
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Sat, 8 Nov 2014 22:54:57 +0300
|
||||
Subject: [PATCH] Split off webtool dependency from tools
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/lib/tools/src/cover_web.erl b/lib/tools/src/cover_web.erl
|
||||
index 69f2f3b..9085300 100644
|
||||
--- a/lib/tools/src/cover_web.erl
|
||||
+++ b/lib/tools/src/cover_web.erl
|
||||
@@ -50,14 +50,25 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%% Start webtool and webcover from erlang shell
|
||||
start() ->
|
||||
- webtool:start(),
|
||||
- webtool:start_tools([],"app=webcover"),
|
||||
+ try
|
||||
+ % Disable automatic dependency picking up
|
||||
+ erlang:apply(webtool, start, []),
|
||||
+ erlang:apply(webtool, start_tools, [[],"app=webcover"])
|
||||
+ catch
|
||||
+ error:undef -> error_logger:error_msg("No erlang-webtool found.~nPlease install erlang-webtool package first.~n")
|
||||
+ end,
|
||||
ok.
|
||||
|
||||
%% Stop webtool and webcover from erlang shell
|
||||
stop() ->
|
||||
- webtool:stop_tools([],"app=webcover"),
|
||||
- webtool:stop().
|
||||
+ try
|
||||
+ % Disable automatic dependency picking up
|
||||
+ erlang:apply(webtool, stop_tools, [[],"app=webcover"]),
|
||||
+ erlang:apply(webtool, stop, [])
|
||||
+ catch
|
||||
+ error:undef -> error_logger:error_msg("No erlang-webtool found.~nPlease install erlang-webtool package first.~n")
|
||||
+ end,
|
||||
+ ok.
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,430 @@
|
|||
From: Sergei Golovan <sgolovan@gmail.com>
|
||||
Date: Sun, 9 Feb 2014 23:06:25 +0400
|
||||
Subject: [PATCH] lib/inets/src/ftp/ftp.erl: Check the filenames, usernames,
|
||||
passwords etc. for <CR> and <LF> in them and return error if these
|
||||
offending chars are found. See
|
||||
http://erlang.org/pipermail/erlang-bugs/2014-January/003998.html for
|
||||
details. lib/inets/test/ftp_suite_lib.erl: Added checks for <CR><LF> in file
|
||||
and directory names.
|
||||
|
||||
|
||||
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
|
||||
index 520db1b..5674599 100644
|
||||
--- a/lib/inets/src/ftp/ftp.erl
|
||||
+++ b/lib/inets/src/ftp/ftp.erl
|
||||
@@ -192,7 +192,12 @@ do_open(Pid, OpenOptions, TLSOpts) ->
|
||||
'ok' | {'error', Reason :: 'euser' | common_reason()}.
|
||||
|
||||
user(Pid, User, Pass) ->
|
||||
- call(Pid, {user, User, Pass}, atom).
|
||||
+ case {is_name_sane(User), is_name_sane(Pass)} of
|
||||
+ {true, true} ->
|
||||
+ call(Pid, {user, User, Pass}, atom);
|
||||
+ _ ->
|
||||
+ {error, euser}
|
||||
+ end.
|
||||
|
||||
-spec user(Pid :: pid(),
|
||||
User :: string(),
|
||||
@@ -201,7 +206,12 @@ user(Pid, User, Pass) ->
|
||||
'ok' | {'error', Reason :: 'euser' | common_reason()}.
|
||||
|
||||
user(Pid, User, Pass, Acc) ->
|
||||
- call(Pid, {user, User, Pass, Acc}, atom).
|
||||
+ case {is_name_sane(User), is_name_sane(Pass), is_name_sane(Acc)} of
|
||||
+ {true, true, true} ->
|
||||
+ call(Pid, {user, User, Pass, Acc}, atom);
|
||||
+ _ ->
|
||||
+ {error, euser}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -216,7 +226,12 @@ user(Pid, User, Pass, Acc) ->
|
||||
'ok' | {'error', Reason :: 'eacct' | common_reason()}.
|
||||
|
||||
account(Pid, Acc) ->
|
||||
- call(Pid, {account, Acc}, atom).
|
||||
+ case is_name_sane(Acc) of
|
||||
+ true ->
|
||||
+ call(Pid, {account, Acc}, atom);
|
||||
+ _ ->
|
||||
+ {error, eacct}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -262,7 +277,12 @@ lpwd(Pid) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
cd(Pid, Dir) ->
|
||||
- call(Pid, {cd, Dir}, atom).
|
||||
+ case is_name_sane(Dir) of
|
||||
+ true ->
|
||||
+ call(Pid, {cd, Dir}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -305,7 +325,12 @@ ls(Pid) ->
|
||||
{'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
ls(Pid, Dir) ->
|
||||
- call(Pid, {dir, long, Dir}, string).
|
||||
+ case is_name_sane(Dir) of
|
||||
+ true ->
|
||||
+ call(Pid, {dir, long, Dir}, string);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -333,7 +358,12 @@ nlist(Pid) ->
|
||||
{'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
nlist(Pid, Dir) ->
|
||||
- call(Pid, {dir, short, Dir}, string).
|
||||
+ case is_name_sane(Dir) of
|
||||
+ true ->
|
||||
+ call(Pid, {dir, short, Dir}, string);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -349,7 +379,12 @@ nlist(Pid, Dir) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
rename(Pid, Old, New) ->
|
||||
- call(Pid, {rename, Old, New}, string).
|
||||
+ case {is_name_sane(Old), is_name_sane(New)} of
|
||||
+ {true, true} ->
|
||||
+ call(Pid, {rename, Old, New}, string);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -365,7 +400,12 @@ rename(Pid, Old, New) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
delete(Pid, File) ->
|
||||
- call(Pid, {delete, File}, string).
|
||||
+ case is_name_sane(File) of
|
||||
+ true ->
|
||||
+ call(Pid, {delete, File}, string);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -380,7 +420,12 @@ delete(Pid, File) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
mkdir(Pid, Dir) ->
|
||||
- call(Pid, {mkdir, Dir}, atom).
|
||||
+ case is_name_sane(Dir) of
|
||||
+ true ->
|
||||
+ call(Pid, {mkdir, Dir}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -395,7 +440,12 @@ mkdir(Pid, Dir) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
rmdir(Pid, Dir) ->
|
||||
- call(Pid, {rmdir, Dir}, atom).
|
||||
+ case is_name_sane(Dir) of
|
||||
+ true ->
|
||||
+ call(Pid, {rmdir, Dir}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -437,7 +487,12 @@ recv(Pid, RemotFileName) ->
|
||||
'ok' | {'error', Reason :: term()}.
|
||||
|
||||
recv(Pid, RemotFileName, LocalFileName) ->
|
||||
- call(Pid, {recv, RemotFileName, LocalFileName}, atom).
|
||||
+ case is_name_sane(RemotFileName) of
|
||||
+ true ->
|
||||
+ call(Pid, {recv, RemotFileName, LocalFileName}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -456,7 +511,12 @@ recv(Pid, RemotFileName, LocalFileName) ->
|
||||
{'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
recv_bin(Pid, RemoteFile) ->
|
||||
- call(Pid, {recv_bin, RemoteFile}, bin).
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {recv_bin, RemoteFile}, bin);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -473,7 +533,12 @@ recv_bin(Pid, RemoteFile) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
recv_chunk_start(Pid, RemoteFile) ->
|
||||
- call(Pid, {recv_chunk_start, RemoteFile}, atom).
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {recv_chunk_start, RemoteFile}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -521,7 +586,12 @@ send(Pid, LocalFileName) ->
|
||||
shortage_reason()}.
|
||||
|
||||
send(Pid, LocalFileName, RemotFileName) ->
|
||||
- call(Pid, {send, LocalFileName, RemotFileName}, atom).
|
||||
+ case is_name_sane(RemotFileName) of
|
||||
+ true ->
|
||||
+ call(Pid, {send, LocalFileName, RemotFileName}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -541,7 +611,12 @@ send(Pid, LocalFileName, RemotFileName) ->
|
||||
shortage_reason()}.
|
||||
|
||||
send_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
|
||||
- call(Pid, {send_bin, Bin, RemoteFile}, atom);
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {send_bin, Bin, RemoteFile}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end;
|
||||
send_bin(_Pid, _Bin, _RemoteFile) ->
|
||||
{error, enotbinary}.
|
||||
|
||||
@@ -559,7 +634,12 @@ send_bin(_Pid, _Bin, _RemoteFile) ->
|
||||
'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
|
||||
|
||||
send_chunk_start(Pid, RemoteFile) ->
|
||||
- call(Pid, {send_chunk_start, RemoteFile}, atom).
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {send_chunk_start, RemoteFile}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -575,7 +655,12 @@ send_chunk_start(Pid, RemoteFile) ->
|
||||
'ok' | {'error', Reason :: term()}.
|
||||
|
||||
append_chunk_start(Pid, RemoteFile) ->
|
||||
- call(Pid, {append_chunk_start, RemoteFile}, atom).
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {append_chunk_start, RemoteFile}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -683,7 +768,12 @@ append(Pid, LocalFileName) ->
|
||||
'ok' | {'error', Reason :: term()}.
|
||||
|
||||
append(Pid, LocalFileName, RemotFileName) ->
|
||||
- call(Pid, {append, LocalFileName, RemotFileName}, atom).
|
||||
+ case is_name_sane(RemotFileName) of
|
||||
+ true ->
|
||||
+ call(Pid, {append, LocalFileName, RemotFileName}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end.
|
||||
|
||||
|
||||
%%--------------------------------------------------------------------------
|
||||
@@ -705,7 +795,12 @@ append(Pid, LocalFileName, RemotFileName) ->
|
||||
shortage_reason()}.
|
||||
|
||||
append_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
|
||||
- call(Pid, {append_bin, Bin, RemoteFile}, atom);
|
||||
+ case is_name_sane(RemoteFile) of
|
||||
+ true ->
|
||||
+ call(Pid, {append_bin, Bin, RemoteFile}, atom);
|
||||
+ _ ->
|
||||
+ {error, efnamena}
|
||||
+ end;
|
||||
append_bin(_Pid, _Bin, _RemoteFile) ->
|
||||
{error, enotbinary}.
|
||||
|
||||
@@ -2302,6 +2397,15 @@ send_bin(State, Bin) ->
|
||||
mk_cmd(Fmt, Args) ->
|
||||
[io_lib:format(Fmt, Args)| [?CR, ?LF]]. % Deep list ok.
|
||||
|
||||
+is_name_sane([]) ->
|
||||
+ true;
|
||||
+is_name_sane([?CR| _]) ->
|
||||
+ false;
|
||||
+is_name_sane([?LF| _]) ->
|
||||
+ false;
|
||||
+is_name_sane([_| Rest]) ->
|
||||
+ is_name_sane(Rest).
|
||||
+
|
||||
pwd_result(Lines) ->
|
||||
{_, [?DOUBLE_QUOTE | Rest]} =
|
||||
lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Lines),
|
||||
diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
|
||||
index 35f21cc..daee1bd 100644
|
||||
--- a/lib/inets/test/ftp_suite_lib.erl
|
||||
+++ b/lib/inets/test/ftp_suite_lib.erl
|
||||
@@ -1266,6 +1266,8 @@ read_log_6035([]) ->
|
||||
%%--------------------------------------------------------------------
|
||||
do_user(Pid) ->
|
||||
{error, euser} = ftp:user(Pid, ?BAD_USER, ?FTP_PASS),
|
||||
+ {error, euser} = ftp:user(Pid, ?FTP_USER++"\r\nPASS "++?FTP_PASS, ?FTP_PASS),
|
||||
+ {error, euser} = ftp:user(Pid, ?FTP_USER, ?FTP_PASS++"\r\nCWD ."),
|
||||
ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS),
|
||||
ok.
|
||||
|
||||
@@ -1278,6 +1280,7 @@ do_pwd(Pid) ->
|
||||
do_cd(Pid) ->
|
||||
ok = ftp:cd(Pid, "/pub"),
|
||||
{error, epath} = ftp:cd(Pid, ?BAD_DIR),
|
||||
+ {error, efnamena} = ftp:cd(Pid, "/pub\r\nCWD ."),
|
||||
ok.
|
||||
|
||||
do_lcd(Pid, Dir) ->
|
||||
@@ -1294,11 +1297,14 @@ do_ls(Pid) ->
|
||||
%% directory, but can also be a filename or a group
|
||||
%% of files (including wildcards).
|
||||
{ok, _} = ftp:ls(Pid, "incom*"),
|
||||
+ %% but \r\n can't be in the wildcard
|
||||
+ {error, efnamena} = ftp:ls(Pid, "incoming\r\nCWD ."),
|
||||
ok.
|
||||
|
||||
do_nlist(Pid, WildcardSupport) ->
|
||||
{ok, _} = ftp:nlist(Pid),
|
||||
{ok, _} = ftp:nlist(Pid, "incoming"),
|
||||
+ {error, efnamena} = ftp:ls(Pid, "incoming\r\nCWD ."),
|
||||
%% neither nlist nor ls operates on a directory
|
||||
%% they operate on a pathname, which *can* be a
|
||||
%% directory, but can also be a filename or a group
|
||||
@@ -1324,6 +1330,8 @@ do_rename(Pid, Config) ->
|
||||
ftp:delete(Pid, NewLFile), % reset
|
||||
ok = ftp:send(Pid, LFile),
|
||||
{error, epath} = ftp:rename(Pid, NewLFile, LFile),
|
||||
+ {error, efnamena} = ftp:rename(Pid, NewLFile++"\r\nRNTO "++LFile++"\r\nRNFR "++NewLFile, LFile),
|
||||
+ {error, efnamena} = ftp:rename(Pid, NewLFile, LFile++"\r\nCWD ."),
|
||||
ok = ftp:rename(Pid, LFile, NewLFile),
|
||||
ftp:delete(Pid, LFile), % cleanup
|
||||
ftp:delete(Pid, NewLFile), % cleanup
|
||||
@@ -1338,6 +1346,7 @@ do_delete(Pid, Config) ->
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
ok = ftp:lcd(Pid, PrivDir),
|
||||
ftp:delete(Pid,LFile), % reset
|
||||
+ {error, efnamena} = ftp:delete(Pid,LFile++"\r\nCWD ."),
|
||||
ok = ftp:send(Pid, LFile),
|
||||
ok = ftp:delete(Pid,LFile),
|
||||
ok.
|
||||
@@ -1348,6 +1357,8 @@ do_mkdir(Pid) ->
|
||||
integer_to_list(B) ++ "_" ++ integer_to_list(C),
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
{ok, CurrDir} = ftp:pwd(Pid),
|
||||
+ {error, efnamena} = ftp:mkdir(Pid, NewDir++"\r\nCWD ."),
|
||||
+ {error, efnamena} = ftp:rmdir(Pid, NewDir++"\r\nCWD ."),
|
||||
ok = ftp:mkdir(Pid, NewDir),
|
||||
ok = ftp:cd(Pid, NewDir),
|
||||
ok = ftp:cd(Pid, CurrDir),
|
||||
@@ -1363,6 +1374,7 @@ do_send(Pid, Config) ->
|
||||
ok = file:write_file(AbsLFile, list_to_binary(Contents)),
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
ok = ftp:lcd(Pid, PrivDir),
|
||||
+ {error, efnamena} = ftp:send(Pid, LFile, RFile++"1\r\nCWD ."),
|
||||
ok = ftp:send(Pid, LFile, RFile),
|
||||
{ok, RFilesString} = ftp:nlist(Pid),
|
||||
RFiles = split(RFilesString),
|
||||
@@ -1392,6 +1404,7 @@ do_append(Pid, Config) ->
|
||||
ftp:delete(Pid, RFile),
|
||||
ftp:delete(Pid, LFile),
|
||||
|
||||
+ {error, efnamena} = ftp:append(Pid, LFile, RFile++"1\r\nCWD ."),
|
||||
ok = ftp:append(Pid, LFile, RFile),
|
||||
ok = ftp:append(Pid, LFile, RFile),
|
||||
ok = ftp:append(Pid, LFile),
|
||||
@@ -1413,6 +1426,7 @@ do_send_bin(Pid, Config) ->
|
||||
Bin = list_to_binary(Contents),
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
{error, enotbinary} = ftp:send_bin(Pid, Contents, File),
|
||||
+ {error, efnamena} = ftp:send_bin(Pid, Bin, File++"1\r\nCWD ."),
|
||||
ok = ftp:send_bin(Pid, Bin, File),
|
||||
{ok, RFilesString} = ftp:nlist(Pid),
|
||||
RFiles = split(RFilesString),
|
||||
@@ -1426,6 +1440,7 @@ do_append_bin(Pid, Config) ->
|
||||
Bin = list_to_binary(Contents),
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
{error, enotbinary} = ftp:append_bin(Pid, Contents, File),
|
||||
+ {error, efnamena} = ftp:append_bin(Pid, Bin, File++"1\r\nCWD ."),
|
||||
ok = ftp:append_bin(Pid, Bin, File),
|
||||
ok = ftp:append_bin(Pid, Bin, File),
|
||||
%% Control the contents of the file
|
||||
@@ -1438,6 +1453,7 @@ do_send_chunk(Pid, Config) ->
|
||||
Contents = "ftp_SUITE test ...",
|
||||
Bin = list_to_binary(Contents),
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
+ {error, efnamena} = ftp:send_chunk_start(Pid, File++"1\r\nCWD ."),
|
||||
ok = ftp:send_chunk_start(Pid, File),
|
||||
{error, echunk} = ftp:cd(Pid, "incoming"),
|
||||
{error, enotbinary} = ftp:send_chunk(Pid, Contents),
|
||||
@@ -1454,6 +1470,7 @@ do_append_chunk(Pid, Config) ->
|
||||
File = ?config(file, Config),
|
||||
Contents = ["ER","LE","RL"],
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
+ {error, efnamena} = ftp:append_chunk_start(Pid, File++"1\r\nCWD ."),
|
||||
ok = ftp:append_chunk_start(Pid, File),
|
||||
{error, enotbinary} = ftp:append_chunk(Pid, lists:nth(1,Contents)),
|
||||
ok = ftp:append_chunk(Pid,list_to_binary(lists:nth(1,Contents))),
|
||||
@@ -1480,6 +1497,7 @@ do_recv(Pid, Config) ->
|
||||
ok = file:delete(AbsFile), % cleanup
|
||||
test_server:sleep(100),
|
||||
ok = ftp:lcd(Pid, PrivDir),
|
||||
+ {error, efnamena} = ftp:recv(Pid, File++"\r\nCWD ."),
|
||||
ok = ftp:recv(Pid, File),
|
||||
{ok, Files} = file:list_dir(PrivDir),
|
||||
true = lists:member(File, Files),
|
||||
@@ -1495,6 +1513,7 @@ do_recv_bin(Pid, Config) ->
|
||||
ok = ftp:cd(Pid, "incoming"),
|
||||
ok = ftp:send_bin(Pid, Bin1, File),
|
||||
test_server:sleep(100),
|
||||
+ {error, efnamena} = ftp:recv_bin(Pid, File++"\r\nCWD ."),
|
||||
{ok, Bin2} = ftp:recv_bin(Pid, File),
|
||||
ok = ftp:delete(Pid, File), % cleanup
|
||||
Contents2 = binary_to_list(Bin2),
|
||||
@@ -1520,6 +1539,7 @@ do_recv_chunk(Pid, Config) ->
|
||||
ok = ftp:send_bin(Pid, Bin1, File),
|
||||
test_server:sleep(100),
|
||||
{error, "ftp:recv_chunk_start/2 not called"} = recv_chunk(Pid, <<>>),
|
||||
+ {error, efnamena} = ftp:recv_chunk_start(Pid, File++"\r\nCWD ."),
|
||||
ok = ftp:recv_chunk_start(Pid, File),
|
||||
{ok, Contents2} = recv_chunk(Pid, <<>>),
|
||||
ok = ftp:delete(Pid, File), % cleanup
|
||||
63
otp-0018-Introduce-os-getenv-2.patch
Normal file
63
otp-0018-Introduce-os-getenv-2.patch
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Sat, 8 Nov 2014 15:11:04 +0300
|
||||
Subject: [PATCH] Introduce os:getenv/2
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
|
||||
index 9122267..7ec1f8e 100644
|
||||
--- a/lib/kernel/doc/src/os.xml
|
||||
+++ b/lib/kernel/doc/src/os.xml
|
||||
@@ -100,6 +100,19 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
|
||||
</desc>
|
||||
</func>
|
||||
<func>
|
||||
+ <name name="getenv" arity="2"/>
|
||||
+ <fsummary>Get the value of an environment variable</fsummary>
|
||||
+ <desc>
|
||||
+ <p>Returns the <c><anno>Value</anno></c> of the environment variable
|
||||
+ <c><anno>VarName</anno></c>, or <c>DefaultValue</c> if the environment variable
|
||||
+ is undefined.</p>
|
||||
+ <p>If Unicode file name encoding is in effect (see the <seealso
|
||||
+ marker="erts:erl#file_name_encoding">erl manual
|
||||
+ page</seealso>), the strings (both <c><anno>VarName</anno></c> and
|
||||
+ <c><anno>Value</anno></c>) may contain characters with codepoints > 255.</p>
|
||||
+ </desc>
|
||||
+ </func>
|
||||
+ <func>
|
||||
<name name="getpid" arity="0"/>
|
||||
<fsummary>Return the process identifier of the emulator process</fsummary>
|
||||
<desc>
|
||||
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
|
||||
index 9415593..d5ef994 100644
|
||||
--- a/lib/kernel/src/os.erl
|
||||
+++ b/lib/kernel/src/os.erl
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
%%% BIFs
|
||||
|
||||
--export([getenv/0, getenv/1, getpid/0, putenv/2, timestamp/0, unsetenv/1]).
|
||||
+-export([getenv/0, getenv/1, getenv/2, getpid/0, putenv/2, timestamp/0, unsetenv/1]).
|
||||
|
||||
-spec getenv() -> [string()].
|
||||
|
||||
@@ -39,6 +39,19 @@ getenv() -> erlang:nif_error(undef).
|
||||
getenv(_) ->
|
||||
erlang:nif_error(undef).
|
||||
|
||||
+-spec getenv(VarName, DefaultValue) -> Value when
|
||||
+ VarName :: string(),
|
||||
+ DefaultValue :: string(),
|
||||
+ Value :: string().
|
||||
+
|
||||
+getenv(VarName, DefaultValue) ->
|
||||
+ case os:getenv(VarName) of
|
||||
+ false ->
|
||||
+ DefaultValue;
|
||||
+ Value ->
|
||||
+ Value
|
||||
+ end.
|
||||
+
|
||||
-spec getpid() -> Value when
|
||||
Value :: string().
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
From: Sergei Golovan <sgolovan@debian.org>
|
||||
Date: Sun, 30 Nov 2014 20:20:41 +0300
|
||||
Subject: [PATCH] Patch removes support for SSLv3 protocol because it is proved
|
||||
to be insecure and nobody should use it anymore.
|
||||
|
||||
|
||||
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
|
||||
index 1d74faf..912acc2 100644
|
||||
--- a/lib/ssl/doc/src/ssl.xml
|
||||
+++ b/lib/ssl/doc/src/ssl.xml
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
<p><c>sslsocket() - opaque to the user. </c></p>
|
||||
|
||||
- <p><c>protocol() = sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2' </c></p>
|
||||
+ <p><c>protocol() = tlsv1 | 'tlsv1.1' | 'tlsv1.2' </c></p>
|
||||
|
||||
<p><c>ciphers() = [ciphersuite()] | string() (according to old API)</c></p>
|
||||
|
||||
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
|
||||
index 0ee5b23..c65f8a3 100644
|
||||
--- a/lib/ssl/doc/src/ssl_app.xml
|
||||
+++ b/lib/ssl/doc/src/ssl_app.xml
|
||||
@@ -47,10 +47,10 @@
|
||||
</p>
|
||||
<p>Note that the environment parameters can be set on the command line,
|
||||
for instance,</p>
|
||||
- <p><c>erl ... -ssl protocol_version '[sslv3, tlsv1]' ...</c>.
|
||||
+ <p><c>erl ... -ssl protocol_version '[tlsv1.1, tlsv1]' ...</c>.
|
||||
</p>
|
||||
<taglist>
|
||||
- <tag><c><![CDATA[protocol_version = [sslv3|tlsv1] <optional>]]></c>.</tag>
|
||||
+ <tag><c><![CDATA[protocol_version = [tlsv1|tlsv1.1|tlsv1.2] <optional>]]></c>.</tag>
|
||||
<item>
|
||||
<p>Protocol that will be supported by started clients and
|
||||
servers. If this option is not set it will default to all
|
||||
@@ -58,6 +58,9 @@
|
||||
Note that this option may be overridden by the version option
|
||||
to ssl:connect/[2,3] and ssl:listen/2.
|
||||
</p>
|
||||
+ <p>For Debian GNU/Linux distribution the sslv3 protocol was
|
||||
+ disabled due to its security issues.
|
||||
+ </p>
|
||||
</item>
|
||||
|
||||
<tag><c><![CDATA[session_lifetime = integer() <optional>]]></c></tag>
|
||||
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
|
||||
index 0186f9f..6f84830 100644
|
||||
--- a/lib/ssl/src/ssl_internal.hrl
|
||||
+++ b/lib/ssl/src/ssl_internal.hrl
|
||||
@@ -67,8 +67,8 @@
|
||||
-define(TRUE, 0).
|
||||
-define(FALSE, 1).
|
||||
|
||||
--define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
|
||||
--define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1, sslv3]).
|
||||
+-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]).
|
||||
+-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]).
|
||||
-define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
|
||||
-define(MIN_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
|
||||
|
||||
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
|
||||
index c17fa53..f4be9be 100644
|
||||
--- a/lib/ssl/src/ssl_record.hrl
|
||||
+++ b/lib/ssl/src/ssl_record.hrl
|
||||
@@ -144,6 +144,7 @@
|
||||
%% }).
|
||||
|
||||
-define(LOWEST_MAJOR_SUPPORTED_VERSION, 3).
|
||||
+-define(LOWEST_MINOR_SUPPORTED_VERSION, 1).
|
||||
|
||||
|
||||
-record(generic_stream_cipher, {
|
||||
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
|
||||
index 8810755..3c5c7e9 100644
|
||||
--- a/lib/ssl/src/tls_record.erl
|
||||
+++ b/lib/ssl/src/tls_record.erl
|
||||
@@ -269,13 +269,19 @@ supported_protocol_versions([_|_] = Vsns) ->
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
is_acceptable_version({N,_})
|
||||
- when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
|
||||
+ when N > ?LOWEST_MAJOR_SUPPORTED_VERSION ->
|
||||
+ true;
|
||||
+is_acceptable_version({N,M})
|
||||
+ when N == ?LOWEST_MAJOR_SUPPORTED_VERSION andalso M >= ?LOWEST_MINOR_SUPPORTED_VERSION ->
|
||||
true;
|
||||
is_acceptable_version(_) ->
|
||||
false.
|
||||
|
||||
is_acceptable_version({N,_} = Version, Versions)
|
||||
- when N >= ?LOWEST_MAJOR_SUPPORTED_VERSION ->
|
||||
+ when N > ?LOWEST_MAJOR_SUPPORTED_VERSION ->
|
||||
+ lists:member(Version, Versions);
|
||||
+is_acceptable_version({N,M} = Version, Versions)
|
||||
+ when N == ?LOWEST_MAJOR_SUPPORTED_VERSION andalso M >= ?LOWEST_MINOR_SUPPORTED_VERSION ->
|
||||
lists:member(Version, Versions);
|
||||
is_acceptable_version(_,_) ->
|
||||
false.
|
||||
566
otp-0020-R16B03-1-backport-of-TLS-1.0-padding-check.patch
Normal file
566
otp-0020-R16B03-1-backport-of-TLS-1.0-padding-check.patch
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
From: John Eckersberg <jeckersb@redhat.com>
|
||||
Date: Fri, 7 Aug 2015 11:39:27 -0400
|
||||
Subject: [PATCH] R16B03-1 backport of TLS-1.0 padding check
|
||||
|
||||
commit 519b07bca04bdd8585b48f2de6b7124ca6455358
|
||||
Author: Ingela Anderton Andin <ingela@erlang.org>
|
||||
Date: Tue Jan 13 15:16:20 2015 +0100
|
||||
|
||||
ssl: Reenable padding check for TLS-1.0 and provide backwards compatible
|
||||
disable option
|
||||
|
||||
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
|
||||
index 912acc2..e496eb1 100644
|
||||
--- a/lib/ssl/doc/src/ssl.xml
|
||||
+++ b/lib/ssl/doc/src/ssl.xml
|
||||
@@ -334,11 +334,23 @@ fun(srp, Username :: string(), UserState :: term()) ->
|
||||
</p>
|
||||
</item>
|
||||
|
||||
+ <tag>{padding_check, boolean()}</tag>
|
||||
+ <item>
|
||||
+ <p> This option only affects TLS-1.0 connections.
|
||||
+ If set to false it disables the block cipher padding check
|
||||
+ to be able to interoperate with legacy software.
|
||||
+ </p>
|
||||
+
|
||||
+ <warning><p> Using this option makes TLS vulnerable to
|
||||
+ the Poodle attack</p></warning>
|
||||
+
|
||||
+ </item>
|
||||
+
|
||||
</taglist>
|
||||
-
|
||||
+
|
||||
</section>
|
||||
-
|
||||
- <section>
|
||||
+
|
||||
+ <section>
|
||||
<title>SSL OPTION DESCRIPTIONS - CLIENT SIDE</title>
|
||||
|
||||
<p>Options described here are client specific or has a slightly different
|
||||
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
|
||||
index b0a7976..49dc9d7 100644
|
||||
--- a/lib/ssl/src/dtls_record.erl
|
||||
+++ b/lib/ssl/src/dtls_record.erl
|
||||
@@ -1,7 +1,7 @@
|
||||
%%
|
||||
%% %CopyrightBegin%
|
||||
%%
|
||||
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
|
||||
+%% Copyright Ericsson AB 2013-2015. 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
|
||||
@@ -140,7 +140,7 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
|
||||
= ConnnectionStates0) ->
|
||||
CompressAlg = SecParams#security_parameters.compression_algorithm,
|
||||
{PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
|
||||
- CipherFragment, ReadState0),
|
||||
+ CipherFragment, ReadState0, true),
|
||||
MacHash = calc_mac_hash(Type, Version, Epoch, Seq, PlainFragment, ReadState1),
|
||||
case ssl_record:is_correct_mac(Mac, MacHash) of
|
||||
true ->
|
||||
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
|
||||
index a7fd9f5..802d29d 100644
|
||||
--- a/lib/ssl/src/ssl.erl
|
||||
+++ b/lib/ssl/src/ssl.erl
|
||||
@@ -640,7 +640,8 @@ handle_options(Opts0, _Role) ->
|
||||
make_next_protocol_selector(
|
||||
handle_option(client_preferred_next_protocols, Opts, undefined)),
|
||||
log_alert = handle_option(log_alert, Opts, true),
|
||||
- server_name_indication = handle_option(server_name_indication, Opts, undefined)
|
||||
+ server_name_indication = handle_option(server_name_indication, Opts, undefined),
|
||||
+ padding_check = proplists:get_value(padding_check, Opts, true)
|
||||
},
|
||||
|
||||
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
|
||||
@@ -652,7 +653,8 @@ handle_options(Opts0, _Role) ->
|
||||
reuse_session, reuse_sessions, ssl_imp,
|
||||
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
|
||||
erl_dist, next_protocols_advertised,
|
||||
- client_preferred_next_protocols, log_alert, server_name_indication],
|
||||
+ client_preferred_next_protocols, log_alert, server_name_indication,
|
||||
+ padding_check],
|
||||
|
||||
SockOpts = lists:foldl(fun(Key, PropList) ->
|
||||
proplists:delete(Key, PropList)
|
||||
@@ -840,6 +842,8 @@ validate_option(server_name_indication, disable) ->
|
||||
disable;
|
||||
validate_option(server_name_indication, undefined) ->
|
||||
undefined;
|
||||
+validate_option(padding_check, Value) when is_boolean(Value) ->
|
||||
+ Value;
|
||||
validate_option(Opt, Value) ->
|
||||
throw({error, {options, {Opt, Value}}}).
|
||||
|
||||
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
|
||||
index b2077c6..e546e37 100644
|
||||
--- a/lib/ssl/src/ssl_cipher.erl
|
||||
+++ b/lib/ssl/src/ssl_cipher.erl
|
||||
@@ -33,7 +33,7 @@
|
||||
-include_lib("public_key/include/public_key.hrl").
|
||||
|
||||
-export([security_parameters/2, security_parameters/3, suite_definition/1,
|
||||
- decipher/5, cipher/5,
|
||||
+ decipher/6, cipher/5,
|
||||
suite/1, suites/1, ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0,
|
||||
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
|
||||
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
|
||||
@@ -127,15 +127,16 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
|
||||
{T, CS0#cipher_state{iv=NextIV}}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
--spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) ->
|
||||
+-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(),
|
||||
+ tls_version(), boolean()) ->
|
||||
{binary(), binary(), #cipher_state{}} | #alert{}.
|
||||
%%
|
||||
%% Description: Decrypts the data and the MAC using cipher described
|
||||
%% by cipher_enum() and updating the cipher state.
|
||||
%%-------------------------------------------------------------------
|
||||
-decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
|
||||
+decipher(?NULL, _HashSz, CipherState, Fragment, _, _) ->
|
||||
{Fragment, <<>>, CipherState};
|
||||
-decipher(?RC4, HashSz, CipherState, Fragment, _) ->
|
||||
+decipher(?RC4, HashSz, CipherState, Fragment, _, _) ->
|
||||
State0 = case CipherState#cipher_state.state of
|
||||
undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
|
||||
S -> S
|
||||
@@ -155,23 +156,23 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
|
||||
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
|
||||
end;
|
||||
|
||||
-decipher(?DES, HashSz, CipherState, Fragment, Version) ->
|
||||
+decipher(?DES, HashSz, CipherState, Fragment, Version, PaddingCheck) ->
|
||||
block_decipher(fun(Key, IV, T) ->
|
||||
crypto:block_decrypt(des_cbc, Key, IV, T)
|
||||
- end, CipherState, HashSz, Fragment, Version);
|
||||
-decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
|
||||
+ end, CipherState, HashSz, Fragment, Version, PaddingCheck);
|
||||
+decipher(?'3DES', HashSz, CipherState, Fragment, Version, PaddingCheck) ->
|
||||
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
|
||||
crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
|
||||
- end, CipherState, HashSz, Fragment, Version);
|
||||
-decipher(?AES, HashSz, CipherState, Fragment, Version) ->
|
||||
+ end, CipherState, HashSz, Fragment, Version, PaddingCheck);
|
||||
+decipher(?AES, HashSz, CipherState, Fragment, Version, PaddingCheck) ->
|
||||
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
|
||||
crypto:block_decrypt(aes_cbc128, Key, IV, T);
|
||||
(Key, IV, T) when byte_size(Key) =:= 32 ->
|
||||
crypto:block_decrypt(aes_cbc256, Key, IV, T)
|
||||
- end, CipherState, HashSz, Fragment, Version).
|
||||
+ end, CipherState, HashSz, Fragment, Version, PaddingCheck).
|
||||
|
||||
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
|
||||
- HashSz, Fragment, Version) ->
|
||||
+ HashSz, Fragment, Version, PaddingCheck) ->
|
||||
try
|
||||
Text = Fun(Key, IV, Fragment),
|
||||
NextIV = next_iv(Fragment, IV),
|
||||
@@ -179,7 +180,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
|
||||
Content = GBC#generic_block_cipher.content,
|
||||
Mac = GBC#generic_block_cipher.mac,
|
||||
CipherState1 = CipherState0#cipher_state{iv=GBC#generic_block_cipher.next_iv},
|
||||
- case is_correct_padding(GBC, Version) of
|
||||
+ case is_correct_padding(GBC, Version, PaddingCheck) of
|
||||
true ->
|
||||
{Content, Mac, CipherState1};
|
||||
false ->
|
||||
@@ -1266,16 +1267,18 @@ generic_stream_cipher_from_bin(T, HashSz) ->
|
||||
#generic_stream_cipher{content=Content,
|
||||
mac=Mac}.
|
||||
|
||||
-%% For interoperability reasons we do not check the padding content in
|
||||
-%% SSL 3.0 and TLS 1.0 as it is not strictly required and breaks
|
||||
-%% interopability with for instance Google.
|
||||
is_correct_padding(#generic_block_cipher{padding_length = Len,
|
||||
- padding = Padding}, {3, N})
|
||||
- when N == 0; N == 1 ->
|
||||
- Len == byte_size(Padding);
|
||||
-%% Padding must be check in TLS 1.1 and after
|
||||
+ padding = Padding}, {3, 0}, _) ->
|
||||
+ Len == byte_size(Padding); %% Only length check is done in SSL 3.0 spec
|
||||
+%% For interoperability reasons it is possible to disable
|
||||
+%% the padding check when using TLS 1.0, as it is not strictly required
|
||||
+%% in the spec (only recommended), howerver this makes TLS 1.0 vunrable to the Poodle attack
|
||||
+%% so by default this clause will not match
|
||||
+is_correct_padding(GenBlockCipher, {3, 1}, false) ->
|
||||
+ is_correct_padding(GenBlockCipher, {3, 0}, false);
|
||||
+%% Padding must be checked in TLS 1.1 and after
|
||||
is_correct_padding(#generic_block_cipher{padding_length = Len,
|
||||
- padding = Padding}, _) ->
|
||||
+ padding = Padding}, _, _) ->
|
||||
Len == byte_size(Padding) andalso
|
||||
list_to_binary(lists:duplicate(Len, Len)) == Padding.
|
||||
|
||||
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
|
||||
index 6f84830..8c12141 100644
|
||||
--- a/lib/ssl/src/ssl_internal.hrl
|
||||
+++ b/lib/ssl/src/ssl_internal.hrl
|
||||
@@ -114,7 +114,8 @@
|
||||
next_protocols_advertised = undefined, %% [binary()],
|
||||
next_protocol_selector = undefined, %% fun([binary()]) -> binary())
|
||||
log_alert :: boolean(),
|
||||
- server_name_indication = undefined
|
||||
+ server_name_indication = undefined,
|
||||
+ padding_check = true
|
||||
}).
|
||||
|
||||
-record(config, {ssl, %% SSL parameters
|
||||
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
|
||||
index 018c8be..ed9efe2 100644
|
||||
--- a/lib/ssl/src/ssl_record.erl
|
||||
+++ b/lib/ssl/src/ssl_record.erl
|
||||
@@ -1,7 +1,7 @@
|
||||
%%
|
||||
%% %CopyrightBegin%
|
||||
%%
|
||||
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
|
||||
+%% Copyright Ericsson AB 2013-2015. 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
|
||||
@@ -48,7 +48,7 @@
|
||||
-export([compress/3, uncompress/3, compressions/0]).
|
||||
|
||||
%% Payload encryption/decryption
|
||||
--export([cipher/4, decipher/3, is_correct_mac/2]).
|
||||
+-export([cipher/4, decipher/4, is_correct_mac/2]).
|
||||
|
||||
%%====================================================================
|
||||
%% Internal application API
|
||||
@@ -372,7 +372,7 @@ cipher(Version, Fragment,
|
||||
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
|
||||
{CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
|
||||
%%--------------------------------------------------------------------
|
||||
--spec decipher(tls_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
|
||||
+-spec decipher(tls_version(), binary(), #connection_state{}, boolean()) -> {binary(), binary(), #connection_state{}}.
|
||||
%%
|
||||
%% Description: Payload decryption
|
||||
%%--------------------------------------------------------------------
|
||||
@@ -382,8 +382,8 @@ decipher(Version, CipherFragment,
|
||||
BulkCipherAlgo,
|
||||
hash_size = HashSz},
|
||||
cipher_state = CipherS0
|
||||
- } = ReadState) ->
|
||||
- case ssl_cipher:decipher(BulkCipherAlgo, HashSz, CipherS0, CipherFragment, Version) of
|
||||
+ } = ReadState, PaddingCheck) ->
|
||||
+ case ssl_cipher:decipher(BulkCipherAlgo, HashSz, CipherS0, CipherFragment, Version, PaddingCheck) of
|
||||
{PlainFragment, Mac, CipherS1} ->
|
||||
CS1 = ReadState#connection_state{cipher_state = CipherS1},
|
||||
{PlainFragment, Mac, CS1};
|
||||
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
|
||||
index ffa04ee..007c9b1 100644
|
||||
--- a/lib/ssl/src/tls_connection.erl
|
||||
+++ b/lib/ssl/src/tls_connection.erl
|
||||
@@ -1,7 +1,7 @@
|
||||
%%
|
||||
%% %CopyrightBegin%
|
||||
%%
|
||||
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
|
||||
+%% Copyright Ericsson AB 2007-2015. 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
|
||||
@@ -499,8 +499,9 @@ next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_ci
|
||||
next_record(#state{protocol_buffers =
|
||||
#protocol_buffers{tls_packets = [], tls_cipher_texts = [CT | Rest]}
|
||||
= Buffers,
|
||||
- connection_states = ConnStates0} = State) ->
|
||||
- case tls_record:decode_cipher_text(CT, ConnStates0) of
|
||||
+ connection_states = ConnStates0,
|
||||
+ ssl_options = #ssl_options{padding_check = Check}} = State) ->
|
||||
+ case tls_record:decode_cipher_text(CT, ConnStates0, Check) of
|
||||
{Plain, ConnStates} ->
|
||||
{Plain, State#state{protocol_buffers =
|
||||
Buffers#protocol_buffers{tls_cipher_texts = Rest},
|
||||
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
|
||||
index 3c5c7e9..dd99d10 100644
|
||||
--- a/lib/ssl/src/tls_record.erl
|
||||
+++ b/lib/ssl/src/tls_record.erl
|
||||
@@ -1,7 +1,7 @@
|
||||
%%
|
||||
%% %CopyrightBegin%
|
||||
%%
|
||||
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
|
||||
+%% Copyright Ericsson AB 2007-2015. 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
|
||||
@@ -34,7 +34,7 @@
|
||||
-export([get_tls_records/2]).
|
||||
|
||||
%% Decoding
|
||||
--export([decode_cipher_text/2]).
|
||||
+-export([decode_cipher_text/3]).
|
||||
|
||||
%% Encoding
|
||||
-export([encode_plain_text/4]).
|
||||
@@ -137,7 +137,7 @@ encode_plain_text(Type, Version, Data,
|
||||
{CipherText, ConnectionStates#connection_states{current_write = WriteState#connection_state{sequence_number = Seq +1}}}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
--spec decode_cipher_text(#ssl_tls{}, #connection_states{}) ->
|
||||
+-spec decode_cipher_text(#ssl_tls{}, #connection_states{}, boolean()) ->
|
||||
{#ssl_tls{}, #connection_states{}}| #alert{}.
|
||||
%%
|
||||
%% Description: Decode cipher text
|
||||
@@ -164,6 +164,33 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
|
||||
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
|
||||
end.
|
||||
|
||||
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
|
||||
+ fragment = CipherFragment} = CipherText,
|
||||
+ #connection_states{current_read =
|
||||
+ #connection_state{
|
||||
+ compression_state = CompressionS0,
|
||||
+ sequence_number = Seq,
|
||||
+ security_parameters=
|
||||
+ #security_parameters{compression_algorithm=CompAlg}
|
||||
+ } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
|
||||
+ case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
|
||||
+ {PlainFragment, Mac, ReadState1} ->
|
||||
+ MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),
|
||||
+ case ssl_record:is_correct_mac(Mac, MacHash) of
|
||||
+ true ->
|
||||
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
|
||||
+ PlainFragment, CompressionS0),
|
||||
+ ConnnectionStates = ConnnectionStates0#connection_states{
|
||||
+ current_read = ReadState1#connection_state{
|
||||
+ sequence_number = Seq + 1,
|
||||
+ compression_state = CompressionS1}},
|
||||
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
|
||||
+ false ->
|
||||
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
|
||||
+ end;
|
||||
+ #alert{} = Alert ->
|
||||
+ Alert
|
||||
+ end.
|
||||
%%--------------------------------------------------------------------
|
||||
-spec protocol_version(tls_atom_version() | tls_version()) ->
|
||||
tls_version() | tls_atom_version().
|
||||
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
|
||||
index 45e9178..3433f9a 100644
|
||||
--- a/lib/ssl/test/ssl_cipher_SUITE.erl
|
||||
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
|
||||
@@ -1,7 +1,7 @@
|
||||
%%
|
||||
%% %CopyrightBegin%
|
||||
%%
|
||||
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
|
||||
+%% Copyright Ericsson AB 2008-2015. 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
|
||||
@@ -38,7 +38,7 @@
|
||||
suite() -> [{ct_hooks,[ts_install_cth]}].
|
||||
|
||||
all() ->
|
||||
- [aes_decipher_good, aes_decipher_good_tls11, aes_decipher_fail, aes_decipher_fail_tls11].
|
||||
+ [aes_decipher_good, aes_decipher_fail, padding_test].
|
||||
|
||||
groups() ->
|
||||
[].
|
||||
@@ -73,93 +73,122 @@ end_per_testcase(_TestCase, Config) ->
|
||||
%% Test Cases --------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
aes_decipher_good() ->
|
||||
- [{doc,"Decipher a known cryptotext."}].
|
||||
+ [{doc,"Decipher a known cryptotext using a correct key"}].
|
||||
|
||||
aes_decipher_good(Config) when is_list(Config) ->
|
||||
HashSz = 32,
|
||||
- CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
- key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>},
|
||||
- Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
|
||||
- 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
|
||||
- 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
|
||||
- 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
|
||||
- Content = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56, "HELLO\n">>,
|
||||
- Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>,
|
||||
- Version = {3,0},
|
||||
- {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
|
||||
- Version1 = {3,1},
|
||||
- {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
|
||||
- ok.
|
||||
+ CipherState = correct_cipher_state(),
|
||||
+ decipher_check_good(HashSz, CipherState, {3,0}),
|
||||
+ decipher_check_good(HashSz, CipherState, {3,1}),
|
||||
+ decipher_check_good(HashSz, CipherState, {3,2}),
|
||||
+ decipher_check_good(HashSz, CipherState, {3,3}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
-
|
||||
-aes_decipher_good_tls11() ->
|
||||
- [{doc,"Decipher a known TLS 1.1 cryptotext."}].
|
||||
-
|
||||
-%% the fragment is actuall a TLS 1.1 record, with
|
||||
-%% Version = TLS 1.1, we get the correct NextIV in #cipher_state
|
||||
-aes_decipher_good_tls11(Config) when is_list(Config) ->
|
||||
- HashSz = 32,
|
||||
- CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
- key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>},
|
||||
- Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
|
||||
- 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
|
||||
- 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
|
||||
- 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
|
||||
- Content = <<"HELLO\n">>,
|
||||
- NextIV = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56>>,
|
||||
- Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>,
|
||||
- Version = {3,2},
|
||||
- {Content, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
|
||||
- Version1 = {3,2},
|
||||
- {Content, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
|
||||
- ok.
|
||||
-
|
||||
-%%--------------------------------------------------------------------
|
||||
-
|
||||
aes_decipher_fail() ->
|
||||
- [{doc,"Decipher a known cryptotext."}].
|
||||
+ [{doc,"Decipher a known cryptotext using a incorrect key"}].
|
||||
|
||||
-%% same as above, last byte of key replaced
|
||||
aes_decipher_fail(Config) when is_list(Config) ->
|
||||
HashSz = 32,
|
||||
- CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
- key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>},
|
||||
- Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
|
||||
- 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
|
||||
- 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
|
||||
- 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
|
||||
- Version = {3,0},
|
||||
- {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
|
||||
- 32 = byte_size(Content),
|
||||
- 32 = byte_size(Mac),
|
||||
- Version1 = {3,1},
|
||||
- {Content1, Mac1, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
|
||||
- 32 = byte_size(Content1),
|
||||
- 32 = byte_size(Mac1),
|
||||
- ok.
|
||||
+ CipherState = incorrect_cipher_state(),
|
||||
+ decipher_check_fail(HashSz, CipherState, {3,0}),
|
||||
+ decipher_check_fail(HashSz, CipherState, {3,1}),
|
||||
+ decipher_check_fail(HashSz, CipherState, {3,2}),
|
||||
+ decipher_check_fail(HashSz, CipherState, {3,3}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
-
|
||||
-aes_decipher_fail_tls11() ->
|
||||
- [{doc,"Decipher a known TLS 1.1 cryptotext."}].
|
||||
-
|
||||
-%% same as above, last byte of key replaced
|
||||
-%% stricter padding checks in TLS 1.1 mean we get an alert instead
|
||||
-aes_decipher_fail_tls11(Config) when is_list(Config) ->
|
||||
- HashSz = 32,
|
||||
- CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
- key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>},
|
||||
- Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
|
||||
- 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
|
||||
- 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
|
||||
- 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
|
||||
- Version = {3,2},
|
||||
- #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} =
|
||||
- ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
|
||||
- Version1 = {3,3},
|
||||
- #alert{level = ?FATAL, description = ?BAD_RECORD_MAC} =
|
||||
- ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version1),
|
||||
- ok.
|
||||
-
|
||||
+padding_test(Config) when is_list(Config) ->
|
||||
+ HashSz = 16,
|
||||
+ CipherState = correct_cipher_state(),
|
||||
+ pad_test(HashSz, CipherState, {3,0}),
|
||||
+ pad_test(HashSz, CipherState, {3,1}),
|
||||
+ pad_test(HashSz, CipherState, {3,2}),
|
||||
+ pad_test(HashSz, CipherState, {3,3}).
|
||||
+
|
||||
+%%--------------------------------------------------------------------
|
||||
+% Internal functions --------------------------------------------------------
|
||||
%%--------------------------------------------------------------------
|
||||
+decipher_check_good(HashSz, CipherState, Version) ->
|
||||
+ {Content, NextIV, Mac} = content_nextiv_mac(Version),
|
||||
+ {Content, Mac, _} =
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, aes_fragment(Version), Version, true).
|
||||
+
|
||||
+decipher_check_fail(HashSz, CipherState, Version) ->
|
||||
+ {Content, NextIV, Mac} = content_nextiv_mac(Version),
|
||||
+ true = {Content, Mac, #cipher_state{iv = NextIV}} =/=
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, aes_fragment(Version), Version, true).
|
||||
+
|
||||
+pad_test(HashSz, CipherState, {3,0} = Version) ->
|
||||
+ %% 3.0 does not have padding test
|
||||
+ {Content, NextIV, Mac} = badpad_content_nextiv_mac(Version),
|
||||
+ {Content, Mac, #cipher_state{iv = NextIV}} =
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, badpad_aes_fragment({3,0}), {3,0}, true),
|
||||
+ {Content, Mac, #cipher_state{iv = NextIV}} =
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, badpad_aes_fragment({3,0}), {3,0}, false);
|
||||
+pad_test(HashSz, CipherState, {3,1} = Version) ->
|
||||
+ %% 3.1 should have padding test, but may be disabled
|
||||
+ {Content, NextIV, Mac} = badpad_content_nextiv_mac(Version),
|
||||
+ BadCont = badpad_content(Content),
|
||||
+ {Content, Mac, #cipher_state{iv = NextIV}} =
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, badpad_aes_fragment({3,1}) , {3,1}, false),
|
||||
+ {BadCont, Mac, #cipher_state{iv = NextIV}} =
|
||||
+ ssl_cipher:decipher(?AES_CBC, HashSz, CipherState, badpad_aes_fragment({3,1}), {3,1}, true);
|
||||
+pad_test(HashSz, CipherState, Version) ->
|
||||
+ %% 3.2 and 3.3 must have padding test
|
||||
+ {Content, NextIV, Mac} = badpad_content_nextiv_mac(Version),
|
||||
+ BadCont = badpad_content(Content),
|
||||
+ {BadCont, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES_CBC, HashSz, CipherState,
|
||||
+ badpad_aes_fragment(Version), Version, false),
|
||||
+ {BadCont, Mac, #cipher_state{iv = NextIV}} = ssl_cipher:decipher(?AES_CBC, HashSz, CipherState,
|
||||
+ badpad_aes_fragment(Version), Version, true).
|
||||
+
|
||||
+aes_fragment({3,N}) when N == 0; N == 1->
|
||||
+ <<197,9,6,109,242,87,80,154,85,250,110,81,119,95,65,185,53,206,216,153,246,169,
|
||||
+ 119,177,178,238,248,174,253,220,242,81,33,0,177,251,91,44,247,53,183,198,165,
|
||||
+ 63,20,194,159,107>>;
|
||||
+
|
||||
+aes_fragment(_) ->
|
||||
+ <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
|
||||
+ 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
|
||||
+ 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
|
||||
+ 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>.
|
||||
+
|
||||
+badpad_aes_fragment({3,N}) when N == 0; N == 1 ->
|
||||
+ <<186,139,125,10,118,21,26,248,120,108,193,104,87,118,145,79,225,55,228,10,105,
|
||||
+ 30,190,37,1,88,139,243,210,99,65,41>>;
|
||||
+badpad_aes_fragment(_) ->
|
||||
+ <<137,31,14,77,228,80,76,103,183,125,55,250,68,190,123,131,117,23,229,180,207,
|
||||
+ 94,121,137,117,157,109,99,113,61,190,138,131,229,201,120,142,179,172,48,77,
|
||||
+ 234,19,240,33,38,91,93>>.
|
||||
+
|
||||
+content_nextiv_mac({3,N}) when N == 0; N == 1 ->
|
||||
+ {<<"HELLO\n">>,
|
||||
+ <<72,196,247,97,62,213,222,109,210,204,217,186,172,184, 197,148>>,
|
||||
+ <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>};
|
||||
+content_nextiv_mac(_) ->
|
||||
+ {<<"HELLO\n">>,
|
||||
+ <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56>>,
|
||||
+ <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>}.
|
||||
+
|
||||
+badpad_content_nextiv_mac({3,N}) when N == 0; N == 1 ->
|
||||
+ {<<"HELLO\n">>,
|
||||
+ <<225,55,228,10,105,30,190,37,1,88,139,243,210,99,65,41>>,
|
||||
+ <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56>>
|
||||
+ };
|
||||
+badpad_content_nextiv_mac(_) ->
|
||||
+ {<<"HELLO\n">>,
|
||||
+ <<133,211,45,189,179,229,56,86,11,178,239,159,14,160,253,140>>,
|
||||
+ <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56>>
|
||||
+ }.
|
||||
+
|
||||
+badpad_content(Content) ->
|
||||
+ %% BadContent will fail mac test
|
||||
+ <<16#F0, Content/binary>>.
|
||||
+
|
||||
+correct_cipher_state() ->
|
||||
+ #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
+ key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>}.
|
||||
+
|
||||
+incorrect_cipher_state() ->
|
||||
+ #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
|
||||
+ key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>}.
|
||||
+
|
||||
31
otp-0021-Add-patch-to-crash-dump-on-large-distribution.patch
Normal file
31
otp-0021-Add-patch-to-crash-dump-on-large-distribution.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From: John Eckersberg <jeckersb@redhat.com>
|
||||
Date: Wed, 16 Dec 2015 11:03:42 -0500
|
||||
Subject: [PATCH] Add patch to crash dump on large distribution
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1291822
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1291855
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1291856
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1291857
|
||||
|
||||
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
|
||||
index 6ecf3f0..7d1f4ea 100644
|
||||
--- a/erts/emulator/beam/dist.c
|
||||
+++ b/erts/emulator/beam/dist.c
|
||||
@@ -1880,7 +1880,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf)
|
||||
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
|
||||
|
||||
if (size > (Uint) INT_MAX)
|
||||
- erl_exit(ERTS_ABORT_EXIT,
|
||||
+ erl_exit(ERTS_DUMP_EXIT,
|
||||
"Absurdly large distribution output data buffer "
|
||||
"(%beu bytes) passed.\n",
|
||||
size);
|
||||
@@ -1919,7 +1919,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf)
|
||||
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
|
||||
|
||||
if (size > (Uint) INT_MAX)
|
||||
- erl_exit(ERTS_ABORT_EXIT,
|
||||
+ erl_exit(ERTS_DUMP_EXIT,
|
||||
"Absurdly large distribution output data buffer "
|
||||
"(%beu bytes) passed.\n",
|
||||
size);
|
||||
891
otp-0022-kernel-inet6_tcp_dist-reuse-inet_tcp_dist-code.patch
Normal file
891
otp-0022-kernel-inet6_tcp_dist-reuse-inet_tcp_dist-code.patch
Normal file
|
|
@ -0,0 +1,891 @@
|
|||
From: Danil Zagoskin <stolen@yandex-team.ru>
|
||||
Date: Sat, 2 May 2015 00:40:53 +0300
|
||||
Subject: [PATCH] kernel: inet6_tcp_dist: reuse inet_tcp_dist code
|
||||
|
||||
inet6_tcp_dist module is an old copy of inet_tcp_dist with changed
|
||||
address family.
|
||||
New features (such as listening port range, interface and generic
|
||||
options) are implemented in inet_tcp_dist only, inet6_tcp_dist looks
|
||||
abandoned (it does not even have tests).
|
||||
This patch makes inet_tcp_dist internals work with abstract driver,
|
||||
and inet6_tcp_dist becomes just a thin wrapper for it.
|
||||
|
||||
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
|
||||
index c714b2b..b31f05b 100644
|
||||
--- a/lib/kernel/src/inet6_tcp.erl
|
||||
+++ b/lib/kernel/src/inet6_tcp.erl
|
||||
@@ -24,10 +24,29 @@
|
||||
-export([controlling_process/2]).
|
||||
-export([fdopen/2]).
|
||||
|
||||
+-export([family/0, mask/2, parse_address/1]).
|
||||
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
|
||||
|
||||
-include("inet_int.hrl").
|
||||
|
||||
+%% my address family
|
||||
+family() -> inet6.
|
||||
+
|
||||
+%% Apply netmask on address
|
||||
+mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
|
||||
+ {M1 band IP1,
|
||||
+ M2 band IP2,
|
||||
+ M3 band IP3,
|
||||
+ M4 band IP4,
|
||||
+ M5 band IP5,
|
||||
+ M6 band IP6,
|
||||
+ M7 band IP7,
|
||||
+ M8 band IP8 }.
|
||||
+
|
||||
+%% Parse address string
|
||||
+parse_address(Host) ->
|
||||
+ inet_parse:ipv6strict_address(Host).
|
||||
+
|
||||
%% inet_tcp port lookup
|
||||
getserv(Port) when is_integer(Port) -> {ok, Port};
|
||||
getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
|
||||
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
|
||||
index 2cb0e10..1488bf4 100644
|
||||
--- a/lib/kernel/src/inet6_tcp_dist.erl
|
||||
+++ b/lib/kernel/src/inet6_tcp_dist.erl
|
||||
@@ -23,28 +23,6 @@
|
||||
-export([listen/1, accept/1, accept_connection/5,
|
||||
setup/5, close/1, select/1, is_node_name/1]).
|
||||
|
||||
-%% internal exports
|
||||
-
|
||||
--export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]).
|
||||
-
|
||||
--import(error_logger,[error_msg/2]).
|
||||
-
|
||||
--include("net_address.hrl").
|
||||
-
|
||||
-
|
||||
-
|
||||
--define(to_port(Socket, Data, Opts),
|
||||
- case inet6_tcp:send(Socket, Data, Opts) of
|
||||
- {error, closed} ->
|
||||
- self() ! {tcp_closed, Socket},
|
||||
- {error, closed};
|
||||
- R ->
|
||||
- R
|
||||
- end).
|
||||
-
|
||||
-
|
||||
--include("dist.hrl").
|
||||
--include("dist_util.hrl").
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Select this protocol based on node name
|
||||
@@ -52,14 +30,7 @@
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
select(Node) ->
|
||||
- case split_node(atom_to_list(Node), $@, []) of
|
||||
- [_, Host] ->
|
||||
- case inet:getaddr(Host,inet6) of
|
||||
- {ok,_} -> true;
|
||||
- _ -> false
|
||||
- end;
|
||||
- _ -> false
|
||||
- end.
|
||||
+ inet_tcp_dist:gen_select(inet6_tcp, Node).
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Create the listen socket, i.e. the port that this erlang
|
||||
@@ -67,59 +38,14 @@ select(Node) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
listen(Name) ->
|
||||
- case inet6_tcp:listen(0, [{active, false}, {packet,2}]) of
|
||||
- {ok, Socket} ->
|
||||
- TcpAddress = get_tcp_address(Socket),
|
||||
- {_,Port} = TcpAddress#net_address.address,
|
||||
- case erl_epmd:register_node(Name, Port) of
|
||||
- {ok, Creation} ->
|
||||
- {ok, {Socket, TcpAddress, Creation}};
|
||||
- Error ->
|
||||
- Error
|
||||
- end;
|
||||
- Error ->
|
||||
- Error
|
||||
- end.
|
||||
+ inet_tcp_dist:gen_listen(inet6_tcp, Name).
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Accepts new connection attempts from other Erlang nodes.
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
accept(Listen) ->
|
||||
- spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
|
||||
-
|
||||
-accept_loop(Kernel, Listen) ->
|
||||
- case inet6_tcp:accept(Listen) of
|
||||
- {ok, Socket} ->
|
||||
- Kernel ! {accept,self(),Socket,inet6,tcp},
|
||||
- controller(Kernel, Socket),
|
||||
- accept_loop(Kernel, Listen);
|
||||
- Error ->
|
||||
- exit(Error)
|
||||
- end.
|
||||
-
|
||||
-controller(Kernel, Socket) ->
|
||||
- receive
|
||||
- {Kernel, controller, Pid} ->
|
||||
- flush_controller(Pid, Socket),
|
||||
- inet6_tcp:controlling_process(Socket, Pid),
|
||||
- flush_controller(Pid, Socket),
|
||||
- Pid ! {self(), controller};
|
||||
- {Kernel, unsupported_protocol} ->
|
||||
- exit(unsupported_protocol)
|
||||
- end.
|
||||
-
|
||||
-flush_controller(Pid, Socket) ->
|
||||
- receive
|
||||
- {tcp, Socket, Data} ->
|
||||
- Pid ! {tcp, Socket, Data},
|
||||
- flush_controller(Pid, Socket);
|
||||
- {tcp_closed, Socket} ->
|
||||
- Pid ! {tcp_closed, Socket},
|
||||
- flush_controller(Pid, Socket)
|
||||
- after 0 ->
|
||||
- ok
|
||||
- end.
|
||||
+ inet_tcp_dist:gen_accept(inet6_tcp, Listen).
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Accepts a new connection attempt from another Erlang node.
|
||||
@@ -127,85 +53,7 @@ flush_controller(Pid, Socket) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
- spawn_opt(?MODULE, do_accept,
|
||||
- [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
|
||||
- [link, {priority, max}]).
|
||||
-
|
||||
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
- receive
|
||||
- {AcceptPid, controller} ->
|
||||
- Timer = dist_util:start_timer(SetupTime),
|
||||
- case check_ip(Socket) of
|
||||
- true ->
|
||||
- HSData = #hs_data{
|
||||
- kernel_pid = Kernel,
|
||||
- this_node = MyNode,
|
||||
- socket = Socket,
|
||||
- timer = Timer,
|
||||
- this_flags = 0,
|
||||
- allowed = Allowed,
|
||||
- f_send = fun(S,D) -> inet6_tcp:send(S,D) end,
|
||||
- f_recv = fun(S,N,T) -> inet6_tcp:recv(S,N,T)
|
||||
- end,
|
||||
- f_setopts_pre_nodeup =
|
||||
- fun(S) ->
|
||||
- inet:setopts(S,
|
||||
- [{active, false},
|
||||
- {packet, 4},
|
||||
- nodelay()])
|
||||
- end,
|
||||
- f_setopts_post_nodeup =
|
||||
- fun(S) ->
|
||||
- inet:setopts(S,
|
||||
- [{active, true},
|
||||
- {deliver, port},
|
||||
- {packet, 4},
|
||||
- nodelay()])
|
||||
- end,
|
||||
- f_getll = fun(S) ->
|
||||
- inet:getll(S)
|
||||
- end,
|
||||
- f_address = fun get_remote_id/2,
|
||||
- mf_tick = fun ?MODULE:tick/1,
|
||||
- mf_getstat = fun ?MODULE:getstat/1
|
||||
- },
|
||||
- dist_util:handshake_other_started(HSData);
|
||||
- {false,IP} ->
|
||||
- error_msg("** Connection attempt from "
|
||||
- "disallowed IP ~w ** ~n", [IP]),
|
||||
- ?shutdown(no_node)
|
||||
- end
|
||||
- end.
|
||||
-
|
||||
-
|
||||
-%% we may not always want the nodelay behaviour
|
||||
-%% for performance reasons
|
||||
-
|
||||
-nodelay() ->
|
||||
- case application:get_env(kernel, dist_nodelay) of
|
||||
- undefined ->
|
||||
- {nodelay, true};
|
||||
- {ok, true} ->
|
||||
- {nodelay, true};
|
||||
- {ok, false} ->
|
||||
- {nodelay, false};
|
||||
- _ ->
|
||||
- {nodelay, true}
|
||||
- end.
|
||||
-
|
||||
-
|
||||
-%% ------------------------------------------------------------
|
||||
-%% Get remote information about a Socket.
|
||||
-%% ------------------------------------------------------------
|
||||
-
|
||||
-get_remote_id(Socket, Node) ->
|
||||
- {ok, Address} = inet:peername(Socket),
|
||||
- [_, Host] = split_node(atom_to_list(Node), $@, []),
|
||||
- #net_address {
|
||||
- address = Address,
|
||||
- host = Host,
|
||||
- protocol = tcp,
|
||||
- family = inet6 }.
|
||||
+ inet_tcp_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Setup a new connection to another Erlang node.
|
||||
@@ -213,214 +61,13 @@ get_remote_id(Socket, Node) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
- spawn_opt(?MODULE, do_setup,
|
||||
- [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
|
||||
- [link, {priority, max}]).
|
||||
-
|
||||
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
- ?trace("~p~n",[{?MODULE,self(),setup,Node}]),
|
||||
- [Name, Address] = splitnode(Node, LongOrShortNames),
|
||||
- case inet:getaddr(Address, inet6) of
|
||||
- {ok, Ip} ->
|
||||
- Timer = dist_util:start_timer(SetupTime),
|
||||
- case erl_epmd:port_please(Name, Ip) of
|
||||
- {port, TcpPort, Version} ->
|
||||
- ?trace("port_please(~p) -> version ~p~n",
|
||||
- [Node,Version]),
|
||||
- dist_util:reset_timer(Timer),
|
||||
- case inet6_tcp:connect(Ip, TcpPort,
|
||||
- [{active, false},
|
||||
- {packet,2}]) of
|
||||
- {ok, Socket} ->
|
||||
- HSData = #hs_data{
|
||||
- kernel_pid = Kernel,
|
||||
- other_node = Node,
|
||||
- this_node = MyNode,
|
||||
- socket = Socket,
|
||||
- timer = Timer,
|
||||
- this_flags = 0,
|
||||
- other_version = Version,
|
||||
- f_send = fun inet6_tcp:send/2,
|
||||
- f_recv = fun inet6_tcp:recv/3,
|
||||
- f_setopts_pre_nodeup =
|
||||
- fun(S) ->
|
||||
- inet:setopts
|
||||
- (S,
|
||||
- [{active, false},
|
||||
- {packet, 4},
|
||||
- nodelay()])
|
||||
- end,
|
||||
- f_setopts_post_nodeup =
|
||||
- fun(S) ->
|
||||
- inet:setopts
|
||||
- (S,
|
||||
- [{active, true},
|
||||
- {deliver, port},
|
||||
- {packet, 4},
|
||||
- nodelay()])
|
||||
- end,
|
||||
- f_getll = fun inet:getll/1,
|
||||
- f_address =
|
||||
- fun(_,_) ->
|
||||
- #net_address {
|
||||
- address = {Ip,TcpPort},
|
||||
- host = Address,
|
||||
- protocol = tcp,
|
||||
- family = inet6}
|
||||
- end,
|
||||
- mf_tick = fun ?MODULE:tick/1,
|
||||
- mf_getstat = fun ?MODULE:getstat/1,
|
||||
- request_type = Type
|
||||
- },
|
||||
- dist_util:handshake_we_started(HSData);
|
||||
- _ ->
|
||||
- %% Other Node may have closed since
|
||||
- %% port_please !
|
||||
- ?trace("other node (~p) "
|
||||
- "closed since port_please.~n",
|
||||
- [Node]),
|
||||
- ?shutdown(Node)
|
||||
- end;
|
||||
- _ ->
|
||||
- ?trace("port_please (~p) "
|
||||
- "failed.~n", [Node]),
|
||||
- ?shutdown(Node)
|
||||
- end;
|
||||
- __Other ->
|
||||
- ?trace("inet_getaddr(~p) "
|
||||
- "failed (~p).~n", [Node,__Other]),
|
||||
- ?shutdown(Node)
|
||||
- end.
|
||||
+ inet_tcp_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
|
||||
|
||||
%%
|
||||
%% Close a socket.
|
||||
%%
|
||||
close(Socket) ->
|
||||
inet6_tcp:close(Socket).
|
||||
-
|
||||
-
|
||||
-%% If Node is illegal terminate the connection setup!!
|
||||
-splitnode(Node, LongOrShortNames) ->
|
||||
- case split_node(atom_to_list(Node), $@, []) of
|
||||
- [Name|Tail] when Tail =/= [] ->
|
||||
- Host = lists:append(Tail),
|
||||
- case split_node(Host, $., []) of
|
||||
- [_] when LongOrShortNames =:= longnames ->
|
||||
- case inet_parse:ipv6strict_address(Host) of
|
||||
- {ok, _} ->
|
||||
- [Name, Host];
|
||||
- _ ->
|
||||
- error_msg("** System running to use "
|
||||
- "fully qualified "
|
||||
- "hostnames **~n"
|
||||
- "** Hostname ~s is illegal **~n",
|
||||
- [Host]),
|
||||
- ?shutdown(Node)
|
||||
- end;
|
||||
- L when length(L) > 1, LongOrShortNames =:= shortnames ->
|
||||
- error_msg("** System NOT running to use fully qualified "
|
||||
- "hostnames **~n"
|
||||
- "** Hostname ~s is illegal **~n",
|
||||
- [Host]),
|
||||
- ?shutdown(Node);
|
||||
- _ ->
|
||||
- [Name, Host]
|
||||
- end;
|
||||
- [_] ->
|
||||
- error_msg("** Nodename ~p illegal, no '@' character **~n",
|
||||
- [Node]),
|
||||
- ?shutdown(Node);
|
||||
- _ ->
|
||||
- error_msg("** Nodename ~p illegal **~n", [Node]),
|
||||
- ?shutdown(Node)
|
||||
- end.
|
||||
-
|
||||
-split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
|
||||
-split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
|
||||
-split_node([], _, Ack) -> [lists:reverse(Ack)].
|
||||
-
|
||||
-%% ------------------------------------------------------------
|
||||
-%% Fetch local information about a Socket.
|
||||
-%% ------------------------------------------------------------
|
||||
-get_tcp_address(Socket) ->
|
||||
- {ok, Address} = inet:sockname(Socket),
|
||||
- {ok, Host} = inet:gethostname(),
|
||||
- #net_address {
|
||||
- address = Address,
|
||||
- host = Host,
|
||||
- protocol = tcp,
|
||||
- family = inet6
|
||||
- }.
|
||||
-
|
||||
-%% ------------------------------------------------------------
|
||||
-%% Do only accept new connection attempts from nodes at our
|
||||
-%% own LAN, if the check_ip environment parameter is true.
|
||||
-%% ------------------------------------------------------------
|
||||
-check_ip(Socket) ->
|
||||
- case application:get_env(check_ip) of
|
||||
- {ok, true} ->
|
||||
- case get_ifs(Socket) of
|
||||
- {ok, IFs, IP} ->
|
||||
- check_ip(IFs, IP);
|
||||
- _ ->
|
||||
- ?shutdown(no_node)
|
||||
- end;
|
||||
- _ ->
|
||||
- true
|
||||
- end.
|
||||
-
|
||||
-get_ifs(Socket) ->
|
||||
- case inet:peername(Socket) of
|
||||
- {ok, {IP, _}} ->
|
||||
- case inet:getif(Socket) of
|
||||
- {ok, IFs} -> {ok, IFs, IP};
|
||||
- Error -> Error
|
||||
- end;
|
||||
- Error ->
|
||||
- Error
|
||||
- end.
|
||||
-
|
||||
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
|
||||
- case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
|
||||
- {M, M} -> true;
|
||||
- _ -> check_ip(IFs, PeerIP)
|
||||
- end;
|
||||
-check_ip([], PeerIP) ->
|
||||
- {false, PeerIP}.
|
||||
|
||||
-mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
|
||||
- {M1 band IP1,
|
||||
- M2 band IP2,
|
||||
- M3 band IP3,
|
||||
- M4 band IP4,
|
||||
- M5 band IP5,
|
||||
- M6 band IP6,
|
||||
- M7 band IP7,
|
||||
- M8 band IP8 }.
|
||||
-
|
||||
is_node_name(Node) when is_atom(Node) ->
|
||||
- case split_node(atom_to_list(Node), $@, []) of
|
||||
- [_,_Host] -> true;
|
||||
- _ -> false
|
||||
- end;
|
||||
-is_node_name(_Node) ->
|
||||
- false.
|
||||
-tick(Sock) ->
|
||||
- ?to_port(Sock,[],[force]).
|
||||
-getstat(Socket) ->
|
||||
- case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
|
||||
- {ok, Stat} ->
|
||||
- split_stat(Stat,0,0,0);
|
||||
- Error ->
|
||||
- Error
|
||||
- end.
|
||||
-
|
||||
-split_stat([{recv_cnt, R}|Stat], _, W, P) ->
|
||||
- split_stat(Stat, R, W, P);
|
||||
-split_stat([{send_cnt, W}|Stat], R, _, P) ->
|
||||
- split_stat(Stat, R, W, P);
|
||||
-split_stat([{send_pend, P}|Stat], R, W, _) ->
|
||||
- split_stat(Stat, R, W, P);
|
||||
-split_stat([], R, W, P) ->
|
||||
- {ok, R, W, P}.
|
||||
-
|
||||
+ inet_tcp_dist:is_node_name(Node).
|
||||
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
|
||||
index 4c2db16..71d35ca 100644
|
||||
--- a/lib/kernel/src/inet_tcp.erl
|
||||
+++ b/lib/kernel/src/inet_tcp.erl
|
||||
@@ -26,11 +26,25 @@
|
||||
-export([controlling_process/2]).
|
||||
-export([fdopen/2]).
|
||||
|
||||
+-export([family/0, mask/2, parse_address/1]).
|
||||
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
|
||||
|
||||
-
|
||||
-include("inet_int.hrl").
|
||||
|
||||
+%% my address family
|
||||
+family() -> inet.
|
||||
+
|
||||
+%% Apply netmask on address
|
||||
+mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
|
||||
+ {M1 band IP1,
|
||||
+ M2 band IP2,
|
||||
+ M3 band IP3,
|
||||
+ M4 band IP4}.
|
||||
+
|
||||
+%% Parse address string
|
||||
+parse_address(Host) ->
|
||||
+ inet_parse:ipv4strict_address(Host).
|
||||
+
|
||||
%% inet_tcp port lookup
|
||||
getserv(Port) when is_integer(Port) -> {ok, Port};
|
||||
getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
|
||||
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
|
||||
index 8005eff..0739cf3 100644
|
||||
--- a/lib/kernel/src/inet_tcp_dist.erl
|
||||
+++ b/lib/kernel/src/inet_tcp_dist.erl
|
||||
@@ -23,9 +23,13 @@
|
||||
-export([listen/1, accept/1, accept_connection/5,
|
||||
setup/5, close/1, select/1, is_node_name/1]).
|
||||
|
||||
+%% Generalized dist API
|
||||
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
|
||||
+ gen_setup/6, gen_select/2]).
|
||||
+
|
||||
%% internal exports
|
||||
|
||||
--export([accept_loop/2,do_accept/6,do_setup/6,getstat/1,tick/1]).
|
||||
+-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]).
|
||||
|
||||
-import(error_logger,[error_msg/2]).
|
||||
|
||||
@@ -33,15 +37,6 @@
|
||||
|
||||
|
||||
|
||||
--define(to_port(Socket, Data, Opts),
|
||||
- case inet_tcp:send(Socket, Data, Opts) of
|
||||
- {error, closed} ->
|
||||
- self() ! {tcp_closed, Socket},
|
||||
- {error, closed};
|
||||
- R ->
|
||||
- R
|
||||
- end).
|
||||
-
|
||||
|
||||
-include("dist.hrl").
|
||||
-include("dist_util.hrl").
|
||||
@@ -52,8 +47,15 @@
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
select(Node) ->
|
||||
+ gen_select(inet_tcp, Node).
|
||||
+
|
||||
+gen_select(Driver, Node) ->
|
||||
case split_node(atom_to_list(Node), $@, []) of
|
||||
- [_,_Host] -> true;
|
||||
+ [_, Host] ->
|
||||
+ case inet:getaddr(Host, Driver:family()) of
|
||||
+ {ok,_} -> true;
|
||||
+ _ -> false
|
||||
+ end;
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
@@ -63,9 +65,12 @@ select(Node) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
listen(Name) ->
|
||||
- case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of
|
||||
+ gen_listen(inet_tcp, Name).
|
||||
+
|
||||
+gen_listen(Driver, Name) ->
|
||||
+ case do_listen(Driver, [{active, false}, {packet,2}, {reuseaddr, true}]) of
|
||||
{ok, Socket} ->
|
||||
- TcpAddress = get_tcp_address(Socket),
|
||||
+ TcpAddress = get_tcp_address(Driver, Socket),
|
||||
{_,Port} = TcpAddress#net_address.address,
|
||||
case erl_epmd:register_node(Name, Port) of
|
||||
{ok, Creation} ->
|
||||
@@ -77,7 +82,7 @@ listen(Name) ->
|
||||
Error
|
||||
end.
|
||||
|
||||
-do_listen(Options0) ->
|
||||
+do_listen(Driver, Options) ->
|
||||
{First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
|
||||
{ok,N} when is_integer(N) ->
|
||||
case application:get_env(kernel,
|
||||
@@ -90,46 +95,60 @@ do_listen(Options0) ->
|
||||
_ ->
|
||||
{0,0}
|
||||
end,
|
||||
- Options = case application:get_env(kernel, inet_dist_use_interface) of
|
||||
- {ok, Ip} ->
|
||||
- [{ip, Ip} | Options0];
|
||||
- _ ->
|
||||
- Options0
|
||||
- end,
|
||||
- do_listen(First, Last, [{backlog,128}|Options]).
|
||||
-
|
||||
-do_listen(First,Last,_) when First > Last ->
|
||||
+ do_listen(Driver, First, Last, listen_options([{backlog,128}|Options])).
|
||||
+
|
||||
+do_listen(_Driver, First,Last,_) when First > Last ->
|
||||
{error,eaddrinuse};
|
||||
-do_listen(First,Last,Options) ->
|
||||
- case inet_tcp:listen(First, Options) of
|
||||
+do_listen(Driver, First,Last,Options) ->
|
||||
+ case Driver:listen(First, Options) of
|
||||
{error, eaddrinuse} ->
|
||||
- do_listen(First+1,Last,Options);
|
||||
+ do_listen(Driver, First+1,Last,Options);
|
||||
Other ->
|
||||
Other
|
||||
end.
|
||||
|
||||
+listen_options(Opts0) ->
|
||||
+ Opts1 =
|
||||
+ case application:get_env(kernel, inet_dist_use_interface) of
|
||||
+ {ok, Ip} ->
|
||||
+ [{ip, Ip} | Opts0];
|
||||
+ _ ->
|
||||
+ Opts0
|
||||
+ end,
|
||||
+ case application:get_env(kernel, inet_dist_listen_options) of
|
||||
+ {ok,ListenOpts} ->
|
||||
+ erlang:display({inet_dist_listen_options, ListenOpts}),
|
||||
+ ListenOpts ++ Opts1;
|
||||
+ _ ->
|
||||
+ Opts1
|
||||
+ end.
|
||||
+
|
||||
+
|
||||
%% ------------------------------------------------------------
|
||||
%% Accepts new connection attempts from other Erlang nodes.
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
accept(Listen) ->
|
||||
- spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
|
||||
+ gen_accept(inet_tcp, Listen).
|
||||
|
||||
-accept_loop(Kernel, Listen) ->
|
||||
- case inet_tcp:accept(Listen) of
|
||||
+gen_accept(Driver, Listen) ->
|
||||
+ spawn_opt(?MODULE, accept_loop, [Driver, self(), Listen], [link, {priority, max}]).
|
||||
+
|
||||
+accept_loop(Driver, Kernel, Listen) ->
|
||||
+ case Driver:accept(Listen) of
|
||||
{ok, Socket} ->
|
||||
- Kernel ! {accept,self(),Socket,inet,tcp},
|
||||
- controller(Kernel, Socket),
|
||||
- accept_loop(Kernel, Listen);
|
||||
+ Kernel ! {accept,self(),Socket,Driver:family(),tcp},
|
||||
+ _ = controller(Driver, Kernel, Socket),
|
||||
+ accept_loop(Driver, Kernel, Listen);
|
||||
Error ->
|
||||
exit(Error)
|
||||
end.
|
||||
|
||||
-controller(Kernel, Socket) ->
|
||||
+controller(Driver, Kernel, Socket) ->
|
||||
receive
|
||||
{Kernel, controller, Pid} ->
|
||||
flush_controller(Pid, Socket),
|
||||
- inet_tcp:controlling_process(Socket, Pid),
|
||||
+ Driver:controlling_process(Socket, Pid),
|
||||
flush_controller(Pid, Socket),
|
||||
Pid ! {self(), controller};
|
||||
{Kernel, unsupported_protocol} ->
|
||||
@@ -154,15 +173,18 @@ flush_controller(Pid, Socket) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
+ gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
|
||||
+
|
||||
+gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
spawn_opt(?MODULE, do_accept,
|
||||
- [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
|
||||
+ [Driver, self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
|
||||
[link, {priority, max}]).
|
||||
|
||||
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
+do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
receive
|
||||
{AcceptPid, controller} ->
|
||||
Timer = dist_util:start_timer(SetupTime),
|
||||
- case check_ip(Socket) of
|
||||
+ case check_ip(Driver, Socket) of
|
||||
true ->
|
||||
HSData = #hs_data{
|
||||
kernel_pid = Kernel,
|
||||
@@ -171,9 +193,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
timer = Timer,
|
||||
this_flags = 0,
|
||||
allowed = Allowed,
|
||||
- f_send = fun(S,D) -> inet_tcp:send(S,D) end,
|
||||
- f_recv = fun(S,N,T) -> inet_tcp:recv(S,N,T)
|
||||
- end,
|
||||
+ f_send = fun Driver:send/2,
|
||||
+ f_recv = fun Driver:recv/3,
|
||||
f_setopts_pre_nodeup =
|
||||
fun(S) ->
|
||||
inet:setopts(S,
|
||||
@@ -192,8 +213,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
|
||||
f_getll = fun(S) ->
|
||||
inet:getll(S)
|
||||
end,
|
||||
- f_address = fun get_remote_id/2,
|
||||
- mf_tick = fun ?MODULE:tick/1,
|
||||
+ f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end,
|
||||
+ mf_tick = fun(S) -> tick(Driver, S) end,
|
||||
mf_getstat = fun ?MODULE:getstat/1
|
||||
},
|
||||
dist_util:handshake_other_started(HSData);
|
||||
@@ -224,13 +245,13 @@ nodelay() ->
|
||||
%% ------------------------------------------------------------
|
||||
%% Get remote information about a Socket.
|
||||
%% ------------------------------------------------------------
|
||||
-get_remote_id(Socket, Node) ->
|
||||
+get_remote_id(Driver, Socket, Node) ->
|
||||
case inet:peername(Socket) of
|
||||
{ok,Address} ->
|
||||
case split_node(atom_to_list(Node), $@, []) of
|
||||
[_,Host] ->
|
||||
#net_address{address=Address,host=Host,
|
||||
- protocol=tcp,family=inet};
|
||||
+ protocol=tcp,family=Driver:family()};
|
||||
_ ->
|
||||
%% No '@' or more than one '@' in node name.
|
||||
?shutdown(no_node)
|
||||
@@ -245,14 +266,18 @@ get_remote_id(Socket, Node) ->
|
||||
%% ------------------------------------------------------------
|
||||
|
||||
setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
+ gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
|
||||
+
|
||||
+gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
|
||||
spawn_opt(?MODULE, do_setup,
|
||||
- [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
|
||||
+ [Driver, self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
|
||||
[link, {priority, max}]).
|
||||
|
||||
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
+do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
|
||||
?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]),
|
||||
- [Name, Address] = splitnode(Node, LongOrShortNames),
|
||||
- case inet:getaddr(Address, inet) of
|
||||
+ [Name, Address] = splitnode(Driver, Node, LongOrShortNames),
|
||||
+ AddressFamily = Driver:family(),
|
||||
+ case inet:getaddr(Address, AddressFamily) of
|
||||
{ok, Ip} ->
|
||||
Timer = dist_util:start_timer(SetupTime),
|
||||
case erl_epmd:port_please(Name, Ip) of
|
||||
@@ -260,9 +285,11 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
?trace("port_please(~p) -> version ~p~n",
|
||||
[Node,Version]),
|
||||
dist_util:reset_timer(Timer),
|
||||
- case inet_tcp:connect(Ip, TcpPort,
|
||||
- [{active, false},
|
||||
- {packet,2}]) of
|
||||
+ case
|
||||
+ Driver:connect(
|
||||
+ Ip, TcpPort,
|
||||
+ connect_options([{active, false}, {packet, 2}]))
|
||||
+ of
|
||||
{ok, Socket} ->
|
||||
HSData = #hs_data{
|
||||
kernel_pid = Kernel,
|
||||
@@ -272,8 +299,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
timer = Timer,
|
||||
this_flags = 0,
|
||||
other_version = Version,
|
||||
- f_send = fun inet_tcp:send/2,
|
||||
- f_recv = fun inet_tcp:recv/3,
|
||||
+ f_send = fun Driver:send/2,
|
||||
+ f_recv = fun Driver:recv/3,
|
||||
f_setopts_pre_nodeup =
|
||||
fun(S) ->
|
||||
inet:setopts
|
||||
@@ -298,9 +325,9 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
address = {Ip,TcpPort},
|
||||
host = Address,
|
||||
protocol = tcp,
|
||||
- family = inet}
|
||||
+ family = AddressFamily}
|
||||
end,
|
||||
- mf_tick = fun ?MODULE:tick/1,
|
||||
+ mf_tick = fun(S) -> tick(Driver, S) end,
|
||||
mf_getstat = fun ?MODULE:getstat/1,
|
||||
request_type = Type
|
||||
},
|
||||
@@ -324,6 +351,15 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
|
||||
?shutdown(Node)
|
||||
end.
|
||||
|
||||
+connect_options(Opts) ->
|
||||
+ case application:get_env(kernel, inet_dist_connect_options) of
|
||||
+ {ok,ConnectOpts} ->
|
||||
+ erlang:display({inet_dist_connect_options, ConnectOpts}),
|
||||
+ ConnectOpts ++ Opts;
|
||||
+ _ ->
|
||||
+ Opts
|
||||
+ end.
|
||||
+
|
||||
%%
|
||||
%% Close a socket.
|
||||
%%
|
||||
@@ -332,18 +368,23 @@ close(Socket) ->
|
||||
|
||||
|
||||
%% If Node is illegal terminate the connection setup!!
|
||||
-splitnode(Node, LongOrShortNames) ->
|
||||
+splitnode(Driver, Node, LongOrShortNames) ->
|
||||
case split_node(atom_to_list(Node), $@, []) of
|
||||
[Name|Tail] when Tail =/= [] ->
|
||||
Host = lists:append(Tail),
|
||||
case split_node(Host, $., []) of
|
||||
[_] when LongOrShortNames =:= longnames ->
|
||||
- error_msg("** System running to use "
|
||||
- "fully qualified "
|
||||
- "hostnames **~n"
|
||||
- "** Hostname ~s is illegal **~n",
|
||||
- [Host]),
|
||||
- ?shutdown(Node);
|
||||
+ case Driver:parse_address(Host) of
|
||||
+ {ok, _} ->
|
||||
+ [Name, Host];
|
||||
+ _ ->
|
||||
+ error_msg("** System running to use "
|
||||
+ "fully qualified "
|
||||
+ "hostnames **~n"
|
||||
+ "** Hostname ~s is illegal **~n",
|
||||
+ [Host]),
|
||||
+ ?shutdown(Node)
|
||||
+ end;
|
||||
L when length(L) > 1, LongOrShortNames =:= shortnames ->
|
||||
error_msg("** System NOT running to use fully qualified "
|
||||
"hostnames **~n"
|
||||
@@ -369,26 +410,26 @@ split_node([], _, Ack) -> [lists:reverse(Ack)].
|
||||
%% ------------------------------------------------------------
|
||||
%% Fetch local information about a Socket.
|
||||
%% ------------------------------------------------------------
|
||||
-get_tcp_address(Socket) ->
|
||||
+get_tcp_address(Driver, Socket) ->
|
||||
{ok, Address} = inet:sockname(Socket),
|
||||
{ok, Host} = inet:gethostname(),
|
||||
#net_address {
|
||||
address = Address,
|
||||
host = Host,
|
||||
protocol = tcp,
|
||||
- family = inet
|
||||
+ family = Driver:family()
|
||||
}.
|
||||
|
||||
%% ------------------------------------------------------------
|
||||
%% Do only accept new connection attempts from nodes at our
|
||||
%% own LAN, if the check_ip environment parameter is true.
|
||||
%% ------------------------------------------------------------
|
||||
-check_ip(Socket) ->
|
||||
+check_ip(Driver, Socket) ->
|
||||
case application:get_env(check_ip) of
|
||||
{ok, true} ->
|
||||
case get_ifs(Socket) of
|
||||
{ok, IFs, IP} ->
|
||||
- check_ip(IFs, IP);
|
||||
+ check_ip(Driver, IFs, IP);
|
||||
_ ->
|
||||
?shutdown(no_node)
|
||||
end;
|
||||
@@ -407,20 +448,14 @@ get_ifs(Socket) ->
|
||||
Error
|
||||
end.
|
||||
|
||||
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
|
||||
- case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
|
||||
+check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) ->
|
||||
+ case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of
|
||||
{M, M} -> true;
|
||||
- _ -> check_ip(IFs, PeerIP)
|
||||
+ _ -> check_ip(Driver, IFs, PeerIP)
|
||||
end;
|
||||
-check_ip([], PeerIP) ->
|
||||
+check_ip(_Driver, [], PeerIP) ->
|
||||
{false, PeerIP}.
|
||||
|
||||
-mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
|
||||
- {M1 band IP1,
|
||||
- M2 band IP2,
|
||||
- M3 band IP3,
|
||||
- M4 band IP4}.
|
||||
-
|
||||
is_node_name(Node) when is_atom(Node) ->
|
||||
case split_node(atom_to_list(Node), $@, []) of
|
||||
[_, _Host] -> true;
|
||||
@@ -429,8 +464,14 @@ is_node_name(Node) when is_atom(Node) ->
|
||||
is_node_name(_Node) ->
|
||||
false.
|
||||
|
||||
-tick(Sock) ->
|
||||
- ?to_port(Sock,[],[force]).
|
||||
+tick(Driver, Socket) ->
|
||||
+ case Driver:send(Socket, [], [force]) of
|
||||
+ {error, closed} ->
|
||||
+ self() ! {tcp_closed, Socket},
|
||||
+ {error, closed};
|
||||
+ R ->
|
||||
+ R
|
||||
+ end.
|
||||
|
||||
getstat(Socket) ->
|
||||
case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
|
||||
737
otp-0023-epmd-support-IPv6-node-registration.patch
Normal file
737
otp-0023-epmd-support-IPv6-node-registration.patch
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
From: Michael Santos <michael.santos@gmail.com>
|
||||
Date: Sun, 18 Oct 2015 16:20:37 -0400
|
||||
Subject: [PATCH] epmd: support IPv6 node registration
|
||||
|
||||
Allow IPv6 nodes to register with and query epmd. On systems with
|
||||
IPv6 support:
|
||||
|
||||
* epmd listens on both the IPv4 and IPv6 ANY or loopback sockets
|
||||
|
||||
* the epmd cli client connects to epmd over the IPv6 loopback
|
||||
|
||||
* distributed nodes started with "-proto_dist inet6_tcp" will register
|
||||
with epmd over IPv6
|
||||
|
||||
To work on IPv6 capable systems that have IPv6 support disabled,
|
||||
epmd ignores errors opening the socket if the protocol is not
|
||||
supported. Similarly, the epmd client will fall back to IPv4 if the IPv6
|
||||
socket is not available.
|
||||
|
||||
Update the minimum supported version of Windows to Windows Vista to
|
||||
support IPv6.
|
||||
|
||||
diff --git a/erts/configure.in b/erts/configure.in
|
||||
index d9bc1ec..756f3cb 100644
|
||||
--- a/erts/configure.in
|
||||
+++ b/erts/configure.in
|
||||
@@ -424,7 +424,7 @@ case $host_os in
|
||||
win32)
|
||||
# The ethread library requires _WIN32_WINNT of at least 0x0403.
|
||||
# -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS.
|
||||
- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501"
|
||||
+ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
|
||||
;;
|
||||
darwin*)
|
||||
CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE"
|
||||
diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
|
||||
index 3e70054..3c9313e 100644
|
||||
--- a/erts/doc/src/epmd.xml
|
||||
+++ b/erts/doc/src/epmd.xml
|
||||
@@ -36,7 +36,7 @@
|
||||
<comsummary>
|
||||
<p>Erlang Port Mapper Daemon</p>
|
||||
<taglist>
|
||||
- <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag>
|
||||
+ <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-address Addresses] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag>
|
||||
<item>
|
||||
<p>Starts the port mapper daemon</p>
|
||||
</item>
|
||||
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
|
||||
index 528a2d9..0b8f821 100644
|
||||
--- a/erts/doc/src/erl.xml
|
||||
+++ b/erts/doc/src/erl.xml
|
||||
@@ -381,6 +381,33 @@
|
||||
similar to <c><![CDATA[code:add_pathsz/1]]></c>. See
|
||||
<seealso marker="kernel:code">code(3)</seealso>.</p>
|
||||
</item>
|
||||
+ <tag><c><![CDATA[-path Dir1 Dir2 ...]]></c></tag>
|
||||
+ <item>
|
||||
+ <p>Replaces the path specified in the boot script. See
|
||||
+ <seealso marker="sasl:script">script(4)</seealso>.</p>
|
||||
+ </item>
|
||||
+ <tag><c><![CDATA[-proto_dist Proto]]></c></tag>
|
||||
+ <item>
|
||||
+ <p>Specify a protocol for Erlang distribution.</p>
|
||||
+ <taglist>
|
||||
+ <tag><c>inet_tcp</c></tag>
|
||||
+ <item>
|
||||
+ <p>TCP over IPv4 (the default)</p>
|
||||
+ </item>
|
||||
+ <tag><c>inet_tls</c></tag>
|
||||
+ <item>
|
||||
+ <p>distribution over TLS/SSL</p>
|
||||
+ </item>
|
||||
+ <tag><c>inet6_tcp</c></tag>
|
||||
+ <item>
|
||||
+ <p>TCP over IPv6</p>
|
||||
+ </item>
|
||||
+ </taglist>
|
||||
+ <p>For example, to start up IPv6 distributed nodes:</p>
|
||||
+<pre>
|
||||
+% <input>erl -name test@ipv6node.example.com -proto_dist inet6_tcp</input>
|
||||
+</pre>
|
||||
+ </item>
|
||||
<tag><c><![CDATA[-remsh Node]]></c></tag>
|
||||
<item>
|
||||
<p>Starts Erlang with a remote shell connected to <c><![CDATA[Node]]></c>.</p>
|
||||
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
|
||||
index 1757fa9..ebae0a5 100644
|
||||
--- a/erts/epmd/src/epmd.c
|
||||
+++ b/erts/epmd/src/epmd.c
|
||||
@@ -342,7 +342,7 @@ static void run_daemon(EpmdVars *g)
|
||||
for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */
|
||||
close(fd);
|
||||
/* Syslog on linux will try to write to whatever if we dont
|
||||
- inform it of that the log is closed. */
|
||||
+ inform it that the log is closed. */
|
||||
closelog();
|
||||
|
||||
/* These chouldn't be needed but for safety... */
|
||||
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
|
||||
index 8817bde..ea7dac7 100644
|
||||
--- a/erts/epmd/src/epmd_cli.c
|
||||
+++ b/erts/epmd/src/epmd_cli.c
|
||||
@@ -135,19 +135,33 @@ void epmd_call(EpmdVars *g,int what)
|
||||
static int conn_to_epmd(EpmdVars *g)
|
||||
{
|
||||
struct EPMD_SOCKADDR_IN address;
|
||||
+ size_t salen = 0;
|
||||
int connect_sock;
|
||||
-
|
||||
- connect_sock = socket(FAMILY, SOCK_STREAM, 0);
|
||||
- if (connect_sock<0)
|
||||
- goto error;
|
||||
+ unsigned short sport = g->port;
|
||||
+
|
||||
+#if defined(EPMD6)
|
||||
+ SET_ADDR6(address, in6addr_loopback, sport);
|
||||
+ salen = sizeof(struct sockaddr_in6);
|
||||
+
|
||||
+ connect_sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
+ if (connect_sock>=0) {
|
||||
+
|
||||
+ if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0)
|
||||
+ return connect_sock;
|
||||
|
||||
- { /* store port number in unsigned short */
|
||||
- unsigned short sport = g->port;
|
||||
- SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport);
|
||||
+ close(connect_sock);
|
||||
}
|
||||
+#endif
|
||||
+ SET_ADDR(address, htonl(INADDR_LOOPBACK), sport);
|
||||
+ salen = sizeof(struct sockaddr_in);
|
||||
|
||||
- if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0)
|
||||
+ connect_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
+ if (connect_sock<0)
|
||||
goto error;
|
||||
+
|
||||
+ if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0)
|
||||
+ goto error;
|
||||
+
|
||||
return connect_sock;
|
||||
|
||||
error:
|
||||
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
|
||||
index 363923e..c6d9173 100644
|
||||
--- a/erts/epmd/src/epmd_int.h
|
||||
+++ b/erts/epmd/src/epmd_int.h
|
||||
@@ -47,6 +47,7 @@
|
||||
# ifndef WINDOWS_H_INCLUDES_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
# endif
|
||||
+# include <ws2tcpip.h>
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#endif
|
||||
@@ -114,6 +115,10 @@
|
||||
# include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
+#if defined(HAVE_IN6) && defined(AF_INET6) && defined(HAVE_INET_PTON)
|
||||
+# define EPMD6
|
||||
+#endif
|
||||
+
|
||||
/* ************************************************************************ */
|
||||
/* Replace some functions by others by making the function name a macro */
|
||||
|
||||
@@ -167,33 +172,53 @@
|
||||
/* ************************************************************************ */
|
||||
/* Macros that let us use IPv6 */
|
||||
|
||||
-#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6)
|
||||
+#if HAVE_IN6
|
||||
+# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY
|
||||
+# if HAVE_DECL_IN6ADDR_ANY_INIT
|
||||
+static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } };
|
||||
+# else
|
||||
+static const struct in6_addr in6addr_any =
|
||||
+ { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
|
||||
+# endif /* HAVE_IN6ADDR_ANY_INIT */
|
||||
+# endif /* ! HAVE_DECL_IN6ADDR_ANY */
|
||||
+
|
||||
+# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK
|
||||
+# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT
|
||||
+static const struct in6_addr in6addr_loopback =
|
||||
+ { { IN6ADDR_LOOPBACK_INIT } };
|
||||
+# else
|
||||
+static const struct in6_addr in6addr_loopback =
|
||||
+ { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
|
||||
+# endif /* HAVE_IN6ADDR_LOOPBACK_INIT */
|
||||
+# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */
|
||||
+#endif /* HAVE_IN6 */
|
||||
+
|
||||
+#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
|
||||
+
|
||||
+#if defined(EPMD6)
|
||||
|
||||
-#define EPMD_SOCKADDR_IN sockaddr_in6
|
||||
-#define EPMD_IN_ADDR in6_addr
|
||||
-#define EPMD_S_ADDR s6_addr
|
||||
-#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr
|
||||
-#define EPMD_ADDR_ANY in6addr_any.s6_addr
|
||||
+#define EPMD_SOCKADDR_IN sockaddr_storage
|
||||
#define FAMILY AF_INET6
|
||||
|
||||
-#define SET_ADDR(dst, addr, port) do { \
|
||||
- memset((char*)&(dst), 0, sizeof(dst)); \
|
||||
- memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \
|
||||
- (dst).sin6_family = AF_INET6; \
|
||||
- (dst).sin6_flowinfo = 0; \
|
||||
- (dst).sin6_port = htons(port); \
|
||||
+#define SET_ADDR6(dst, addr, port) do { \
|
||||
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \
|
||||
+ memset(sa, 0, sizeof(dst)); \
|
||||
+ sa->sin6_family = AF_INET6; \
|
||||
+ sa->sin6_addr = (addr); \
|
||||
+ sa->sin6_port = htons(port); \
|
||||
} while(0)
|
||||
|
||||
-#define IS_ADDR_LOOPBACK(addr) \
|
||||
- (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0)
|
||||
+#define SET_ADDR(dst, addr, port) do { \
|
||||
+ struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \
|
||||
+ memset(sa, 0, sizeof(dst)); \
|
||||
+ sa->sin_family = AF_INET; \
|
||||
+ sa->sin_addr.s_addr = (addr); \
|
||||
+ sa->sin_port = htons(port); \
|
||||
+ } while(0)
|
||||
|
||||
#else /* Not IP v6 */
|
||||
|
||||
#define EPMD_SOCKADDR_IN sockaddr_in
|
||||
-#define EPMD_IN_ADDR in_addr
|
||||
-#define EPMD_S_ADDR s_addr
|
||||
-#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK)
|
||||
-#define EPMD_ADDR_ANY htonl(INADDR_ANY)
|
||||
#define FAMILY AF_INET
|
||||
|
||||
#define SET_ADDR(dst, addr, port) do { \
|
||||
@@ -203,8 +228,6 @@
|
||||
(dst).sin_port = htons(port); \
|
||||
} while(0)
|
||||
|
||||
-#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK))
|
||||
-
|
||||
#endif /* Not IP v6 */
|
||||
|
||||
/* ************************************************************************ */
|
||||
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
|
||||
index 78524a6..28e30d4 100644
|
||||
--- a/erts/epmd/src/epmd_srv.c
|
||||
+++ b/erts/epmd/src/epmd_srv.c
|
||||
@@ -70,6 +70,7 @@ static time_t current_time(EpmdVars*);
|
||||
|
||||
static Connection *conn_init(EpmdVars*);
|
||||
static int conn_open(EpmdVars*,int);
|
||||
+static int conn_local_peer_check(EpmdVars*, int);
|
||||
static int conn_close_fd(EpmdVars*,int);
|
||||
|
||||
static void node_init(EpmdVars*);
|
||||
@@ -200,10 +201,11 @@ void run(EpmdVars *g)
|
||||
{
|
||||
struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS];
|
||||
int listensock[MAX_LISTEN_SOCKETS];
|
||||
- int num_sockets;
|
||||
+ int num_sockets = 0;
|
||||
int i;
|
||||
int opt;
|
||||
unsigned short sport = g->port;
|
||||
+ int bound = 0;
|
||||
|
||||
node_init(g);
|
||||
g->conn = conn_init(g);
|
||||
@@ -246,64 +248,82 @@ void run(EpmdVars *g)
|
||||
if (g->addresses != NULL && /* String contains non-separator characters if: */
|
||||
g->addresses[strspn(g->addresses," ,")] != '\000')
|
||||
{
|
||||
- char *tmp;
|
||||
- char *token;
|
||||
- int loopback_ok = 0;
|
||||
+ char *tmp = NULL;
|
||||
+ char *token = NULL;
|
||||
+
|
||||
+ /* Always listen on the loopback. */
|
||||
+ SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport);
|
||||
+ num_sockets++;
|
||||
+#if defined(EPMD6)
|
||||
+ SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport);
|
||||
+ num_sockets++;
|
||||
+#endif
|
||||
|
||||
- if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL)
|
||||
+ if ((tmp = strdup(g->addresses)) == NULL)
|
||||
{
|
||||
dbg_perror(g,"cannot allocate memory");
|
||||
epmd_cleanup_exit(g,1);
|
||||
}
|
||||
- strcpy(tmp,g->addresses);
|
||||
|
||||
- for(token = strtok(tmp,", "), num_sockets = 0;
|
||||
+ for(token = strtok(tmp,", ");
|
||||
token != NULL;
|
||||
- token = strtok(NULL,", "), num_sockets++)
|
||||
+ token = strtok(NULL,", "))
|
||||
{
|
||||
- struct EPMD_IN_ADDR addr;
|
||||
-#ifdef HAVE_INET_PTON
|
||||
- int ret;
|
||||
+ struct in_addr addr;
|
||||
+#if defined(EPMD6)
|
||||
+ struct in6_addr addr6;
|
||||
+ struct sockaddr_storage *sa = &iserv_addr[num_sockets];
|
||||
|
||||
- if ((ret = inet_pton(FAMILY,token,&addr)) == -1)
|
||||
+ if (inet_pton(AF_INET6,token,&addr6) == 1)
|
||||
{
|
||||
- dbg_perror(g,"cannot convert IP address to network format");
|
||||
- epmd_cleanup_exit(g,1);
|
||||
+ SET_ADDR6(iserv_addr[num_sockets],addr6,sport);
|
||||
+ }
|
||||
+ else if (inet_pton(AF_INET,token,&addr) == 1)
|
||||
+ {
|
||||
+ SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
|
||||
+ }
|
||||
+ else
|
||||
+#else
|
||||
+ if ((addr.s_addr = inet_addr(token)) != INADDR_NONE)
|
||||
+ {
|
||||
+ SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport);
|
||||
}
|
||||
- else if (ret == 0)
|
||||
-#elif !defined(EPMD6)
|
||||
- if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE)
|
||||
+ else
|
||||
#endif
|
||||
{
|
||||
dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token);
|
||||
epmd_cleanup_exit(g,1);
|
||||
}
|
||||
|
||||
+#if defined(EPMD6)
|
||||
+ if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6))
|
||||
+ continue;
|
||||
+
|
||||
+ if (sa->ss_family == AF_INET)
|
||||
+#endif
|
||||
if (IS_ADDR_LOOPBACK(addr))
|
||||
- loopback_ok = 1;
|
||||
+ continue;
|
||||
|
||||
- if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1)
|
||||
+ num_sockets++;
|
||||
+
|
||||
+ if (num_sockets >= MAX_LISTEN_SOCKETS)
|
||||
{
|
||||
dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses",
|
||||
MAX_LISTEN_SOCKETS);
|
||||
epmd_cleanup_exit(g,1);
|
||||
}
|
||||
-
|
||||
- SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport);
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
-
|
||||
- if (!loopback_ok)
|
||||
- {
|
||||
- SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport);
|
||||
- num_sockets++;
|
||||
- }
|
||||
}
|
||||
else
|
||||
{
|
||||
- SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport);
|
||||
- num_sockets = 1;
|
||||
+ SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport);
|
||||
+ num_sockets++;
|
||||
+#if defined(EPMD6)
|
||||
+ SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport);
|
||||
+ num_sockets++;
|
||||
+#endif
|
||||
}
|
||||
#ifdef HAVE_SYSTEMD_SD_DAEMON_H
|
||||
}
|
||||
@@ -334,13 +354,39 @@ void run(EpmdVars *g)
|
||||
#endif
|
||||
for (i = 0; i < num_sockets; i++)
|
||||
{
|
||||
- if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0)
|
||||
+ struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i];
|
||||
+#if defined(EPMD6)
|
||||
+ size_t salen = (sa->sa_family == AF_INET6 ?
|
||||
+ sizeof(struct sockaddr_in6) :
|
||||
+ sizeof(struct sockaddr_in));
|
||||
+#else
|
||||
+ size_t salen = sizeof(struct sockaddr_in);
|
||||
+#endif
|
||||
+
|
||||
+ if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0)
|
||||
{
|
||||
- dbg_perror(g,"error opening stream socket");
|
||||
+ switch (errno) {
|
||||
+ case EAFNOSUPPORT:
|
||||
+ case EPROTONOSUPPORT:
|
||||
+ continue;
|
||||
+ default:
|
||||
+ dbg_perror(g,"error opening stream socket");
|
||||
+ epmd_cleanup_exit(g,1);
|
||||
+ }
|
||||
+ }
|
||||
+ g->listenfd[bound++] = listensock[i];
|
||||
+
|
||||
+#if HAVE_DECL_IPV6_V6ONLY
|
||||
+ opt = 1;
|
||||
+ if (sa->sa_family == AF_INET6 &&
|
||||
+ setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt,
|
||||
+ sizeof(opt)) <0)
|
||||
+ {
|
||||
+ dbg_perror(g,"can't set IPv6 only socket option");
|
||||
epmd_cleanup_exit(g,1);
|
||||
}
|
||||
- g->listenfd[i] = listensock[i];
|
||||
-
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Note that we must not enable the SO_REUSEADDR on Windows,
|
||||
* because addresses will be reused even if they are still in use.
|
||||
@@ -372,8 +418,7 @@ void run(EpmdVars *g)
|
||||
dbg_perror(g,"failed to set non-blocking mode of listening socket %d",
|
||||
listensock[i]);
|
||||
|
||||
- if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i],
|
||||
- sizeof(iserv_addr[i])) < 0)
|
||||
+ if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0)
|
||||
{
|
||||
if (errno == EADDRINUSE)
|
||||
{
|
||||
@@ -394,6 +439,11 @@ void run(EpmdVars *g)
|
||||
}
|
||||
select_fd_set(g, listensock[i]);
|
||||
}
|
||||
+ if (bound == 0) {
|
||||
+ dbg_perror(g,"unable to bind any address");
|
||||
+ epmd_cleanup_exit(g,1);
|
||||
+ }
|
||||
+ num_sockets = bound;
|
||||
#ifdef HAVE_SYSTEMD_SD_DAEMON_H
|
||||
}
|
||||
sd_notifyf(0, "READY=1\n"
|
||||
@@ -438,8 +488,8 @@ void run(EpmdVars *g)
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sockets; i++)
|
||||
- if (FD_ISSET(listensock[i],&read_mask)) {
|
||||
- if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) {
|
||||
+ if (FD_ISSET(g->listenfd[i],&read_mask)) {
|
||||
+ if (do_accept(g, g->listenfd[i]) && g->active_conn < g->max_conn) {
|
||||
/*
|
||||
* The accept() succeeded, and we have at least one file
|
||||
* descriptor still free, which means that another accept()
|
||||
@@ -1001,15 +1051,6 @@ static int conn_open(EpmdVars *g,int fd)
|
||||
|
||||
for (i = 0; i < g->max_conn; i++) {
|
||||
if (g->conn[i].open == EPMD_FALSE) {
|
||||
- struct sockaddr_in si;
|
||||
- struct sockaddr_in di;
|
||||
-#ifdef HAVE_SOCKLEN_T
|
||||
- socklen_t st;
|
||||
-#else
|
||||
- int st;
|
||||
-#endif
|
||||
- st = sizeof(si);
|
||||
-
|
||||
g->active_conn++;
|
||||
s = &g->conn[i];
|
||||
|
||||
@@ -1020,20 +1061,7 @@ static int conn_open(EpmdVars *g,int fd)
|
||||
s->open = EPMD_TRUE;
|
||||
s->keep = EPMD_FALSE;
|
||||
|
||||
- /* Determine if connection is from localhost */
|
||||
- if (getpeername(s->fd,(struct sockaddr*) &si,&st) ||
|
||||
- st < sizeof(si)) {
|
||||
- /* Failure to get peername is regarded as non local host */
|
||||
- s->local_peer = EPMD_FALSE;
|
||||
- } else {
|
||||
- /* Only 127.x.x.x and connections from the host's IP address
|
||||
- allowed, no false positives */
|
||||
- s->local_peer =
|
||||
- (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) ==
|
||||
- 0x7F000000U) ||
|
||||
- (getsockname(s->fd,(struct sockaddr*) &di,&st) ?
|
||||
- EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr));
|
||||
- }
|
||||
+ s->local_peer = conn_local_peer_check(g, s->fd);
|
||||
dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" :
|
||||
"Non-local peer connected");
|
||||
|
||||
@@ -1041,7 +1069,7 @@ static int conn_open(EpmdVars *g,int fd)
|
||||
s->got = 0;
|
||||
s->mod_time = current_time(g); /* Note activity */
|
||||
|
||||
- s->buf = (char *)malloc(INBUF_SIZE);
|
||||
+ s->buf = malloc(INBUF_SIZE);
|
||||
|
||||
if (s->buf == NULL) {
|
||||
dbg_printf(g,0,"epmd: Insufficient memory");
|
||||
@@ -1059,6 +1087,60 @@ static int conn_open(EpmdVars *g,int fd)
|
||||
return EPMD_FALSE;
|
||||
}
|
||||
|
||||
+static int conn_local_peer_check(EpmdVars *g, int fd)
|
||||
+{
|
||||
+ struct EPMD_SOCKADDR_IN si;
|
||||
+ struct EPMD_SOCKADDR_IN di;
|
||||
+
|
||||
+ struct sockaddr_in *si4 = (struct sockaddr_in *)&si;
|
||||
+ struct sockaddr_in *di4 = (struct sockaddr_in *)&di;
|
||||
+
|
||||
+#if defined(EPMD6)
|
||||
+ struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si;
|
||||
+ struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di;
|
||||
+#endif
|
||||
+
|
||||
+#ifdef HAVE_SOCKLEN_T
|
||||
+ socklen_t st;
|
||||
+#else
|
||||
+ int st;
|
||||
+#endif
|
||||
+
|
||||
+ st = sizeof(si);
|
||||
+
|
||||
+ /* Determine if connection is from localhost */
|
||||
+ if (getpeername(fd,(struct sockaddr*) &si,&st) ||
|
||||
+ st > sizeof(si)) {
|
||||
+ /* Failure to get peername is regarded as non local host */
|
||||
+ return EPMD_FALSE;
|
||||
+ }
|
||||
+
|
||||
+ /* Only 127.x.x.x and connections from the host's IP address
|
||||
+ allowed, no false positives */
|
||||
+#if defined(EPMD6)
|
||||
+ if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr)))
|
||||
+ return EPMD_TRUE;
|
||||
+
|
||||
+ if (si.ss_family == AF_INET)
|
||||
+#endif
|
||||
+ if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) ==
|
||||
+ 0x7F000000U)
|
||||
+ return EPMD_TRUE;
|
||||
+
|
||||
+ if (getsockname(fd,(struct sockaddr*) &di,&st))
|
||||
+ return EPMD_FALSE;
|
||||
+
|
||||
+#if defined(EPMD6)
|
||||
+ if (si.ss_family == AF_INET6)
|
||||
+ return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr));
|
||||
+ if (si.ss_family == AF_INET)
|
||||
+#endif
|
||||
+ return si4->sin_addr.s_addr == di4->sin_addr.s_addr;
|
||||
+#if defined(EPMD6)
|
||||
+ return EPMD_FALSE;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static int conn_close_fd(EpmdVars *g,int fd)
|
||||
{
|
||||
int i;
|
||||
diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
|
||||
index cc24a55..8dfc21f 100644
|
||||
--- a/erts/epmd/test/epmd_SUITE.erl
|
||||
+++ b/erts/epmd/test/epmd_SUITE.erl
|
||||
@@ -42,6 +42,7 @@
|
||||
-export(
|
||||
[
|
||||
register_name/1,
|
||||
+ register_name_ipv6/1,
|
||||
register_names_1/1,
|
||||
register_names_2/1,
|
||||
register_duplicate_name/1,
|
||||
@@ -108,7 +109,8 @@
|
||||
suite() -> [{ct_hooks,[ts_install_cth]}].
|
||||
|
||||
all() ->
|
||||
- [register_name, register_names_1, register_names_2,
|
||||
+ [register_name, register_name_ipv6,
|
||||
+ register_names_1, register_names_2,
|
||||
register_duplicate_name, unicode_name, long_unicode_name,
|
||||
get_port_nr, slow_get_port_nr,
|
||||
unregister_others_name_1, unregister_others_name_2,
|
||||
@@ -165,6 +167,24 @@ register_name(Config) when is_list(Config) ->
|
||||
?line ok = close(Sock), % Unregister
|
||||
ok.
|
||||
|
||||
+register_name_ipv6(doc) ->
|
||||
+ ["Register a name over IPv6"];
|
||||
+register_name_ipv6(suite) ->
|
||||
+ [];
|
||||
+register_name_ipv6(Config) when is_list(Config) ->
|
||||
+ % Test if the host has an IPv6 loopback address
|
||||
+ Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]),
|
||||
+ case Res of
|
||||
+ {ok,LSock} ->
|
||||
+ gen_tcp:close(LSock),
|
||||
+ ?line ok = epmdrun(),
|
||||
+ ?line {ok,Sock} = register_node6("foobar6"),
|
||||
+ ?line ok = close(Sock), % Unregister
|
||||
+ ok;
|
||||
+ _Error ->
|
||||
+ {skip, "Host does not have an IPv6 loopback address"}
|
||||
+ end.
|
||||
+
|
||||
register_names_1(doc) ->
|
||||
["Register and unregister two nodes"];
|
||||
register_names_1(suite) ->
|
||||
@@ -238,13 +258,14 @@ register_node(Name) ->
|
||||
register_node(Name,Port) ->
|
||||
register_node_v2(Port,$M,0,5,5,Name,"").
|
||||
|
||||
+register_node6(Name) ->
|
||||
+ register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,"").
|
||||
+
|
||||
register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
|
||||
- Utf8Name = unicode:characters_to_binary(Name),
|
||||
- Req = [?EPMD_ALIVE2_REQ, put16(Port), NodeType, Prot,
|
||||
- put16(HVsn), put16(LVsn),
|
||||
- put16(size(Utf8Name)), binary_to_list(Utf8Name),
|
||||
- size16(Extra), Extra],
|
||||
- case send_req(Req) of
|
||||
+ register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra).
|
||||
+register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) ->
|
||||
+ Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra),
|
||||
+ case send_req(Req, Addr) of
|
||||
{ok,Sock} ->
|
||||
case recv(Sock,4) of
|
||||
{ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} ->
|
||||
@@ -1129,7 +1150,9 @@ send_direct(Sock, Bytes) ->
|
||||
end.
|
||||
|
||||
send_req(Req) ->
|
||||
- case connect() of
|
||||
+ send_req(Req, "localhost").
|
||||
+send_req(Req, Addr) ->
|
||||
+ case connect(Addr) of
|
||||
{ok,Sock} ->
|
||||
case send(Sock, [size16(Req), Req]) of
|
||||
ok ->
|
||||
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
|
||||
index d511f2e..99ee635 100644
|
||||
--- a/lib/erl_interface/configure.in
|
||||
+++ b/lib/erl_interface/configure.in
|
||||
@@ -250,7 +250,7 @@ case "$threads_disabled" in
|
||||
;;
|
||||
win32_threads)
|
||||
EI_THREADS="true"
|
||||
- THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500"
|
||||
+ THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
|
||||
;;
|
||||
pthread)
|
||||
EI_THREADS="true"
|
||||
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
|
||||
index 91af49f..21a3dec 100644
|
||||
--- a/lib/kernel/src/erl_epmd.erl
|
||||
+++ b/lib/kernel/src/erl_epmd.erl
|
||||
@@ -31,7 +31,7 @@
|
||||
%% External exports
|
||||
-export([start/0, start_link/0, stop/0, port_please/2,
|
||||
port_please/3, names/0, names/1,
|
||||
- register_node/2, open/0, open/1, open/2]).
|
||||
+ register_node/2, register_node/3, open/0, open/1, open/2]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
@@ -106,7 +106,9 @@ names1(HostName) ->
|
||||
|
||||
|
||||
register_node(Name, PortNo) ->
|
||||
- gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
|
||||
+ register_node(Name, PortNo, inet).
|
||||
+register_node(Name, PortNo, Family) ->
|
||||
+ gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_server
|
||||
@@ -124,10 +126,10 @@ init(_) ->
|
||||
-spec handle_call(calls(), term(), state()) ->
|
||||
{'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
|
||||
|
||||
-handle_call({register, Name, PortNo}, _From, State) ->
|
||||
+handle_call({register, Name, PortNo, Family}, _From, State) ->
|
||||
case State#state.socket of
|
||||
P when P < 0 ->
|
||||
- case do_register_node(Name, PortNo) of
|
||||
+ case do_register_node(Name, PortNo, Family) of
|
||||
{alive, Socket, Creation} ->
|
||||
S = State#state{socket = Socket,
|
||||
port_no = PortNo,
|
||||
@@ -210,8 +212,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
|
||||
close(Socket) ->
|
||||
gen_tcp:close(Socket).
|
||||
|
||||
-do_register_node(NodeName, TcpPort) ->
|
||||
- case open() of
|
||||
+do_register_node(NodeName, TcpPort, Family) ->
|
||||
+ Localhost = case Family of
|
||||
+ inet -> open({127,0,0,1});
|
||||
+ inet6 -> open({0,0,0,0,0,0,0,1})
|
||||
+ end,
|
||||
+ case Localhost of
|
||||
{ok, Socket} ->
|
||||
Name = to_string(NodeName),
|
||||
Extra = "",
|
||||
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
|
||||
index 3756786..be73888 100755
|
||||
--- a/lib/wx/configure.in
|
||||
+++ b/lib/wx/configure.in
|
||||
@@ -163,14 +163,14 @@ case $host_os in
|
||||
CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS"
|
||||
;;
|
||||
mingw32)
|
||||
- CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE"
|
||||
- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500"
|
||||
+ CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE"
|
||||
+ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
|
||||
AC_MSG_WARN([Reverting to 32-bit time_t])
|
||||
CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T"
|
||||
;;
|
||||
win32)
|
||||
- CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE"
|
||||
- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500"
|
||||
+ CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE"
|
||||
+ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
|
||||
;;
|
||||
*)
|
||||
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
|
||||
1028
otp-0024-Remove-unused-code-in-error-logger-handlers.patch
Normal file
1028
otp-0024-Remove-unused-code-in-error-logger-handlers.patch
Normal file
File diff suppressed because it is too large
Load diff
74
otp-0025-Teach-sasl_report-to-limit-crash-reports.patch
Normal file
74
otp-0025-Teach-sasl_report-to-limit-crash-reports.patch
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
|
||||
Date: Tue, 25 Aug 2015 15:20:23 +0200
|
||||
Subject: [PATCH] Teach sasl_report to limit crash reports
|
||||
|
||||
|
||||
diff --git a/lib/sasl/src/sasl_report.erl b/lib/sasl/src/sasl_report.erl
|
||||
index c3e6fed..aa84e4f 100644
|
||||
--- a/lib/sasl/src/sasl_report.erl
|
||||
+++ b/lib/sasl/src/sasl_report.erl
|
||||
@@ -61,27 +61,53 @@ write_report2(IO, Fd, Head, supervisor_report, Report) ->
|
||||
Context = sup_get(errorContext, Report),
|
||||
Reason = sup_get(reason, Report),
|
||||
Offender = sup_get(offender, Report),
|
||||
- FmtString = " Supervisor: ~p~n Context: ~p~n Reason: "
|
||||
- "~80.18p~n Offender: ~80.18p~n~n",
|
||||
- write_report_action(IO, Fd, Head ++ FmtString,
|
||||
- [Name,Context,Reason,Offender]);
|
||||
+ {FmtString,Args} = supervisor_format([Name,Context,Reason,Offender]),
|
||||
+ write_report_action(IO, Fd, Head, FmtString, Args);
|
||||
write_report2(IO, Fd, Head, progress, Report) ->
|
||||
Format = format_key_val(Report),
|
||||
- write_report_action(IO, Fd, Head ++ "~s", [Format]);
|
||||
+ write_report_action(IO, Fd, Head, "~s", [Format]);
|
||||
write_report2(IO, Fd, Head, crash_report, Report) ->
|
||||
- Format = proc_lib:format(Report),
|
||||
- write_report_action(IO, Fd, Head ++ "~s", [Format]).
|
||||
+ Depth = get_depth(),
|
||||
+ Format = proc_lib:format(Report, latin1, Depth),
|
||||
+ write_report_action(IO, Fd, Head, "~s", [Format]).
|
||||
+
|
||||
+supervisor_format(Args0) ->
|
||||
+ case get_depth() of
|
||||
+ unlimited ->
|
||||
+ {" Supervisor: ~p~n"
|
||||
+ " Context: ~p~n"
|
||||
+ " Reason: ~80.18p~n"
|
||||
+ " Offender: ~80.18p~n~n",
|
||||
+ Args0};
|
||||
+ Depth ->
|
||||
+ [A,B,C,D] = Args0,
|
||||
+ Args = [A,Depth,B,Depth,C,Depth,D,Depth],
|
||||
+ {" Supervisor: ~P~n"
|
||||
+ " Context: ~P~n"
|
||||
+ " Reason: ~80.18P~n"
|
||||
+ " Offender: ~80.18P~n~n",
|
||||
+ Args}
|
||||
+ end.
|
||||
|
||||
-write_report_action(io, Fd, Format, Args) ->
|
||||
- io:format(Fd, Format, Args);
|
||||
-write_report_action(io_lib, _Fd, Format, Args) ->
|
||||
- io_lib:format(Format, Args).
|
||||
+write_report_action(IO, Fd, Head, Format, Args) ->
|
||||
+ S = [Head|io_lib:format(Format, Args)],
|
||||
+ case IO of
|
||||
+ io -> io:put_chars(Fd, S);
|
||||
+ io_lib -> S
|
||||
+ end.
|
||||
|
||||
format_key_val([{Tag,Data}|Rep]) ->
|
||||
io_lib:format(" ~16w: ~p~n",[Tag,Data]) ++ format_key_val(Rep);
|
||||
format_key_val(_) ->
|
||||
[].
|
||||
|
||||
+get_depth() ->
|
||||
+ case application:get_env(kernel, error_logger_format_depth) of
|
||||
+ {ok, Depth} when is_integer(Depth) ->
|
||||
+ max(10, Depth);
|
||||
+ undefined ->
|
||||
+ unlimited
|
||||
+ end.
|
||||
|
||||
sup_get(Tag, Report) ->
|
||||
case lists:keysearch(Tag, 1, Report) of
|
||||
1064
otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch
Normal file
1064
otp-0026-Revert-Remove-unused-code-in-error-logger-handlers.patch
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,34 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Thu, 14 Jul 2016 17:51:16 +0300
|
||||
Subject: [PATCH] Respect -proto_dist switch while connection to EPMD
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
|
||||
index 21a3dec..0ba695c 100644
|
||||
--- a/lib/kernel/src/erl_epmd.erl
|
||||
+++ b/lib/kernel/src/erl_epmd.erl
|
||||
@@ -107,6 +107,10 @@ names1(HostName) ->
|
||||
|
||||
register_node(Name, PortNo) ->
|
||||
register_node(Name, PortNo, inet).
|
||||
+register_node(Name, PortNo, inet_tcp) ->
|
||||
+ register_node(Name, PortNo, inet);
|
||||
+register_node(Name, PortNo, inet6_tcp) ->
|
||||
+ register_node(Name, PortNo, inet6);
|
||||
register_node(Name, PortNo, Family) ->
|
||||
gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
|
||||
|
||||
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
|
||||
index 0739cf3..c64ddc8 100644
|
||||
--- a/lib/kernel/src/inet_tcp_dist.erl
|
||||
+++ b/lib/kernel/src/inet_tcp_dist.erl
|
||||
@@ -72,7 +72,7 @@ gen_listen(Driver, Name) ->
|
||||
{ok, Socket} ->
|
||||
TcpAddress = get_tcp_address(Driver, Socket),
|
||||
{_,Port} = TcpAddress#net_address.address,
|
||||
- case erl_epmd:register_node(Name, Port) of
|
||||
+ case erl_epmd:register_node(Name, Port, Driver) of
|
||||
{ok, Creation} ->
|
||||
{ok, {Socket, TcpAddress, Creation}};
|
||||
Error ->
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
From: Dan Gudmundsson <dgud@erlang.org>
|
||||
Date: Thu, 17 Mar 2016 10:23:41 +0100
|
||||
Subject: [PATCH] mnesia: Send mnesia_down messages to waiting transactions
|
||||
|
||||
Mnesia didn't forward mnesia_down to transactions which where already
|
||||
decided to be aborted, but that could lead to hanging transactions
|
||||
still waiting for messages from the node which had stopped.
|
||||
|
||||
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
|
||||
index 17af0ca..329192e 100644
|
||||
--- a/lib/mnesia/src/mnesia_tm.erl
|
||||
+++ b/lib/mnesia/src/mnesia_tm.erl
|
||||
@@ -1714,13 +1714,10 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
|
||||
?eval_debug_fun({?MODULE, commit_participant, undo_prepare},
|
||||
[{tid, Tid}]);
|
||||
|
||||
- {'EXIT', _, _} ->
|
||||
+ {'EXIT', _MnesiaTM, Reason} ->
|
||||
+ reply(Coord, {do_abort, Tid, self(), {bad_commit,Reason}}),
|
||||
mnesia_recover:log_decision(D#decision{outcome = aborted}),
|
||||
- ?eval_debug_fun({?MODULE, commit_participant, exit_log_abort},
|
||||
- [{tid, Tid}]),
|
||||
- mnesia_schema:undo_prepare_commit(Tid, C0),
|
||||
- ?eval_debug_fun({?MODULE, commit_participant, exit_undo_prepare},
|
||||
- [{tid, Tid}]);
|
||||
+ mnesia_schema:undo_prepare_commit(Tid, C0);
|
||||
|
||||
Msg ->
|
||||
verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n",
|
||||
@@ -2236,8 +2233,6 @@ reconfigure_coordinators(N, [{Tid, [Store | _]} | Coordinators]) ->
|
||||
true ->
|
||||
send_mnesia_down(Tid, Store, N)
|
||||
end;
|
||||
- aborted ->
|
||||
- ignore; % avoid spurious mnesia_down messages
|
||||
_ ->
|
||||
%% Tell the coordinator about the mnesia_down
|
||||
send_mnesia_down(Tid, Store, N)
|
||||
139
otp-0029-Fix-a-few-javadoc-errors.patch
Normal file
139
otp-0029-Fix-a-few-javadoc-errors.patch
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
From: Anthony Ramine <n.oxyde@gmail.com>
|
||||
Date: Sun, 8 Jun 2014 12:37:10 +0200
|
||||
Subject: [PATCH] Fix a few javadoc errors
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Reported-by: Boris Mühmer
|
||||
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
|
||||
index 9ba6a4a..7aa30ee 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractConnection.java
|
||||
@@ -266,7 +266,7 @@ public abstract class AbstractConnection extends Thread {
|
||||
*
|
||||
* @param dest
|
||||
* the Erlang PID of the remote process.
|
||||
- * @param msg
|
||||
+ * @param payload
|
||||
* the encoded message to send.
|
||||
*
|
||||
* @exception java.io.IOException
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
|
||||
index 8e8bd47..e7a9d10 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpConnection.java
|
||||
@@ -404,7 +404,7 @@ public class OtpConnection extends AbstractConnection {
|
||||
*
|
||||
* @param dest
|
||||
* the Erlang PID of the remote process.
|
||||
- * @param msg
|
||||
+ * @param payload
|
||||
* the encoded message to send.
|
||||
*
|
||||
* @exception java.io.IOException
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
|
||||
index 7e3e2a7..84b1355 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangLong.java
|
||||
@@ -51,8 +51,8 @@ public class OtpErlangLong extends OtpErlangObject implements Serializable,
|
||||
/**
|
||||
* Create an Erlang integer from the given value.
|
||||
*
|
||||
- * @param val
|
||||
- * the long value to use.
|
||||
+ * @param v
|
||||
+ * the big integer value to use.
|
||||
*/
|
||||
public OtpErlangLong(final BigInteger v) {
|
||||
if (v == null) {
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
|
||||
index fe81ce3..f75e435 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangPid.java
|
||||
@@ -162,7 +162,7 @@ public class OtpErlangPid extends OtpErlangObject implements Serializable,
|
||||
* Determine if two PIDs are equal. PIDs are equal if their components are
|
||||
* equal.
|
||||
*
|
||||
- * @param port
|
||||
+ * @param o
|
||||
* the other PID to compare to.
|
||||
*
|
||||
* @return true if the PIDs are equal, false otherwise.
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
|
||||
index 6766b52..a5e202c 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
|
||||
@@ -41,8 +41,6 @@ public class OtpErlangString extends OtpErlangObject implements Serializable,
|
||||
|
||||
/**
|
||||
* Create an Erlang string from a list of integers.
|
||||
- *
|
||||
- * @return an Erlang string with Unicode code units.
|
||||
*
|
||||
* @throws OtpErlangException
|
||||
* for non-proper and non-integer lists.
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
|
||||
index 0fd93b0..4a4a1e7 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
|
||||
@@ -69,6 +69,7 @@ package com.ericsson.otp.erlang;
|
||||
* notify other parties in a timely manner.
|
||||
* </p>
|
||||
*
|
||||
+ * <p>
|
||||
* When retrieving messages from a mailbox that has received an exit signal, an
|
||||
* {@link OtpErlangExit OtpErlangExit} exception will be raised. Note that the
|
||||
* exception is queued in the mailbox along with other messages, and will not be
|
||||
@@ -420,7 +421,6 @@ public class OtpMbox {
|
||||
|
||||
/**
|
||||
* Equivalent to <code>exit(new OtpErlangAtom(reason))</code>.
|
||||
- * </p>
|
||||
*
|
||||
* @see #exit(OtpErlangObject)
|
||||
*/
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMsg.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMsg.java
|
||||
index 6f507bf..31a5d0f 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMsg.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMsg.java
|
||||
@@ -30,14 +30,14 @@ package com.ericsson.otp.erlang;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
- * The header information that is available is as follows: <lu>
|
||||
+ * The header information that is available is as follows: <ul>
|
||||
* <li> a tag indicating the type of message
|
||||
* <li> the intended recipient of the message, either as a
|
||||
* {@link OtpErlangPid pid} or as a String, but never both.
|
||||
* <li> (sometimes) the sender of the message. Due to some eccentric
|
||||
* characteristics of the Erlang distribution protocol, not all messages have
|
||||
* information about the sending process. In particular, only messages whose tag
|
||||
- * is {@link OtpMsg#regSendTag regSendTag} contain sender information. </lu>
|
||||
+ * is {@link OtpMsg#regSendTag regSendTag} contain sender information. </ul>
|
||||
*
|
||||
* <p>
|
||||
* Message are sent using the Erlang external format (see separate
|
||||
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
|
||||
index 78f47aa..fd4eba3 100644
|
||||
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
|
||||
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
|
||||
@@ -202,7 +202,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
|
||||
/**
|
||||
* Write an array of bytes to the stream.
|
||||
*
|
||||
- * @param buf
|
||||
+ * @param bytes
|
||||
* the array of bytes to write.
|
||||
*
|
||||
*/
|
||||
@@ -637,7 +637,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
|
||||
* Write a positive short to the stream. The short is interpreted as a two's
|
||||
* complement unsigned short even if it is negative.
|
||||
*
|
||||
- * @param s
|
||||
+ * @param us
|
||||
* the short to use.
|
||||
*/
|
||||
public void write_ushort(final short us) {
|
||||
3
sources
3
sources
|
|
@ -1,4 +1 @@
|
|||
d27250e9ee98d6388e7f2e65379a0406 otp_src_R16B03-1.readme
|
||||
eff44490c9bbae3a5c5741bec2390ba3 otp_doc_html_R16B03-1.tar.gz
|
||||
39113c0d2515bdd8cd7e0f975a380122 otp_doc_man_R16B03-1.tar.gz
|
||||
e5ece977375197338c1b93b3d88514f8 otp_src_R16B03-1.tar.gz
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue