2 ms·
Looks fine from my armchair: This is the TXR Lisp interactive listener of TXR 298. Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet. 1
by kazinator 2y ago
Looks fine from my armchair:
This is the TXR Lisp interactive listener of TXR 298.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
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))
It would be tidy to deduplicate that, though it is overhead.
- titanomachy 2y agoWhy is your lisp rendering ipv4 and ipv6 addresses as integers instead of octets...?
- kazinator 2y agoBecause 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>)