1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(inet_tcp).
21
22%% Socket server for TCP/IP
23
24-export([connect/3, connect/4, listen/2, accept/1, accept/2, close/1]).
25-export([send/2, send/3, recv/2, recv/3, unrecv/2]).
26-export([shutdown/2]).
27-export([controlling_process/2]).
28-export([fdopen/2]).
29
30-export([family/0, mask/2, parse_address/1]). % inet_tcp_dist
31-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
32-export([translate_ip/1]).
33
34-include("inet_int.hrl").
35
36-define(FAMILY, inet).
37-define(PROTO, tcp).
38-define(TYPE, stream).
39
40%% my address family
41family() -> ?FAMILY.
42
43%% Apply netmask on address
44mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
45    {M1 band IP1,
46     M2 band IP2,
47     M3 band IP3,
48     M4 band IP4}.
49
50%% Parse address string
51parse_address(Host) ->
52    inet_parse:ipv4strict_address(Host).
53
54%% inet_tcp port lookup
55getserv(Port) when is_integer(Port) -> {ok, Port};
56getserv(Name) when is_atom(Name) -> inet:getservbyname(Name, ?PROTO).
57
58%% inet_tcp address lookup
59getaddr(Address) -> inet:getaddr(Address, ?FAMILY).
60getaddr(Address, Timer) -> inet:getaddr_tm(Address, ?FAMILY, Timer).
61
62%% inet_tcp address lookup
63getaddrs(Address) -> inet:getaddrs(Address, ?FAMILY).
64getaddrs(Address, Timer) -> inet:getaddrs_tm(Address, ?FAMILY, Timer).
65
66%% inet_udp special this side addresses
67translate_ip(IP) -> inet:translate_ip(IP, ?FAMILY).
68
69%%
70%% Send data on a socket
71%%
72send(Socket, Packet, Opts) -> prim_inet:send(Socket, Packet, Opts).
73send(Socket, Packet) -> prim_inet:send(Socket, Packet, []).
74
75%%
76%% Receive data from a socket (inactive only)
77%%
78recv(Socket, Length) -> prim_inet:recv(Socket, Length).
79recv(Socket, Length, Timeout) -> prim_inet:recv(Socket, Length, Timeout).
80
81unrecv(Socket, Data) -> prim_inet:unrecv(Socket, Data).
82
83%%
84%% Shutdown one end of a socket
85%%
86shutdown(Socket, How) ->
87    prim_inet:shutdown(Socket, How).
88
89%%
90%% Close a socket (async)
91%%
92close(Socket) ->
93    inet:tcp_close(Socket).
94
95%%
96%% Set controlling process
97%%
98controlling_process(Socket, NewOwner) ->
99    inet:tcp_controlling_process(Socket, NewOwner).
100
101%%
102%% Connect
103%%
104connect(Address, Port, Opts) ->
105    do_connect(Address, Port, Opts, infinity).
106
107connect(Address, Port, Opts, infinity) ->
108    do_connect(Address, Port, Opts, infinity);
109connect(Address, Port, Opts, Timeout)
110  when is_integer(Timeout), Timeout >= 0 ->
111    do_connect(Address, Port, Opts, Timeout).
112
113do_connect(Addr = {A,B,C,D}, Port, Opts, Time)
114  when ?ip(A,B,C,D), ?port(Port) ->
115    case inet:connect_options(Opts, ?MODULE) of
116	{error, Reason} -> exit(Reason);
117	{ok,
118	 #connect_opts{
119	    fd = Fd,
120	    ifaddr = BAddr = {Ab,Bb,Cb,Db},
121	    port = BPort,
122	    opts = SockOpts}}
123	when ?ip(Ab,Bb,Cb,Db), ?port(BPort) ->
124	    case inet:open(
125		   Fd, BAddr, BPort, SockOpts,
126		   ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
127		{ok, S} ->
128		    case prim_inet:connect(S, Addr, Port, Time) of
129			ok -> {ok,S};
130			Error -> prim_inet:close(S), Error
131		    end;
132		Error -> Error
133	    end;
134	{ok, _} -> exit(badarg)
135    end.
136
137%%
138%% Listen
139%%
140listen(Port, Opts) ->
141    case inet:listen_options([{port,Port} | Opts], ?MODULE) of
142	{error, Reason} -> exit(Reason);
143	{ok,
144	 #listen_opts{
145	    fd = Fd,
146	    ifaddr = BAddr = {A,B,C,D},
147	    port = BPort,
148	    opts = SockOpts} = R}
149	when ?ip(A,B,C,D), ?port(BPort) ->
150	    case inet:open(
151		   Fd, BAddr, BPort, SockOpts,
152		   ?PROTO, ?FAMILY, ?TYPE, ?MODULE) of
153		{ok, S} ->
154		    case prim_inet:listen(S, R#listen_opts.backlog) of
155			ok -> {ok, S};
156			Error -> prim_inet:close(S), Error
157		    end;
158		Error -> Error
159	    end;
160	{ok, _} -> exit(badarg)
161    end.
162
163%%
164%% Accept
165%%
166accept(L) ->
167    case prim_inet:accept(L, accept_family_opts()) of
168	{ok, S} ->
169	    inet_db:register_socket(S, ?MODULE),
170	    {ok,S};
171	Error -> Error
172    end.
173
174accept(L, Timeout) ->
175    case prim_inet:accept(L, Timeout, accept_family_opts()) of
176	{ok, S} ->
177	    inet_db:register_socket(S, ?MODULE),
178	    {ok,S};
179	Error -> Error
180    end.
181
182accept_family_opts() -> [tos, ttl, recvtos, recvttl].
183
184%%
185%% Create a port/socket from a file descriptor
186%%
187fdopen(Fd, Opts) ->
188    inet:fdopen(Fd, Opts, ?PROTO, ?FAMILY, ?TYPE, ?MODULE).
189