mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
net: add failed addresses + details on connect errors, make connect more robust in the default non blocking mode (#15364)
This commit is contained in:
parent
d6b594c4e8
commit
fd1b6efea6
9 changed files with 202 additions and 41 deletions
|
@ -1,6 +1,7 @@
|
|||
module net
|
||||
|
||||
import time
|
||||
import strings
|
||||
|
||||
const (
|
||||
tcp_default_read_timeout = 30 * time.second
|
||||
|
@ -24,12 +25,16 @@ pub fn dial_tcp(address string) ?&TcpConn {
|
|||
return error('$err.msg(); could not resolve address $address in dial_tcp')
|
||||
}
|
||||
|
||||
// Keep track of dialing errors that take place
|
||||
mut errs := []IError{}
|
||||
|
||||
// Very simple dialer
|
||||
for addr in addrs {
|
||||
mut s := new_tcp_socket(addr.family()) or {
|
||||
return error('$err.msg(); could not create new tcp socket in dial_tcp')
|
||||
}
|
||||
s.connect(addr) or {
|
||||
errs << err
|
||||
// Connection failed
|
||||
s.close() or { continue }
|
||||
continue
|
||||
|
@ -41,8 +46,20 @@ pub fn dial_tcp(address string) ?&TcpConn {
|
|||
write_timeout: net.tcp_default_write_timeout
|
||||
}
|
||||
}
|
||||
|
||||
// Once we've failed now try and explain why we failed to connect
|
||||
// to any of these addresses
|
||||
mut err_builder := strings.new_builder(1024)
|
||||
err_builder.write_string('dial_tcp failed for address $address\n')
|
||||
err_builder.write_string('tried addrs:\n')
|
||||
for i := 0; i < errs.len; i++ {
|
||||
addr := addrs[i]
|
||||
why := errs[i]
|
||||
err_builder.write_string('\t$addr: $why\n')
|
||||
}
|
||||
|
||||
// failed
|
||||
return error('dial_tcp failed for address $address')
|
||||
return error(err_builder.str())
|
||||
}
|
||||
|
||||
// bind local address and dail.
|
||||
|
@ -431,34 +448,39 @@ fn (mut s TcpSocket) connect(a Addr) ? {
|
|||
if res == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// The socket is nonblocking and the connection cannot be completed
|
||||
// immediately. (UNIX domain sockets failed with EAGAIN instead.)
|
||||
// It is possible to select(2) or poll(2) for completion by selecting
|
||||
// the socket for writing. After select(2) indicates writability,
|
||||
// use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to
|
||||
// determine whether connect() completed successfully (SO_ERROR is zero) or
|
||||
// unsuccessfully (SO_ERROR is one of the usual error codes listed here,
|
||||
// ex‐ plaining the reason for the failure).
|
||||
write_result := s.@select(.write, net.connect_timeout)?
|
||||
if write_result {
|
||||
ecode := error_code()
|
||||
// On nix non-blocking sockets we expect einprogress
|
||||
// On windows we expect res == -1 && error_code() == ewouldblock
|
||||
if (is_windows && ecode == int(error_ewouldblock))
|
||||
|| (!is_windows && res == -1 && ecode == int(error_einprogress)) {
|
||||
// The socket is nonblocking and the connection cannot be completed
|
||||
// immediately. (UNIX domain sockets failed with EAGAIN instead.)
|
||||
// It is possible to select(2) or poll(2) for completion by selecting
|
||||
// the socket for writing. After select(2) indicates writability,
|
||||
// use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to
|
||||
// determine whether connect() completed successfully (SO_ERROR is zero) or
|
||||
// unsuccessfully (SO_ERROR is one of the usual error codes listed here,
|
||||
// ex‐ plaining the reason for the failure).
|
||||
write_result := s.@select(.write, net.connect_timeout)?
|
||||
err := 0
|
||||
len := sizeof(err)
|
||||
socket_error(C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len))?
|
||||
|
||||
if err != 0 {
|
||||
return wrap_error(err)
|
||||
xyz := C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len)
|
||||
if xyz == 0 && err == 0 {
|
||||
return
|
||||
}
|
||||
// Succeeded
|
||||
return
|
||||
if write_result {
|
||||
if xyz == 0 {
|
||||
wrap_error(err)?
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return err_timed_out
|
||||
}
|
||||
|
||||
// Get the error
|
||||
socket_error(C.connect(s.handle, voidptr(&a), a.len()))?
|
||||
|
||||
// otherwise we timed out
|
||||
return err_connect_timed_out
|
||||
wrap_error(ecode)?
|
||||
return
|
||||
} $else {
|
||||
socket_error(C.connect(s.handle, voidptr(&a), a.len()))?
|
||||
x := C.connect(s.handle, voidptr(&a), a.len())
|
||||
socket_error(x)?
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue