aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-05-31 10:58:19 +0200
committerMicael Karlberg <[email protected]>2018-09-18 13:01:37 +0200
commit63338250778d2caad08aa3180b372e5260f22aa7 (patch)
tree81b90d47c0f92e22fc2b656373defbc7b2b4229a
parent7ce277e9635830c6d5c56ba02e3346a6496dec09 (diff)
downloadotp-63338250778d2caad08aa3180b372e5260f22aa7.tar.gz
otp-63338250778d2caad08aa3180b372e5260f22aa7.tar.bz2
otp-63338250778d2caad08aa3180b372e5260f22aa7.zip
[socket-nif-doc] Add preliminary doc for socket
The doc now builds. Had to update the code (spec and types) to match. Though, te result is less then stellar. OTP-14831
-rw-r--r--erts/doc/src/Makefile6
-rw-r--r--erts/doc/src/ref_man.xml3
-rw-r--r--erts/doc/src/socket.xml308
-rw-r--r--erts/doc/src/specs.xml1
-rw-r--r--erts/emulator/nifs/common/socket_nif.c535
-rw-r--r--erts/preloaded/src/socket.erl152
6 files changed, 821 insertions, 184 deletions
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index 21aa3db864..1540344fde 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -52,7 +52,8 @@ XML_REF3_EFILES = \
erlang.xml \
erl_tracer.xml \
init.xml \
- zlib.xml
+ zlib.xml \
+ socket.xml
XML_REF3_FILES = \
driver_entry.xml \
@@ -63,7 +64,8 @@ XML_REF3_FILES = \
erlang.xml \
erts_alloc.xml \
init.xml \
- zlib.xml
+ zlib.xml \
+ socket.xml
XML_PART_FILES = \
part.xml
diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml
index 0617463a7b..da099dd5bb 100644
--- a/erts/doc/src/ref_man.xml
+++ b/erts/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,6 +35,7 @@
<xi:include href="erlang.xml"/>
<xi:include href="init.xml"/>
<xi:include href="zlib.xml"/>
+ <xi:include href="socket.xml"/>
<xi:include href="epmd.xml"/>
<xi:include href="erl.xml"/>
<xi:include href="erlc.xml"/>
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
new file mode 100644
index 0000000000..9b487172c5
--- /dev/null
+++ b/erts/doc/src/socket.xml
@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>socket</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>socket.xml</file>
+ </header>
+ <module>socket</module>
+ <modulesummary>Socket interface.</modulesummary>
+ <description>
+ <p>This module provides an API for the socket interface.
+ It is used to create, delete and manipulate sockets.</p>
+ </description>
+
+ <datatypes>
+ <datatype>
+ <name name="domain"/>
+ </datatype>
+ <datatype>
+ <name name="type"/>
+ </datatype>
+ <datatype>
+ <name name="protocol"/>
+ </datatype>
+ <datatype>
+ <name name="socket"/>
+ </datatype>
+ <datatype>
+ <name name="ip4_address"/>
+ </datatype>
+ <datatype>
+ <name name="ip6_address"/>
+ </datatype>
+ <datatype>
+ <name name="ip_address"/>
+ </datatype>
+ <datatype>
+ <name name="in4_sockaddr"/>
+ </datatype>
+ <datatype>
+ <name name="in6_sockaddr"/>
+ </datatype>
+ <datatype>
+ <name name="in_sockaddr"/>
+ </datatype>
+ <datatype>
+ <name name="port_number"/>
+ </datatype>
+ <datatype>
+ <name name="accept_flags"/>
+ </datatype>
+ <datatype>
+ <name name="accept_flag"/>
+ </datatype>
+ <datatype>
+ <name name="send_flags"/>
+ </datatype>
+ <datatype>
+ <name name="send_flag"/>
+ </datatype>
+ <datatype>
+ <name name="shutdown_how"/>
+ </datatype>
+ <datatype>
+ <name name="sockopt_level"/>
+ </datatype>
+ <datatype>
+ <name name="otp_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="ip_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="ipv6_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="tcp_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="udp_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="sctp_socket_option"/>
+ </datatype>
+ <datatype>
+ <name name="ip_tos_flag"/>
+ </datatype>
+ </datatypes>
+
+ <funcs>
+ <func>
+ <name name="accept" arity="1"/>
+ <name name="accept" arity="2"/>
+ <fsummary>Accept a connection on a socket.</fsummary>
+ <desc>
+ <p>Accept a connection on a socket.</p>
+ <p>This call is used with connection-based socket types
+ (stream or seqpacket). It extracs the first pending connection
+ request for the listen socket and returns the (newly) connected
+ socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="bind" arity="2"/>
+ <fsummary>Bind a name to a socket.</fsummary>
+ <desc>
+ <p>Bind a name to a socket.</p>
+ <p>When a socket is created
+ (with <seealso marker="#open"><c>open</c></seealso>),
+ it has no address assigned to it. <c>bind</c> assigns the
+ address specified by the <c>Addr</c> argument.</p>
+ <p>The rules used for name binding vary between domains.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="close" arity="1"/>
+ <fsummary>Close a socket.</fsummary>
+ <desc>
+ <p>Closes the socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="connect" arity="2"/>
+ <name name="connect" arity="3"/>
+ <fsummary>Initiate a connection on a socket.</fsummary>
+ <desc>
+ <p>This function connects the socket to the address
+ specied by the <c>Addr</c> argument.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="getopt" arity="3" clause_i="1"/>
+ <name name="getopt" arity="3" clause_i="2"/>
+ <name name="getopt" arity="3" clause_i="3"/>
+ <name name="getopt" arity="3" clause_i="4"/>
+ <name name="getopt" arity="3" clause_i="5"/>
+ <name name="getopt" arity="3" clause_i="6"/>
+ <name name="getopt" arity="3" clause_i="7"/>
+ <name name="getopt" arity="3" clause_i="8"/>
+ <fsummary>Get an option on a socket.</fsummary>
+ <desc>
+ <p>Get an option on a socket.</p>
+ <p>What properties are valid depend on what kind of socket
+ it is (<c>domain</c>, <c>type</c> and <c>protocol</c>).</p>
+ <p>When specifying <c>Level</c> as an integer, and therefor
+ using "native mode", it is *currently* up to the caller to
+ know how to interpret the result.</p>
+
+ <note><p>Not all options are valid on all platforms. That is,
+ even if "we" support an option, that does not mean that the
+ underlying OS does.</p></note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="listen" arity="1"/>
+ <name name="listen" arity="2"/>
+ <fsummary>Listen for connections on a socket.</fsummary>
+ <desc>
+ <p>Listen for connections on a socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="open" arity="2"/>
+ <name name="open" arity="3"/>
+ <name name="open" arity="4"/>
+ <fsummary>Create an endpoint for communication.</fsummary>
+ <desc>
+ <p>Creates an endpoint (socket) for communication.</p>
+ <p>For some types there is a default protocol, which will
+ be used if no protocol is specified: </p>
+ <taglist>
+ <tag><c>stream</c></tag>
+ <item>
+ <p><c>tcp</c></p>
+ </item>
+ <tag><c>dgram</c></tag>
+ <item>
+ <p><c>udp</c></p>
+ </item>
+ <tag><c>seqpacket</c></tag>
+ <item>
+ <p><c>sctp</c></p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="recv" arity="2"/>
+ <name name="recv" arity="3"/>
+ <name name="recv" arity="4"/>
+ <fsummary>Receive a message from a socket.</fsummary>
+ <desc>
+ <p>Receive a message from a socket.</p>
+ <p>There is a special case for the argument <c>Length</c>.
+ If it is set to zero (0), it means "give me everything you
+ currently have".</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="recvfrom" arity="1"/>
+ <name name="recvfrom" arity="2"/>
+ <name name="recvfrom" arity="3"/>
+ <name name="recvfrom" arity="4"/>
+ <fsummary>Receive a message from a socket.</fsummary>
+ <desc>
+ <p>Receive a message from a socket.</p>
+ <p>This function reads "messages", which means that regardless of
+ how much we want to read, it returns when we get a message.</p>
+ <p>The <c>MaxSize</c> argument basically defines the size of the
+ receive buffer. By setting the value to zero (0), the configured
+ size (setopt) is used.</p>
+ <p>It may be impossible to know what (buffer) size is appropriate
+ "in advance", and in those cases it may be convenient to use the
+ (recv) 'peek' flag. When this flag is provided the message is *not*
+ "consumed" from the underlying buffers, so another recvfrom call
+ is needed, possibly with a then adjusted buffer size.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="send" arity="2"/>
+ <name name="send" arity="3"/>
+ <name name="send" arity="4"/>
+ <fsummary>Send a message on a socket.</fsummary>
+ <desc>
+ <p>Send a message on a connected socket.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="sendto" arity="4"/>
+ <name name="sendto" arity="5"/>
+ <fsummary>Send a message on a socket.</fsummary>
+ <desc>
+ <p>Send a message on a socket, to the specified destination.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="setopt" arity="4" clause_i="1"/>
+ <name name="setopt" arity="4" clause_i="2"/>
+ <name name="setopt" arity="4" clause_i="3"/>
+ <name name="setopt" arity="4" clause_i="4"/>
+ <name name="setopt" arity="4" clause_i="5"/>
+ <name name="setopt" arity="4" clause_i="6"/>
+ <name name="setopt" arity="4" clause_i="7"/>
+ <fsummary>Set options on a socket.</fsummary>
+ <desc>
+ <p>Set options on a socket.</p>
+ <p>What properties are valid depend on what kind of socket
+ it is (<c>domain</c>, <c>type</c> and <c>protocol</c>).</p>
+
+ <note><p>Not all options are valid on all platforms. That is,
+ even if "we" support an option, that does not mean that the
+ underlying OS does.</p></note>
+
+ <note><p>Sockets are set 'non-blocking' when created, so this option
+ is *not* available (as it would adversely effect the Erlang VM
+ to set a socket 'blocking').</p></note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="shutdown" arity="2"/>
+ <fsummary>Shut down part of a full-duplex connection.</fsummary>
+ <desc>
+ <p>Shut down all or part of a full-duplex connection.</p>
+ </desc>
+ </func>
+
+ </funcs>
+</erlref>
+
diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml
index ed6be650e5..4f6951a44b 100644
--- a/erts/doc/src/specs.xml
+++ b/erts/doc/src/specs.xml
@@ -4,5 +4,6 @@
<xi:include href="../specs/specs_erlang.xml"/>
<xi:include href="../specs/specs_erl_tracer.xml"/>
<xi:include href="../specs/specs_init.xml"/>
+ <xi:include href="../specs/specs_socket.xml"/>
<xi:include href="../specs/specs_zlib.xml"/>
</specs>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index c63eff40ec..ed961d691d 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -23,6 +23,8 @@
*
*/
+#define STATIC_ERLANG_NIF 1
+
/* #include <stdio.h> */
/* #include <stdlib.h> */
/* #include <stdarg.h> */
@@ -425,6 +427,8 @@ typedef union {
if (enif_select((E), (FD), (M), (O), (P), (R)) < 0) \
return enif_make_badarg((E));
+#define COMPARE(A, B) enif_compare((A), (B))
+
#define IS_ATOM(E, TE) enif_is_atom((E), (TE))
#define IS_BIN(E, TE) enif_is_binary((E), (TE))
#define IS_NUM(E, TE) enif_is_number((E), (TE))
@@ -581,6 +585,7 @@ typedef struct {
unsigned int state;
SocketAddress remote;
+ unsigned int addrLen;
/* +++ Controller (owner) process +++ */
@@ -710,8 +715,8 @@ static ERL_NIF_TERM nif_open(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_bind(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[]);
+ int argc,
+ const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_connect(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
@@ -760,9 +765,11 @@ static ERL_NIF_TERM nif_finalize_connection(ErlNifEnv* env,
static ERL_NIF_TERM nif_finalize_close(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
+/*
static ERL_NIF_TERM nif_cancel(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
+*/
static ERL_NIF_TERM nopen(ErlNifEnv* env,
@@ -773,10 +780,8 @@ static ERL_NIF_TERM nopen(ErlNifEnv* env,
static ERL_NIF_TERM nbind(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM addr);
-static ERL_NIF_TERM nconnect(ErlNifEnv* env,
- SocketDescriptor* descP,
- const ERL_NIF_TERM* addr,
- int port);
+static ERL_NIF_TERM nconnect(ErlNifEnv* env,
+ SocketDescriptor* descP);
static ERL_NIF_TERM nlisten(ErlNifEnv* env,
SocketDescriptor* descP,
int backlog);
@@ -1156,6 +1161,43 @@ static ERL_NIF_TERM nfinalize_close(ErlNifEnv* env,
SocketDescriptor* descP);
+static BOOLEAN_T decode_in_sockaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eSockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+static BOOLEAN_T decode_in4_sockaddr(ErlNifEnv* env,
+ const ERL_NIF_TERM* eIn4SockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+static BOOLEAN_T decode_in4_sockaddr_atomaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+static BOOLEAN_T decode_in4_sockaddr_addr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+static BOOLEAN_T decode_in6_sockaddr(ErlNifEnv* env,
+ const ERL_NIF_TERM* eIn6SockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+static BOOLEAN_T decode_in6_sockaddr_atomaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ unsigned int flowInfo,
+ unsigned int scopeId,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
+/* Decode an in6_sockaddr where the address field is a tuple */
+static BOOLEAN_T decode_in6_sockaddr_addr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ unsigned int flowInfo,
+ unsigned int scopeId,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP);
static char* decode_laddress(ErlNifEnv* env,
int domain,
ERL_NIF_TERM localAddr,
@@ -1184,18 +1226,22 @@ static char* decode_address_atom(ErlNifEnv* env,
int port,
SocketAddress* localP,
unsigned int* addrLenP);
+/*
static char* decode_send_addr(ErlNifEnv* env,
int domain,
ERL_NIF_TERM addr,
int port,
SocketAddress** toAddrP,
unsigned int* addrLenP);
+*/
+/*
static char* decode_send_addr_tuple(ErlNifEnv* env,
int domain,
ERL_NIF_TERM addr,
int port,
SocketAddress* toAddrP,
unsigned int* addrLenP);
+*/
static void encode_address(ErlNifEnv* env,
SocketAddress* fromAddrP,
unsigned int fromAddrLen,
@@ -1278,11 +1324,15 @@ static ERL_NIF_TERM make_error(ErlNifEnv* env, ERL_NIF_TERM reason);
static ERL_NIF_TERM make_error1(ErlNifEnv* env, char* reason);
static ERL_NIF_TERM make_error2(ErlNifEnv* env, int err);
+/*
static char* send_msg_error_closed(ErlNifEnv* env,
ErlNifPid* pid);
+*/
+/*
static char* send_msg_error(ErlNifEnv* env,
ERL_NIF_TERM reason,
ErlNifPid* pid);
+*/
static char* send_msg_nif_abort(ErlNifEnv* env,
ERL_NIF_TERM ref,
ERL_NIF_TERM reason,
@@ -1335,22 +1385,26 @@ static const struct in6_addr in6addr_loopback =
/* *** String constants *** */
-static char str_close[] = "close";
-static char str_closed[] = "closed";
-static char str_closing[] = "closing";
-static char str_error[] = "error";
-static char str_false[] = "false";
-static char str_nif_abort[] = "nif_abort";
-static char str_ok[] = "ok";
-static char str_select[] = "select";
-static char str_timeout[] = "timeout";
-static char str_true[] = "true";
-static char str_undefined[] = "undefined";
-
-static char str_lowdelay[] = "lowdelay";
-static char str_throughput[] = "throughput";
-static char str_reliability[] = "reliability";
-static char str_mincost[] = "mincost";
+static char str_any[] = "any";
+static char str_close[] = "close";
+static char str_closed[] = "closed";
+static char str_closing[] = "closing";
+static char str_error[] = "error";
+static char str_false[] = "false";
+static char str_in4_sockaddr[] = "in4_sockaddr";
+static char str_in6_sockaddr[] = "in6_sockaddr";
+static char str_loopback[] = "loopback";
+static char str_nif_abort[] = "nif_abort";
+static char str_ok[] = "ok";
+static char str_select[] = "select";
+static char str_timeout[] = "timeout";
+static char str_true[] = "true";
+static char str_undefined[] = "undefined";
+
+static char str_lowdelay[] = "lowdelay";
+static char str_throughput[] = "throughput";
+static char str_reliability[] = "reliability";
+static char str_mincost[] = "mincost";
/* (special) error string constants */
static char str_eagain[] = "eagain";
@@ -1368,11 +1422,15 @@ static char str_exsend[] = "exsend"; // failed send
/* *** Atoms *** */
+static ERL_NIF_TERM atom_any;
static ERL_NIF_TERM atom_close;
static ERL_NIF_TERM atom_closed;
static ERL_NIF_TERM atom_closing;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_false;
+static ERL_NIF_TERM atom_in4_sockaddr;
+static ERL_NIF_TERM atom_in6_sockaddr;
+static ERL_NIF_TERM atom_loopback;
static ERL_NIF_TERM atom_nif_abort;
static ERL_NIF_TERM atom_ok;
static ERL_NIF_TERM atom_select;
@@ -1425,11 +1483,11 @@ static SocketData socketData;
* ------------------------------
* nif_open(Domain, Type, Protocol, Extra)
* nif_bind(Sock, LocalAddr)
- * nif_connect(Sock, Addr, Port)
+ * nif_connect(Sock, SockAddr)
* nif_listen(Sock, Backlog)
* nif_accept(LSock, Ref)
* nif_send(Sock, SendRef, Data, Flags)
- * nif_sendto(Sock, SendRef, Data, Flags, DstAddr, DstPort)
+ * nif_sendto(Sock, SendRef, Data, Flags, DstSockAddr)
* nif_recv(Sock, RecvRef, Length, Flags)
* nif_recvfrom(Sock, Flags)
* nif_close(Sock)
@@ -1437,8 +1495,8 @@ static SocketData socketData;
*
* And some functions to manipulate and retrieve socket options:
* -------------------------------------------------------------
- * nif_setopt/3
- * nif_getopt/2
+ * nif_setopt/5
+ * nif_getopt/4
*
* And some utility functions:
* -------------------------------------------------------------
@@ -1795,7 +1853,7 @@ ERL_NIF_TERM nbind(ErlNifEnv* env,
ERL_NIF_TERM addr)
{
SocketAddress local;
- unsigned int addrLen;
+ unsigned int addrLen = 0;
char* err;
int port;
@@ -2010,60 +2068,41 @@ char* decode_laddress_tuple(ErlNifEnv* env,
*
* Arguments:
* Socket (ref) - Points to the socket descriptor.
- * Addr - Address of "remote" host.
- * A tuple of size 4 or 8 (depending on domain)
- * Port - Port number of "remote" host.
+ * SockAddr - Socket Address of "remote" host.
+ * This is in_sockaddr(), which is either
+ * in4_sockaddr (#in4_sockaddr{}) or
+ * in6_sockaddr (#in6_sockaddr{}).
*/
static
ERL_NIF_TERM nif_connect(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
- SocketDescriptor* descP;
- int addrSz;
- const ERL_NIF_TERM* addr;
- int port;
+ SocketDescriptor* descP;
+ ERL_NIF_TERM eSockAddr;
/* Extract arguments and perform preliminary validation */
- if ((argc != 3) ||
- !enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
- !GET_TUPLE(env, argv[1], &addrSz, &addr) ||
- !GET_INT(env, argv[2], &port)) {
+ if ((argc != 2) ||
+ !enif_get_resource(env, argv[0], sockets, (void**) &descP)) {
return enif_make_badarg(env);
}
+ eSockAddr = argv[1];
- switch (descP->domain) {
- case AF_INET:
- if (addrSz != 4)
- return make_error(env, atom_einval);
- break;
-
-#if defined(HAVE_IN6) && defined(AF_INET6)
- case AF_INET6:
- if (addrSz != 8)
- return make_error(env, atom_einval);
- break;
-#endif
-
- default:
- return make_error(env, atom_eafnosupport);
- break;
- } // switch (descP->domain)
+ if (!decode_in_sockaddr(env, eSockAddr,
+ &descP->remote, &descP->addrLen)) {
+ return enif_make_badarg(env);
+ }
- return nconnect(env, descP, addr, port);
+ return nconnect(env, descP);
}
static
-ERL_NIF_TERM nconnect(ErlNifEnv* env,
- SocketDescriptor* descP,
- const ERL_NIF_TERM* addr,
- int port)
+ERL_NIF_TERM nconnect(ErlNifEnv* env,
+ SocketDescriptor* descP)
{
- unsigned int addrLen;
- int code;
- char* xerr;
+ int code;
/* Verify that we are where in the proper state */
@@ -2076,13 +2115,9 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env,
if (IS_CONNECTING(descP))
return make_error(env, atom_einval);
- if ((xerr = decode_address_tuple(env,
- descP->domain, addr, port,
- &descP->remote, &addrLen)) != NULL)
- return make_error1(env, xerr);
-
code = sock_connect(descP->sock,
- (struct sockaddr*) &descP->remote, addrLen);
+ (struct sockaddr*) &descP->remote,
+ descP->addrLen);
if (IS_SOCKET_ERROR(code) &&
((sock_errno() == ERRNO_BLOCK) || /* Winsock2 */
@@ -2661,8 +2696,7 @@ ERL_NIF_TERM nsend(ErlNifEnv* env,
* SendRef - A unique id for this (send) request.
* Data - The data to send in the form of a IOVec.
* Flags - Send flags.
- * DestAddr - Destination address.
- * DestPort - Destination Port.
+ * DestSockAddr - Destination (socket) address.
*/
static
@@ -2675,40 +2709,34 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
ErlNifBinary data;
unsigned int eflags;
int flags;
- ERL_NIF_TERM addr;
- int port;
+ ERL_NIF_TERM eSockAddr;
SocketAddress remoteAddr;
- SocketAddress* remoteAddrP = &remoteAddr;
unsigned int remoteAddrLen;
- char* xerr;
- // ERL_NIF_TERM res;
/* Extract arguments and perform preliminary validation */
if ((argc != 6) ||
!enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
!GET_BIN(env, argv[2], &data) ||
- !GET_UINT(env, argv[3], &eflags) ||
- !GET_INT(env, argv[5], &port)) {
+ !GET_UINT(env, argv[3], &eflags)) {
return enif_make_badarg(env);
}
- sendRef = argv[1];
- addr = argv[4];
+ sendRef = argv[1];
+ eSockAddr = argv[4];
/* THIS TEST IS NOT CORRECT!!! */
if (!IS_OPEN(descP))
return make_error(env, atom_einval);
if (!esendflags2sendflags(eflags, &flags))
- return enif_make_badarg(env);
+ return make_error(env, atom_einval);
- if ((xerr = decode_send_addr(env, descP->domain,
- addr, port,
- &remoteAddrP,
- &remoteAddrLen)) != NULL)
- return make_error1(env, xerr);
+ if (!decode_in_sockaddr(env, eSockAddr,
+ &remoteAddr,
+ &remoteAddrLen))
+ return make_error(env, atom_einval);
- return nsendto(env, descP, sendRef, &data, flags, remoteAddrP, remoteAddrLen);
+ return nsendto(env, descP, sendRef, &data, flags, &remoteAddr, remoteAddrLen);
}
@@ -5619,6 +5647,7 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
* This function whouls really have a char* return value
* type!!
*/
+/*
static
char* decode_send_addr(ErlNifEnv* env,
int domain,
@@ -5631,7 +5660,7 @@ char* decode_send_addr(ErlNifEnv* env,
unsigned int len;
char a[16]; // Just in case...
- /* The only acceptable value is the atom 'null' */
+ / * The only acceptable value is the atom 'null' * /
if (!(GET_ATOM_LEN(env, addr, &len) &&
(len > 0) &&
@@ -5648,15 +5677,16 @@ char* decode_send_addr(ErlNifEnv* env,
return str_einval;
} else if (IS_TUPLE(env, addr)) {
- /* We now know that the we have a proper address. */
+ / * We now know that the we have a proper address. * /
return decode_send_addr_tuple(env, domain, addr, port,
*toAddrP, toAddrLenP);
} else {
return str_einval;
}
}
+*/
-
+/*
static
char* decode_send_addr_tuple(ErlNifEnv* env,
int domain,
@@ -5665,10 +5695,10 @@ char* decode_send_addr_tuple(ErlNifEnv* env,
SocketAddress* toAddrP,
unsigned int* toAddrLenP)
{
- /* We handle two different tuples:
+ / * We handle two different tuples:
* - size 4 (INET)
* - size 8 (INET6)
- */
+ * /
const ERL_NIF_TERM* addrt;
int addrtSz;
@@ -5699,6 +5729,304 @@ char* decode_send_addr_tuple(ErlNifEnv* env,
toAddrP, toAddrLenP);
}
+*/
+
+
+/* Decode an in_sockaddr(). This is either a:
+ * in4_sockaddr: #in4_sockaddr{} = 3 tuple =>
+ * 1: The tag in4_sockaddr
+ * 2: Port number (an integer())
+ * 3: The address: any | loopback | ip4_address()
+ * in6_sockaddr: #in6_sockaddr{} = 5 tuple =>
+ * 1: The tag in6_sockaddr
+ * 2: Port number: integer()
+ * 3: The address: any | loopback | ip6_address()
+ * 4: Flow info: integer()
+ * 5: Scope Id: integer()
+ *
+ */
+static
+BOOLEAN_T decode_in_sockaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eSockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ const ERL_NIF_TERM* addrt;
+ int addrtSz;
+ ERL_NIF_TERM result;
+
+ if (!GET_TUPLE(env, eSockAddr, &addrtSz, &addrt))
+ return FALSE;
+
+ /*
+ * We use the tuple size to figure out which
+ * of the records this is.
+ */
+ switch (addrtSz) {
+ case 3:
+ result = decode_in4_sockaddr(env, addrt, sockAddrP, addrLenP);
+ break;
+
+#if defined(HAVE_IN6) && defined(AF_INET6)
+ case 5:
+ result = decode_in6_sockaddr(env, addrt, sockAddrP, addrLenP);
+ break;
+#endif
+
+ default:
+ result = FALSE;
+ break;
+ }
+
+ return result;
+}
+
+
+
+/* Decode an in4_sockaddr().
+ * The first element should be the atom in4_sockaddr
+ * The second, the port number integer .
+ * The third and final, the ip4_address tuple.
+ */
+static
+BOOLEAN_T decode_in4_sockaddr(ErlNifEnv* env,
+ const ERL_NIF_TERM* eIn4SockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ int port;
+
+ /* 1: Ensure that the tuple has the correct tag: in4_sockaddr */
+ if (COMPARE(atom_in4_sockaddr, eIn4SockAddr[0]) != 0)
+ return FALSE;
+
+ /* 2: Get the port number */
+ if (!GET_INT(env, eIn4SockAddr[1], &port))
+ return FALSE;
+
+ /* 3: Get the address.
+ * It can either be the atoms: any | loopback,
+ * or the IPv4 address tuple (size 4).
+ */
+ if (IS_ATOM(env, eIn4SockAddr[2])) {
+ return decode_in4_sockaddr_atomaddr(env, eIn4SockAddr[2], port,
+ sockAddrP, addrLenP);
+ } else if (IS_TUPLE(env, eIn4SockAddr[2])) {
+ return decode_in4_sockaddr_addr(env, eIn4SockAddr[2], port,
+ sockAddrP, addrLenP);
+ } else {
+ return FALSE;
+ }
+}
+
+
+
+static
+BOOLEAN_T decode_in4_sockaddr_atomaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ struct in_addr addr;
+
+ if (COMPARE(atom_loopback, eAddr) == 0) {
+ addr.s_addr = sock_htonl(INADDR_LOOPBACK);
+ } else if (COMPARE(atom_any, eAddr) == 0) {
+ addr.s_addr = sock_htonl(INADDR_ANY);
+ } else {
+ return FALSE;
+ }
+
+ sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in));
+#ifndef NO_SA_LEN
+ sockAddrP->sai.sin_len = sizeof(struct sockaddr_in6);
+#endif
+ sockAddrP->sai.sin_family = AF_INET;
+ sockAddrP->sai.sin_port = sock_htons(port);
+ sockAddrP->sai.sin_addr.s_addr = addr.s_addr;
+ *addrLenP = sizeof(struct sockaddr_in);
+
+ return TRUE;
+}
+
+
+/* Decode an in4_sockaddr where the address field is a tuple.
+ * Its *supposed* to be an ip4_address (tuple).
+ */
+static
+BOOLEAN_T decode_in4_sockaddr_addr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ const ERL_NIF_TERM* ip4AddrT;
+ int ip4AddrTSz;
+ int a, v;
+ char addr[4];
+
+ /* This shall be a 4 tuple */
+ if (!GET_TUPLE(env, eAddr, &ip4AddrTSz, &ip4AddrT))
+ return FALSE;
+
+ if (ip4AddrTSz != 4)
+ return FALSE;
+
+ sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in));
+#ifndef NO_SA_LEN
+ sockAddrP->sai.sin_len = sizeof(struct sockaddr_in);
+#endif
+ sockAddrP->sai.sin_family = AF_INET;
+ sockAddrP->sai.sin_port = sock_htons(port);
+ for (a = 0; a < 4; a++) {
+ if (!GET_INT(env, ip4AddrT[a], &v))
+ return FALSE;
+ addr[a] = v;
+ }
+ sys_memcpy(&sockAddrP->sai.sin_addr, &addr, sizeof(addr));
+ *addrLenP = sizeof(struct sockaddr_in);
+
+ return TRUE;
+}
+
+
+
+/* Decode an in6_sockaddr().
+ * The first element should be the atom in4_sockaddr
+ * The second, the port number integer .
+ * The third, the ip4_address tuple.
+ * The forth, the flowinfo integer.
+ * The fifth and final, the scope_id integer.
+ */
+#if defined(HAVE_IN6) && defined(AF_INET6)
+static
+BOOLEAN_T decode_in6_sockaddr(ErlNifEnv* env,
+ const ERL_NIF_TERM* eIn6SockAddr,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ int port;
+ unsigned int flowInfo, scopeId;
+
+ /* 1: Ensure that the tuple has the correct tag: in6_sockaddr */
+ if (COMPARE(atom_in6_sockaddr, eIn6SockAddr[0]) != 0)
+ return FALSE;
+
+ /* 2: Get the port number */
+ if (!GET_INT(env, eIn6SockAddr[1], &port))
+ return FALSE;
+
+ /* 4: Get the flowinfo */
+ if (!GET_UINT(env, eIn6SockAddr[3], &flowInfo))
+ return FALSE;
+
+ /* 5: Get the scope_id */
+ if (!GET_UINT(env, eIn6SockAddr[4], &scopeId))
+ return FALSE;
+
+ /* 3: Get the address.
+ * It can either be the atoms: any | loopback,
+ * or the IPv6 address tuple (size 8).
+ */
+ if (IS_ATOM(env, eIn6SockAddr[2])) {
+ return decode_in6_sockaddr_atomaddr(env, eIn6SockAddr[2], port,
+ flowInfo, scopeId,
+ sockAddrP, addrLenP);
+ } else if (IS_TUPLE(env, eIn6SockAddr[2])) {
+ return decode_in6_sockaddr_addr(env, eIn6SockAddr[2], port,
+ flowInfo, scopeId,
+ sockAddrP, addrLenP);
+ } else {
+ return FALSE;
+ }
+}
+#endif
+
+
+#if defined(HAVE_IN6) && defined(AF_INET6)
+static
+BOOLEAN_T decode_in6_sockaddr_atomaddr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ unsigned int flowInfo,
+ unsigned int scopeId,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ const struct in6_addr* addr;
+
+ if (COMPARE(atom_loopback, eAddr) == 0) {
+ addr = &in6addr_loopback;
+ } else if (COMPARE(atom_any, eAddr) == 0) {
+ addr = &in6addr_any;
+ } else {
+ return FALSE;
+ }
+
+ sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in6));
+#ifndef NO_SA_LEN
+ sockAddrP->sai6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ sockAddrP->sai6.sin6_family = AF_INET6;
+ sockAddrP->sai6.sin6_port = sock_htons(port);
+ sockAddrP->sai6.sin6_flowinfo = flowInfo;
+ sockAddrP->sai6.sin6_scope_id = scopeId;
+ sockAddrP->sai6.sin6_addr = *addr;
+ *addrLenP = sizeof(struct sockaddr_in6);
+
+ return TRUE;
+}
+#endif
+
+
+
+#if defined(HAVE_IN6) && defined(AF_INET6)
+/* Decode an in6_sockaddr where the address field is a tuple */
+static
+BOOLEAN_T decode_in6_sockaddr_addr(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ int port,
+ unsigned int flowInfo,
+ unsigned int scopeId,
+ SocketAddress* sockAddrP,
+ unsigned int* addrLenP)
+{
+ const ERL_NIF_TERM* ip6AddrT;
+ int ip6AddrTSz;
+ int a, v;
+ char addr[16];
+
+ /* This shall be a 8 tuple */
+ if (!GET_TUPLE(env, eAddr, &ip6AddrTSz, &ip6AddrT))
+ return FALSE;
+
+ if (ip6AddrTSz != 8)
+ return FALSE;
+
+ sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in6));
+#ifndef NO_SA_LEN
+ sockAddrP->sai6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ sockAddrP->sai6.sin6_family = AF_INET6;
+ sockAddrP->sai6.sin6_port = sock_htons(port);
+ sockAddrP->sai6.sin6_flowinfo = flowInfo;
+ sockAddrP->sai6.sin6_scope_id = scopeId;
+ /* The address tuple is of size 8
+ * and each element is a two byte integer
+ */
+ for (a = 0; a < 8; a++) {
+ if (!GET_INT(env, ip6AddrT[a], &v))
+ return FALSE;
+ addr[a*2 ] = ((v >> 8) & 0xFF);
+ addr[a*2+1] = (v & 0xFF);
+ }
+ sys_memcpy(&sockAddrP->sai6.sin6_addr, &addr, sizeof(addr));
+ *addrLenP = sizeof(struct sockaddr_in6);
+
+ return TRUE;
+}
+#endif
/* Decode the 4- or 8-element address tuple
@@ -6651,13 +6979,14 @@ ERL_NIF_TERM make_error2(ErlNifEnv* env, int err)
* This message is for processes that are waiting in the
* erlang API functions for a select message.
*/
+/*
static
char* send_msg_error_closed(ErlNifEnv* env,
ErlNifPid* pid)
{
return send_msg_error(env, atom_closed, pid);
}
-
+*/
/* Send an error message to the specified process:
* A message in the form:
@@ -6667,6 +6996,7 @@ char* send_msg_error_closed(ErlNifEnv* env,
* This message is for processes that are waiting in the
* erlang API functions for a select message.
*/
+/*
static
char* send_msg_error(ErlNifEnv* env,
ERL_NIF_TERM reason,
@@ -6676,6 +7006,7 @@ char* send_msg_error(ErlNifEnv* env,
return send_msg(env, msg, pid);
}
+*/
/* Send an (nif-) abort message to the specified process:
@@ -6985,18 +7316,18 @@ ErlNifFunc socket_funcs[] =
// The proper "socket" interface
{"nif_open", 4, nif_open, 0},
- {"nif_bind", 3, nif_bind, 0},
- {"nif_connect", 3, nif_connect, 0},
+ {"nif_bind", 2, nif_bind, 0},
+ {"nif_connect", 2, nif_connect, 0},
{"nif_listen", 2, nif_listen, 0},
{"nif_accept", 2, nif_accept, 0},
{"nif_send", 4, nif_send, 0},
- {"nif_sendto", 6, nif_sendto, 0},
+ {"nif_sendto", 5, nif_sendto, 0},
{"nif_recv", 4, nif_recv, 0},
- {"nif_recvfrom", 2, nif_recvfrom, 0},
+ {"nif_recvfrom", 4, nif_recvfrom, 0},
{"nif_close", 1, nif_close, 0},
{"nif_shutdown", 2, nif_shutdown, 0},
- {"nif_setopt", 3, nif_setopt, 0},
- {"nif_getopt", 2, nif_getopt, 0},
+ {"nif_setopt", 5, nif_setopt, 0},
+ {"nif_getopt", 4, nif_getopt, 0},
/* Misc utility functions */
{"nif_link_if2idx", 1, nif_link_if2idx, 0},
@@ -7008,7 +7339,7 @@ ErlNifFunc socket_funcs[] =
* is called after the connect *select* has "completed".
*/
{"nif_finalize_connection", 1, nif_finalize_connection, 0},
- {"nif_cancel", 2, nif_cancel, 0},
+ // {"nif_cancel", 2, nif_cancel, 0},
{"nif_finalize_close", 1, nif_finalize_close, ERL_NIF_DIRTY_JOB_IO_BOUND}
};
@@ -7125,6 +7456,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
socketData.numProtoSCTP = 0;
/* +++ Misc atoms +++ */
+ atom_any = MKA(env, str_any);
// atom_active = MKA(env, str_active);
// atom_active_n = MKA(env, str_active_n);
// atom_active_once = MKA(env, str_active_once);
@@ -7135,6 +7467,9 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_closing = MKA(env, str_closing);
atom_error = MKA(env, str_error);
atom_false = MKA(env, str_false);
+ atom_in4_sockaddr = MKA(env, str_in4_sockaddr);
+ atom_in6_sockaddr = MKA(env, str_in6_sockaddr);
+ atom_loopback = MKA(env, str_loopback);
// atom_list = MKA(env, str_list);
// atom_mode = MKA(env, str_mode);
atom_nif_abort = MKA(env, str_nif_abort);
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index a67a019b80..2942f26505 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -30,13 +30,13 @@
-export([
open/2, open/3, open/4,
- bind/2, bind/3,
- connect/3,
+ bind/2,
+ connect/2, connect/3,
listen/1, listen/2,
accept/1, accept/2,
send/2, send/3, send/4,
- sendto/5,
+ sendto/4, sendto/5,
%% sendmsg/4,
%% writev/4, OR SENDV? It will be strange for recv then: recvv (instead of readv)
@@ -125,6 +125,8 @@
%% If we do we may need to include the family (domain) in the
%% map (as the native type do. See struct sockaddr_in6).
%% </KOLLA>
+-type in_sockaddr() :: in4_sockaddr() | in6_sockaddr().
+
-record(in4_sockaddr, {port = 0 :: port_number(),
addr = any :: any | loopback | ip4_address()}).
-type in4_sockaddr() :: #in4_sockaddr{}.
@@ -134,8 +136,6 @@
scope_id = 0 :: in6_scope_id()}).
-type in6_sockaddr() :: #in6_sockaddr{}.
--type in_sockaddr() :: in4_sockaddr() | in6_sockaddr().
-
-type port_number() :: 0..65535.
%% otp - The option is internal to our (OTP) imeplementation.
@@ -369,7 +369,7 @@
%% Optional address
%% On an unconnected socket this is used to specify the target
%% address for a datagram.
- %% For a connected socket, this field should be specified [].
+ %% For a connected socket, this field should be specifiedset to [].
name :: list(),
%% Scatter/gather array
@@ -495,7 +495,8 @@ on_load(Path, Extra) when is_list(Path) andalso is_map(Extra) ->
on_load(true, _Path, _Extra) ->
ok;
on_load(false, Path, Extra) ->
- ok = erlang:load_nif(Path, maps:put(timestamp, formated_timestamp(), Extra)).
+ %% ok = erlang:load_nif(Path, maps:put(timestamp, formated_timestamp(), Extra)).
+ ok = erlang:load_nif(Path, Extra).
@@ -582,7 +583,7 @@ default_protocol(Protocol, _) -> Protocol.
-spec bind(Socket, FileOrAddr) -> ok | {error, Reason} when
Socket :: socket(),
- FileOrAddr :: binary() | string() | ip_address() | any | loopback,
+ FileOrAddr :: binary() | string() | in_sockaddr() | any | loopback,
Reason :: term().
bind(Socket, File) when is_binary(File) ->
@@ -602,26 +603,11 @@ bind(Socket, File) when is_list(File) andalso (File =/= []) ->
true ->
{error, einval}
end;
-bind(Socket, Addr) when is_tuple(Addr) orelse
- (Addr =:= any) orelse
- (Addr =:= loopback) ->
- bind(Socket, Addr, 0).
-
-
--spec bind(Socket, Address, Port) -> ok | {ok, NewPort} | {error, Reason} when
- Socket :: socket(),
- Address :: ip_address() | any | loopback,
- Port :: port_number(),
- NewPort :: port_number(),
- Reason :: term().
-
-%% Shall we keep info about domain so that we can verify address?
-bind(#socket{ref = SockRef}, Addr, Port)
- when (is_tuple(Addr) andalso
- ((size(Addr) =:= 4) orelse (size(Addr) =:= 8))) orelse
- ((Addr =:= any) orelse (Addr =:= loopback)) andalso
- (is_integer(Port) andalso (Port >= 0)) ->
- nif_bind(SockRef, {Addr, Port}).
+bind(#socket{ref = SockRef} = _Socket, SockAddr)
+ when is_record(SockAddr, in4_sockaddr) orelse
+ is_record(SockAddr, in6_sockaddr) orelse
+ (SockAddr =:= any) orelse (SockAddr =:= loopback) ->
+ nif_bind(SockRef, SockAddr).
@@ -630,32 +616,29 @@ bind(#socket{ref = SockRef}, Addr, Port)
%% connect - initiate a connection on a socket
%%
--spec connect(Socket, Addr, Port) -> ok | {error, Reason} when
- Socket :: socket(),
- Addr :: ip_address(),
- Port :: port_number(),
- Reason :: term().
+-spec connect(Socket, SockAddr) -> ok | {error, Reason} when
+ Socket :: socket(),
+ SockAddr :: in_sockaddr(),
+ Reason :: term().
-connect(Socket, Addr, Port) ->
- connect(Socket, Addr, Port, infinity).
+connect(Socket, SockAddr) ->
+ connect(Socket, SockAddr, infinity).
--spec connect(Socket, Addr, Port, Timeout) -> ok | {error, Reason} when
- Socket :: socket(),
- Addr :: ip_address(),
- Port :: port_number(),
- Timeout :: timeout(),
- Reason :: term().
+-spec connect(Socket, SockAddr, Timeout) -> ok | {error, Reason} when
+ Socket :: socket(),
+ SockAddr :: in_sockaddr(),
+ Timeout :: timeout(),
+ Reason :: term().
-connect(_Socket, _Addr, _Port, Timeout)
+connect(_Socket, _SockAddr, Timeout)
when (is_integer(Timeout) andalso (Timeout =< 0)) ->
{error, timeout};
-connect(#socket{ref = SockRef}, Addr, Port, Timeout)
- when (is_tuple(Addr) andalso
- ((size(Addr) =:= 4) orelse (size(Addr) =:= 8))) andalso
- (is_integer(Port) andalso (Port >= 0)) andalso
+connect(#socket{ref = SockRef}, SockAddr, Timeout)
+ when (is_record(SockAddr, in4_sockaddr) orelse
+ is_record(SockAddr, in6_sockaddr)) andalso
((Timeout =:= infinity) orelse is_integer(Timeout)) ->
TS = timestamp(Timeout),
- case nif_connect(SockRef, Addr, Port) of
+ case nif_connect(SockRef, SockAddr) of
ok ->
%% Connected!
ok;
@@ -680,14 +663,18 @@ connect(#socket{ref = SockRef}, Addr, Port, Timeout)
%% listen - listen for connections on a socket
%%
--spec listen(Socket, Backlog) -> ok | {error, Reason} when
+-spec listen(Socket) -> ok | {error, Reason} when
Socket :: socket(),
- Backlog :: pos_integer(),
Reason :: term().
listen(Socket) ->
listen(Socket, ?SOCKET_LISTEN_BACKLOG_DEFAULT).
+-spec listen(Socket, Backlog) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Backlog :: pos_integer(),
+ Reason :: term().
+
listen(#socket{ref = SockRef}, Backlog)
when (is_integer(Backlog) andalso (Backlog >= 0)) ->
nif_listen(SockRef, Backlog).
@@ -700,15 +687,20 @@ listen(#socket{ref = SockRef}, Backlog)
%% accept, accept4 - accept a connection on a socket
%%
--spec accept(LSocket, Timeout) -> {ok, Socket} | {error, Reason} when
+-spec accept(LSocket) -> {ok, Socket} | {error, Reason} when
LSocket :: socket(),
- Timeout :: timeout(),
Socket :: socket(),
Reason :: term().
accept(Socket) ->
accept(Socket, ?SOCKET_ACCEPT_TIMEOUT_DEFAULT).
+-spec accept(LSocket, Timeout) -> {ok, Socket} | {error, Reason} when
+ LSocket :: socket(),
+ Timeout :: timeout(),
+ Socket :: socket(),
+ Reason :: term().
+
%% Do we really need this optimization?
accept(_, Timeout) when is_integer(Timeout) andalso (Timeout =< 0) ->
{error, timeout};
@@ -824,35 +816,35 @@ do_send(SockRef, Data, EFlags, Timeout) ->
%% ---------------------------------------------------------------------------
%%
-sendto(Socket, Data, Flags, DestAddr, DestPort) ->
- sendto(Socket, Data, Flags, DestAddr, DestPort, ?SOCKET_SENDTO_TIMEOUT_DEFAULT).
+sendto(Socket, Data, Flags, DestSockAddr) ->
+ sendto(Socket, Data, Flags, DestSockAddr, ?SOCKET_SENDTO_TIMEOUT_DEFAULT).
--spec sendto(Socket, Data, Flags, DestAddr, DestPort, Timeout) ->
+-spec sendto(Socket, Data, Flags, DestSockAddr, Timeout) ->
ok | {error, Reason} when
- Socket :: socket(),
- Data :: binary(),
- Flags :: send_flags(),
- DestAddr :: null | ip_address(),
- DestPort :: port_number(),
- Timeout :: timeout(),
- Reason :: term().
-
-sendto(Socket, Data, Flags, DestAddr, DestPort, Timeout) when is_list(Data) ->
+ Socket :: socket(),
+ Data :: binary(),
+ Flags :: send_flags(),
+ DestSockAddr :: null | in_sockaddr(),
+ Timeout :: timeout(),
+ Reason :: term().
+
+sendto(Socket, Data, Flags, DestSockAddr, Timeout) when is_list(Data) ->
Bin = erlang:list_to_binary(Data),
- sendto(Socket, Bin, Flags, DestAddr, DestPort, Timeout);
-sendto(#socket{ref = SockRef}, Data, Flags, DestAddr, DestPort, Timeout)
+ sendto(Socket, Bin, Flags, DestSockAddr, Timeout);
+sendto(#socket{ref = SockRef}, Data, Flags, DestSockAddr, Timeout)
when is_binary(Data) andalso
is_list(Flags) andalso
- (is_tuple(DestAddr) orelse (DestAddr =:= null)) andalso
- is_integer(DestPort) andalso
+ (is_record(DestSockAddr, in4_sockaddr) orelse
+ is_record(DestSockAddr, in6_sockaddr) orelse
+ (DestSockAddr =:= null)) andalso
(is_integer(Timeout) orelse (Timeout =:= infinity)) ->
EFlags = enc_send_flags(Flags),
- do_sendto(SockRef, Data, EFlags, DestAddr, DestPort, Timeout).
+ do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout).
-do_sendto(SockRef, Data, EFlags, DestAddr, DestPort, Timeout) ->
+do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout) ->
TS = timestamp(Timeout),
SendRef = make_ref(),
- case nif_sendto(SockRef, SendRef, Data, EFlags, DestAddr, DestPort) of
+ case nif_sendto(SockRef, SendRef, Data, EFlags, DestSockAddr) of
ok ->
%% We are done
ok;
@@ -862,10 +854,10 @@ do_sendto(SockRef, Data, EFlags, DestAddr, DestPort, Timeout) ->
receive
{select, SockRef, SendRef, ready_output} when (Written > 0) ->
<<_:Written/binary, Rest/binary>> = Data,
- do_sendto(SockRef, Rest, EFlags, DestAddr, DestPort,
+ do_sendto(SockRef, Rest, EFlags, DestSockAddr,
next_timeout(TS, Timeout));
{select, SockRef, SendRef, ready_output} ->
- do_sendto(SockRef, Data, EFlags, DestAddr, DestPort,
+ do_sendto(SockRef, Data, EFlags, DestSockAddr,
next_timeout(TS, Timeout));
{nif_abort, SendRef, Reason} ->
@@ -880,7 +872,7 @@ do_sendto(SockRef, Data, EFlags, DestAddr, DestPort, Timeout) ->
{error, eagain} ->
receive
{select, SockRef, SendRef, ready_output} ->
- do_sendto(SockRef, Data, EFlags, DestAddr, DestPort,
+ do_sendto(SockRef, Data, EFlags, DestSockAddr,
next_timeout(TS, Timeout))
after Timeout ->
nif_cancel(SockRef, sendto, SendRef),
@@ -1158,13 +1150,12 @@ recvfrom(Socket, BufSz, Flags) when is_list(Flags) ->
recvfrom(Socket, BufSz, Timeout) ->
recvfrom(Socket, BufSz, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
--spec recvfrom(Socket, BufSz, Flags, Timeout) -> {ok, {SrcDomain, Source, Data}} | {error, Reason} when
+-spec recvfrom(Socket, BufSz, Flags, Timeout) -> {ok, {Source, Data}} | {error, Reason} when
Socket :: socket(),
BufSz :: non_neg_integer(),
Flags :: recv_flags(),
Timeout :: timeout(),
- SrcDomain :: domain() | undefined,
- Source :: {ip_address(), port_number()} | string() | undefined,
+ Source :: in_sockaddr() | string() | undefined,
Data :: binary(),
Reason :: term().
@@ -1179,7 +1170,7 @@ do_recvfrom(SockRef, BufSz, EFlags, Timeout) ->
TS = timestamp(Timeout),
RecvRef = make_ref(),
case nif_recvfrom(SockRef, RecvRef, BufSz, EFlags) of
- {ok, {_Domain, _Source, _NewData}} = OK ->
+ {ok, {_Source, _NewData}} = OK ->
OK;
{error, eagain} ->
@@ -1473,7 +1464,6 @@ link_if2idx(If) when is_list(If) ->
nif_link_if2idx(If).
-
%% ===========================================================================
%%
%% link_idx2if - Mappings between network interface names and indexes: idx -> if
@@ -2138,10 +2128,10 @@ nif_info() ->
nif_open(_Domain, _Type, _Protocol, _Extra) ->
erlang:error(badarg).
-nif_bind(_SRef, _LocalAddr) ->
+nif_bind(_SRef, _SockAddr) ->
erlang:error(badarg).
-nif_connect(_SRef, _Addr, _Port) ->
+nif_connect(_SRef, _SockAddr) ->
erlang:error(badarg).
nif_finalize_connection(_SRef) ->
@@ -2156,7 +2146,7 @@ nif_accept(_SRef, _Ref) ->
nif_send(_SockRef, _SendRef, _Data, _Flags) ->
erlang:error(badarg).
-nif_sendto(_SRef, _SendRef, _Data, _Flags, _Dest, _Port) ->
+nif_sendto(_SRef, _SendRef, _Data, _Flags, _DestSockAddr) ->
erlang:error(badarg).
nif_recv(_SRef, _RecvRef, _Length, _Flags) ->