From faea8584311fcb5365c585280e5e9b2364ed121e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 2 Sep 2011 10:38:39 +0200 Subject: erts,kernel: Add type stream sockets to SCTP --- erts/emulator/drivers/common/inet_drv.c | 118 +++++++++++++++++++++++--------- erts/preloaded/src/erl_prim_loader.erl | 8 +-- erts/preloaded/src/prim_inet.erl | 64 +++++++---------- 3 files changed, 113 insertions(+), 77 deletions(-) (limited to 'erts') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 8f2a4f0ba5..8979093649 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -427,7 +427,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */ #define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */ -/* INET_REQ_GETTYPE enumeration */ +/* open and INET_REQ_GETTYPE enumeration */ #define INET_TYPE_STREAM 1 #define INET_TYPE_DGRAM 2 #define INET_TYPE_SEQPACKET 3 @@ -7855,34 +7855,56 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, { tcp_descriptor* desc = (tcp_descriptor*)e; switch(cmd) { - case INET_REQ_OPEN: /* open socket and return internal index */ + case INET_REQ_OPEN: { /* open socket and return internal index */ + int domain; DEBUGF(("tcp_inet_ctl(%ld): OPEN\r\n", (long)desc->inet.port)); - if ((len == 1) && (buf[0] == INET_AF_INET)) - return - inet_ctl_open(INETP(desc), AF_INET, SOCK_STREAM, rbuf, rsize); + if (len != 2) return ctl_error(EINVAL, rbuf, rsize); + switch(buf[0]) { + case INET_AF_INET: + domain = AF_INET; + break; #if defined(HAVE_IN6) && defined(AF_INET6) - else if ((len == 1) && (buf[0] == INET_AF_INET6)) - return - inet_ctl_open(INETP(desc), AF_INET6, SOCK_STREAM, rbuf, rsize); + case INET_AF_INET6: + domain = AF_INET6; + break; #else - else if ((len == 1) && (buf[0] == INET_AF_INET6)) - return ctl_xerror("eafnosupport",rbuf,rsize); + case INET_AF_INET6: + return ctl_xerror("eafnosupport", rbuf, rsize); + break; #endif - else + default: return ctl_error(EINVAL, rbuf, rsize); + } + if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize); + return inet_ctl_open(INETP(desc), domain, SOCK_STREAM, rbuf, rsize); + break; + } - case INET_REQ_FDOPEN: /* pass in an open socket */ - DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port)); - if ((len == 5) && (buf[0] == INET_AF_INET)) - return inet_ctl_fdopen(INETP(desc), AF_INET, SOCK_STREAM, - (SOCKET) get_int32(buf+1), rbuf, rsize); + case INET_REQ_FDOPEN: { /* pass in an open socket */ + int domain; + DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port)); + if (len != 6) return ctl_error(EINVAL, rbuf, rsize); + switch(buf[0]) { + case INET_AF_INET: + domain = AF_INET; + break; #if defined(HAVE_IN6) && defined(AF_INET6) - else if ((len == 5) && (buf[0] == INET_AF_INET6)) - return inet_ctl_fdopen(INETP(desc), AF_INET6, SOCK_STREAM, - (SOCKET) get_int32(buf+1), rbuf, rsize); + case INET_AF_INET6: + domain = AF_INET6; + break; +#else + case INET_AF_INET6: + return ctl_xerror("eafnosupport", rbuf, rsize); + break; #endif - else + default: return ctl_error(EINVAL, rbuf, rsize); + } + if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize); + return inet_ctl_fdopen(INETP(desc), domain, SOCK_STREAM, + (SOCKET) get_int32(buf+2), rbuf, rsize); + break; + } case INET_REQ_LISTEN: { /* argument backlog */ @@ -9466,21 +9488,31 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, udp_descriptor * udesc = (udp_descriptor *) e; inet_descriptor* desc = INETP(udesc); int type = SOCK_DGRAM; - int af; -#ifdef HAVE_SCTP - if (IS_SCTP(desc)) type = SOCK_SEQPACKET; -#endif + int af = AF_INET; switch(cmd) { case INET_REQ_OPEN: /* open socket and return internal index */ DEBUGF(("packet_inet_ctl(%ld): OPEN\r\n", (long)desc->port)); - if (len != 1) { + if (len != 2) { return ctl_error(EINVAL, rbuf, rsize); } switch (buf[0]) { case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) - case INET_AF_INET6: af = AF_INET6; break; + case INET_AF_INET6: af = AF_INET6; break; +#else + case INET_AF_INET6: + return ctl_xerror("eafnosupport", rbuf, rsize); + break; +#endif + default: + return ctl_error(EINVAL, rbuf, rsize); + } + switch (buf[1]) { + case INET_TYPE_STREAM: type = SOCK_STREAM; break; + case INET_TYPE_DGRAM: type = SOCK_DGRAM; break; +#ifdef HAVE_SCTP + case INET_TYPE_SEQPACKET: type = SOCK_SEQPACKET; break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -9507,18 +9539,35 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, return replen; - case INET_REQ_FDOPEN: /* pass in an open (and bound) socket */ + case INET_REQ_FDOPEN: { /* pass in an open (and bound) socket */ + SOCKET s; DEBUGF(("packet inet_ctl(%ld): FDOPEN\r\n", (long)desc->port)); - if ((len == 5) && (buf[0] == INET_AF_INET)) - replen = inet_ctl_fdopen(desc, AF_INET, SOCK_DGRAM, - (SOCKET)get_int32(buf+1),rbuf,rsize); + if (len != 6) { + return ctl_error(EINVAL, rbuf, rsize); + } + switch (buf[0]) { + case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) - else if ((len == 5) && (buf[0] == INET_AF_INET6)) - replen = inet_ctl_fdopen(desc, AF_INET6, SOCK_DGRAM, - (SOCKET)get_int32(buf+1),rbuf,rsize); + case INET_AF_INET6: af = AF_INET6; break; +#else + case INET_AF_INET6: + return ctl_xerror("eafnosupport", rbuf, rsize); + break; #endif - else + default: return ctl_error(EINVAL, rbuf, rsize); + } + switch (buf[1]) { + case INET_TYPE_STREAM: type = SOCK_STREAM; break; + case INET_TYPE_DGRAM: type = SOCK_DGRAM; break; +#ifdef HAVE_SCTP + case INET_TYPE_SEQPACKET: type = SOCK_SEQPACKET; break; +#endif + default: + return ctl_error(EINVAL, rbuf, rsize); + } + s = (SOCKET)get_int32(buf+2); + replen = inet_ctl_fdopen(desc, af, type, s, rbuf, rsize); if ((*rbuf)[0] != INET_REP_ERROR) { if (desc->active) @@ -9538,6 +9587,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, #endif } return replen; + } case INET_REQ_CLOSE: diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 0b4db3d9d0..35defde692 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -729,7 +729,7 @@ udp_options() -> %% INET version IPv4 addresses %% ll_tcp_connect(LocalPort, IP, RemotePort) -> - case ll_open_set_bind(tcp, ?INET_FAMILY, tcp_options(), + case ll_open_set_bind(tcp, ?INET_FAMILY, stream, tcp_options(), ?INET_ADDRESS, LocalPort) of {ok,S} -> case prim_inet:connect(S, IP, RemotePort, tcp_timeout()) of @@ -743,11 +743,11 @@ ll_tcp_connect(LocalPort, IP, RemotePort) -> %% Open and initialize an udp port for broadcast %% ll_udp_open(P) -> - ll_open_set_bind(udp, ?INET_FAMILY, udp_options(), ?INET_ADDRESS, P). + ll_open_set_bind(udp, ?INET_FAMILY, dgram, udp_options(), ?INET_ADDRESS, P). -ll_open_set_bind(Protocol, Family, SOpts, IP, Port) -> - case prim_inet:open(Protocol, Family) of +ll_open_set_bind(Protocol, Family, Type, SOpts, IP, Port) -> + case prim_inet:open(Protocol, Family, Type) of {ok, S} -> case prim_inet:setopts(S, SOpts) of ok -> diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index adf64f90df..231a5ed4e5 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -25,7 +25,7 @@ %% Primitive inet_drv interface --export([open/1, open/2, fdopen/2, fdopen/3, close/1]). +-export([open/3, fdopen/4, close/1]). -export([bind/3, listen/1, listen/2]). -export([connect/3, connect/4, async_connect/4]). -export([accept/1, accept/2, async_accept/2]). @@ -56,58 +56,44 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -%% OPEN(tcp | udp | sctp, inet | inet6) -> +%% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket) -> %% {ok, insock()} | %% {error, Reason} %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -open(Protocol) -> open1(Protocol, ?INET_AF_INET). +open(Protocol, Family, Type) -> + open(Protocol, Family, Type, ?INET_REQ_OPEN, []). -open(Protocol, inet) -> open1(Protocol, ?INET_AF_INET); -open(Protocol, inet6) -> open1(Protocol, ?INET_AF_INET6); -open(_, _) -> {error, einval}. +fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> + open(Protocol, Family, Type, ?INET_REQ_FDOPEN, ?int32(Fd)). -fdopen(Protocol, Fd) -> fdopen1(Protocol, ?INET_AF_INET, Fd). - -fdopen(Protocol, Fd, inet) -> fdopen1(Protocol, ?INET_AF_INET, Fd); -fdopen(Protocol, Fd, inet6) -> fdopen1(Protocol, ?INET_AF_INET6, Fd); -fdopen(_, _, _) -> {error, einval}. - -open1(Protocol, Family) -> - case open0(Protocol) of - {ok, S} -> - case ctl_cmd(S, ?INET_REQ_OPEN, [Family]) of - {ok, _} -> - {ok,S}; +open(Protocol, Family, Type, Req, Data) -> + Drv = protocol2drv(Protocol), + AF = enc_family(Family), + T = enc_type(Type), + try erlang:open_port({spawn_driver,Drv}, [binary]) of + S -> + case ctl_cmd(S, Req, [AF,T,Data]) of + {ok,_} -> {ok,S}; Error -> - close(S), Error - end; - Error -> Error - end. - -fdopen1(Protocol, Family, Fd) when is_integer(Fd) -> - case open0(Protocol) of - {ok, S} -> - case ctl_cmd(S,?INET_REQ_FDOPEN,[Family,?int32(Fd)]) of - {ok, _} -> {ok,S}; - Error -> close(S), Error - end; - Error -> Error - end. - -open0(Protocol) -> - try erlang:open_port({spawn_driver,protocol2drv(Protocol)}, [binary]) of - Port -> {ok,Port} + close(S), + Error + end catch error:Reason -> {error,Reason} end. +enc_family(inet) -> ?INET_AF_INET; +enc_family(inet6) -> ?INET_AF_INET6. + +enc_type(stream) -> ?INET_TYPE_STREAM; +enc_type(dgram) -> ?INET_TYPE_DGRAM; +enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET. + protocol2drv(tcp) -> "tcp_inet"; protocol2drv(udp) -> "udp_inet"; -protocol2drv(sctp) -> "sctp_inet"; -protocol2drv(_) -> - erlang:error(eprotonosupport). +protocol2drv(sctp) -> "sctp_inet". drv2protocol("tcp_inet") -> tcp; drv2protocol("udp_inet") -> udp; -- cgit v1.2.3