3 ms·
Because that's what they are; that's the representation. Look at the classic struct sockaddr_in structure it has a member sin_addr of type struct in_addr. What
by kazinator 2y ago
Because that's what they are; that's the representation.
Look at the classic struct sockaddr_in structure it has a member sin_addr of type struct in_addr. What is that?
In my header files here I have it as:
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
The C structure has an integer, so the Lisp analog does also.
C socket code does things like
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
INADDR_LOOPBACK is 127.0.0.1 encoded as an integer.
It's easy to to do bitwise arithmetic on it. E.g. to apply a netmask like 255.0.0.0, you literally just form the netmask as 0xFF000000, and use your & operator: addr & 0xFF00000000.
In the case of IPv6, there is a union: a view of the address as 16 bytes, 8 words, or 4 double words.
Since I have bignum integers, I just made it a simple integer, so it looks like the IPv4 case. You can do bitwise arithmetic on it in a straightforward.
We can get the addresses in text format like this:
1> (getaddrinfo "news.ycombinator.com")
(#S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32)
#S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32)
#S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0
flow-info 0 scope-id 0 prefix 128)
#S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0
flow-info 0 scope-id 0 prefix 128))
2> (first *1)
#S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32)
3> (third *1)
#S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0
flow-info 0 scope-id 0 prefix 128)
4> (str-inaddr *2.addr)
"209.216.230.207"
5> (str-in6addr *3.addr)
"2606:7100:1:67::26"
str-inaddr and str-in6addr* take an integer and return a string.
Their rough opposites return a structure, because the general text format can encode prefix and port number info.
6> (inaddr-str *4)
#S(sockaddr-in canonname nil addr 3520653007 port 0 prefix 32)
7> (in6addr-str *5)
#S(sockaddr-in6 canonname nil addr 50544109533264435600708011529282256934 port 0
flow-info 0 scope-id 0 prefix 128)
The structures also support a generic method str-addr:
8> (mapcar .(str-addr) (getaddrinfo "news.ycombinator.com"))
("209.216.230.207" "209.216.230.207" "2606:7100:1:67::26" "2606:7100:1:67::26")
This will take into account prefix and port number if they are present and nonzero.
We could define a custom print method in the sockaddr base:
9> (defmeth sockaddr print (self stream pretty-p)
(put-string `#<@(typeof self) @{self.(str-addr)}>` stream))
(meth sockaddr
print)
10> (getaddrinfo "news.ycombinator.com")
(#<sockaddr-in 209.216.230.207> #<sockaddr-in 209.216.230.207>
#<sockaddr-in6 2606:7100:1:67::26> #<sockaddr-in6 2606:7100:1:67::26>)