Skip to content

Dubious logic in `TcpStream::connect`

Due to the current implementation of TcpStream::connect (!473 (merged)), picodata run appears to be broken in certain setups (many modern linux distributions e.g. Arch, Fedora; Mac):

$ picodata run
...
2024-04-26 12:16:08.171 [574389] main/103/interactive I> tx_binary: bound to [::1]:3301
2024-04-26 12:16:08.171 [574389] main/103/interactive/box.load_cfg I> set 'listen' configuration option to "localhost:3301"
2024-04-26 12:16:08.173 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
2024-04-26 12:16:08.373 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
2024-04-26 12:16:08.574 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
...
$ picodata run --listen localhost:3301
...
2024-04-26 12:16:08.171 [574389] main/103/interactive I> tx_binary: bound to [::1]:3301
2024-04-26 12:16:08.171 [574389] main/103/interactive/box.load_cfg I> set 'listen' configuration option to "localhost:3301"
2024-04-26 12:16:08.173 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
2024-04-26 12:16:08.373 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
2024-04-26 12:16:08.574 [574389] main/103/interactive discovery.rs:199 W> calling .proc_discover failed to 'localhost:3301' failed: failed to connect to address 'localhost:3301': Connection refused (os error 111)
...

The key takeaway here is that localhost has been resolved to an IPv6 address [::1] in the server socket binding logic, but the connection establishing function used by picodata run:

  • prioritizes IPv4 addresses (which is fine)
  • only tries to connect to a first IPv4 address, completely disregarding IPv6 addresses (which is wrong).

Furthermore, nonblocking_socket() is also flawed, because it only creates IPv4 sockets (AF_INET), whereas IPv6 sockets require AF_INET6.

While it is true that the problem can be solved by using an explicit IPv4 address (i.e. picodata run --listen 127.0.0.1:3301), at the very least we should fix the defaults in picodata run.


Addendum: example of a correct solution to this problem:

https://doc.rust-lang.org/src/std/net/tcp.rs.html#156-158

https://doc.rust-lang.org/src/std/net/mod.rs.html#71-89

Edited by Dmitry Ivanov