Skip to content

Commit

Permalink
Added support for net:getaddrinfo/1,2
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Dushin <[email protected]>
  • Loading branch information
fadushin committed Oct 29, 2023
1 parent 92eed62 commit 4ff90ec
Show file tree
Hide file tree
Showing 19 changed files with 708 additions and 3 deletions.
36 changes: 36 additions & 0 deletions doc/src/programmers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1860,3 +1860,39 @@ For example:
end

Close a UDP socket just as you would a TCP socket, as described above.

### Miscellaneous Networking APIs

You can retrieve information about hostnames and services using the `net:getaddrinfo/1` and `net:getaddrinfo/2` functions. The return value is a list of maps each of which contains address information about the host, including its family (`inet`), protocol (`tcp` or `udp`), type (`stream` or `dgram`), and the address, currently an IPv4 tuple.

For example:

%% erlang
{ok, AddrInfos} = net:getaddrinfo("www.atomvm.net"),

lists:foreach(
fun(AddrInfo) ->
#{
family := Family,
protocol := Protocol,
type := Type,
address := Address
} = AddrInfo,

io:format("family: ~p prototcol: ~p type: ~p address: ~p", [Family, Protocol, Type, Address])

end,
AddrInfos
),

The `host` parameter can be a domain name (typically) or a dotted pair IPv4 address.

If you want to narrow the information you get back to a specific service type, you can specify a service name or port number (as a string value) as the second parameter:

%% erlang
{ok, AddrInfos} = net:getaddrinfo("www.atomvm.net", "https"),
...

Service names are well-known identifiers on the internet, but they may vary from operating system to operating system. See the `services(3)` man pages for more information.

> Note. Currently, the `net:getaddrinfo/1` function only supports reporting of IPv4 addresses.
1 change: 1 addition & 0 deletions libs/estdlib/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(ERLANG_MODULES
lists
maps
math
net
logger
logger_std_h
proplists
Expand Down
80 changes: 80 additions & 0 deletions libs/estdlib/src/net.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
%
% This file is part of AtomVM.
%
% Copyright 2023 Fred Dushin <[email protected]>
%
% 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.
%
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
%

-module(net).

-export([getaddrinfo/1, getaddrinfo/2]).

%% nif call (so we can use guards at the API)
-export([getaddrinfo_nif/2]).

-type addrinfo() :: #{
family := socket:domain(),
socktype := socket:type(),
protocol := socket:protocol(),
%% NB. The erlang docs appear to be wrong about this
address := socket:sockaddr(),
addr := socket:sockaddr()
}.

-type service() :: string().

-export_type([addrinfo/0, service/0]).

%%-----------------------------------------------------------------------------
%% @param Host the host string for which to find address information
%% @returns Address info for the specified host
%% @equiv getaddrinfo(Host, undefined)
%% @doc Retrieve address information for a given hostname.
%% @end
%%-----------------------------------------------------------------------------
-spec getaddrinfo(Host :: string()) -> {ok, AddrInfo :: addrinfo()} | {error, Reason :: term()}.
getaddrinfo(Host) when is_list(Host) ->
?MODULE:getaddrinfo(Host, undefined).

%%-----------------------------------------------------------------------------
%% @param Host the host string for which to find address information
%% @param Service the service string for which to find address information
%% @returns Address info for the specified host and service
%% @doc Retrieve address information for a given hostname and service.
%%
%% The `Host' parameter may be a fully qualified host name or a string
%% containing a valid dotted pair IP address. (Currently, only IPv4 is
%% supported).
%%
%% The `Service' parameter may be the name of a service (as defined via
%% `services(3)` or a string containing a decimal value of the same.
%%
%% Note that the `Host' or `String' parameter may be `undefined', but
%% not both.
%% @end
%%-----------------------------------------------------------------------------
-spec getaddrinfo(Host :: string() | undefined, Service :: service() | undefined) ->
{ok, AddrInfo :: addrinfo()} | {error, Reason :: term()}.
getaddrinfo(Host, Service) when
(is_list(Host) orelse Host =:= undefined) andalso
(is_list(Service) orelse Service =:= undefined) andalso
not (Host =:= undefined andalso Service =:= undefined)
->
?MODULE:getaddrinfo_nif(Host, Service).

%% @hidden
getaddrinfo_nif(_Host, _Service) ->
erlang:nif_error(undefined).
1 change: 1 addition & 0 deletions src/libAtomVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ define_if_function_exists(libAtomVM open "fcntl.h" PUBLIC HAVE_OPEN)
define_if_function_exists(libAtomVM close "unistd.h" PUBLIC HAVE_CLOSE)
define_if_function_exists(libAtomVM mkfifo "sys/stat.h" PRIVATE HAVE_MKFIFO)
define_if_function_exists(libAtomVM unlink "unistd.h" PRIVATE HAVE_UNLINK)
define_if_function_exists(libAtomVM getservbyname "netdb.h" PRIVATE HAVE_SERVBYNAME)
define_if_symbol_exists(libAtomVM O_CLOEXEC "fcntl.h" PRIVATE HAVE_O_CLOEXEC)
define_if_symbol_exists(libAtomVM O_DIRECTORY "fcntl.h" PRIVATE HAVE_O_DIRECTORY)
define_if_symbol_exists(libAtomVM O_DSYNC "fcntl.h" PRIVATE HAVE_O_DSYNC)
Expand Down
22 changes: 22 additions & 0 deletions src/libAtomVM/interop.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,3 +611,25 @@ term interop_kv_get_value_default(term kv, AtomString key, term default_value, G
return default_value;
}
}

term interop_atom_term_select_atom(GlobalContext *global, const AtomStringIntPair *table, int value)
{
int i;
for (i = 0; table[i].as_val != NULL; i++) {
if (value == table[i].i_val) {
int global_atom_index = globalcontext_insert_atom(global, table[i].as_val);
return term_from_atom_index(global_atom_index);
}
}
return term_invalid_term();
}

term interop_chars_to_list(const char *chars, size_t len, Heap *heap)
{
term ret = term_nil();
for (int i = (int) len - 1; i >= 0; --i) {
term c_term = term_from_int(chars[i]);
ret = term_list_prepend(c_term, ret, heap);
}
return ret;
}
3 changes: 3 additions & 0 deletions src/libAtomVM/interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ term interop_proplist_get_value(term list, term key);
term interop_proplist_get_value_default(term list, term key, term default_value);
term interop_map_get_value(GlobalContext *glb, term map, term key);
term interop_map_get_value_default(GlobalContext *glb, term map, term key, term default_value);
term interop_chars_to_list(const char *chars, size_t len, Heap *heap);

NO_DISCARD InteropFunctionResult interop_iolist_size(term t, size_t *size);
NO_DISCARD InteropFunctionResult interop_write_iolist(term t, char *p);
Expand Down Expand Up @@ -147,4 +148,6 @@ static inline term interop_bytes_to_list(const void *bytes, int len, Heap *heap)
}
#endif

term interop_atom_term_select_atom(GlobalContext *global, const AtomStringIntPair *table, int value);

#endif
Loading

0 comments on commit 4ff90ec

Please sign in to comment.