Packages

Process ip's in js and erlang via gleam

Current section

Files

Jump to
gip src gip_ffi.erl
Raw

src/gip_ffi.erl

% Copyright 2024 BradBot_1
% 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.
-module(gip_ffi).
-export([parse/1]).
-export([is_ip/1]).
-export([is_v4/1]).
-export([is_v6/1]).
-export([stringify/1]).
-export([self/0]).
parse(RawIp) ->
case inet:parse_address(erlang:binary_to_list(RawIp)) of
{ok, Address} -> {ok, unpack(Address)};
{error, _} -> {error, <<"Invalid IP provided">>}
end.
unpack(Ip) ->
if
erlang:tuple_size(Ip) == 8 -> erlang:list_to_tuple(convert_16bit_list_to_8bit_list(erlang:tuple_to_list(Ip)));
true -> Ip
end.
convert_16bit_to_8bit(N) when is_integer(N), N >= 0, N =< 65535 ->
High8 = (N bsr 8) band 255,
Low8 = N band 255,
{High8, Low8}.
convert_16bit_list_to_8bit_list(Nums) when is_list(Nums) ->
convert_16bit_list_to_8bit_list(Nums, []).
convert_16bit_list_to_8bit_list([], Acc) ->
lists:reverse(Acc);
convert_16bit_list_to_8bit_list([H | T], Acc) ->
{High8, Low8} = convert_16bit_to_8bit(H),
convert_16bit_list_to_8bit_list(T, [Low8, High8 | Acc]).
is_ip(RawIp) ->
case inet:parse_address(erlang:binary_to_list(RawIp)) of
{ok, _} -> true;
{error, _} -> false
end.
is_v4(RawIp) ->
case inet:parse_address(erlang:binary_to_list(RawIp)) of
{ok, Address} -> erlang:tuple_size(Address) == 4;
{error, _} -> false
end.
is_v6(RawIp) ->
case inet:parse_address(erlang:binary_to_list(RawIp)) of
{ok, Address} -> erlang:tuple_size(Address) == 8;
{error, _} -> false
end.
stringify(Ip) ->
case inet:ntoa(pack(Ip)) of
{error, _} -> {error, <<"Cannot convert to IP">>};
Address -> {ok, erlang:list_to_binary(Address)}
end.
pack(Ip) ->
if
erlang:tuple_size(Ip) == 16 -> erlang:list_to_tuple(convert_8bit_list_to_16bit_list(erlang:tuple_to_list(Ip)));
true -> Ip
end.
convert_8bit_to_16bit(High8, Low8) when is_integer(High8), High8 >= 0, High8 =< 255,
is_integer(Low8), Low8 >= 0, Low8 =< 255 ->
(High8 bsl 8) bor Low8.
convert_8bit_list_to_16bit_list(Bytes) when is_list(Bytes) ->
convert_8bit_list_to_16bit_list(Bytes, []).
convert_8bit_list_to_16bit_list([], Acc) ->
lists:reverse(Acc);
convert_8bit_list_to_16bit_list([High8, Low8 | T], Acc) ->
SixteenBit = convert_8bit_to_16bit(High8, Low8),
convert_8bit_list_to_16bit_list(T, [SixteenBit | Acc]).
% https://stackoverflow.com/a/32986858
self() ->
{ok, Addrs} = inet:getifaddrs(),
{ok, hd([
Addr || {_, Opts} <- Addrs, {addr, Addr} <- Opts,
size(Addr) == 4, Addr =/= {127,0,0,1}
])}.