Rewrite SMTP connect code to properly handle all network errors

Previously e.g. a SocketTimeoutException would exit the loop to test all addresses early.
This commit is contained in:
cketti 2022-10-07 17:45:42 +02:00
parent 142124c19a
commit 2bd2f22b1f

View file

@ -33,7 +33,6 @@ import java.net.Inet6Address
import java.net.InetAddress import java.net.InetAddress
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Socket import java.net.Socket
import java.net.SocketException
import java.security.GeneralSecurityException import java.security.GeneralSecurityException
import java.util.Locale import java.util.Locale
import javax.net.ssl.SSLException import javax.net.ssl.SSLException
@ -83,35 +82,10 @@ class SmtpTransport(
@Throws(MessagingException::class) @Throws(MessagingException::class)
override fun open() { override fun open() {
try { try {
var secureConnection = false var secureConnection = connectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED
val addresses = InetAddress.getAllByName(host)
for ((index, address) in addresses.withIndex()) {
try {
val socketAddress = InetSocketAddress(address, port)
if (connectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) {
socket = trustedSocketFactory.createSocket(null, host, port, clientCertificateAlias).also {
it.connect(socketAddress, SOCKET_CONNECT_TIMEOUT)
}
secureConnection = true
} else {
socket = Socket().also {
it.connect(socketAddress, SOCKET_CONNECT_TIMEOUT)
}
}
} catch (e: SocketException) {
if (index < addresses.lastIndex) {
// there are still other addresses for that host to try
continue
}
throw MessagingException("Cannot connect to host", e) val socket = connect()
} this.socket = socket
// connection success
break
}
val socket = this.socket ?: error("socket == null")
socket.soTimeout = SOCKET_READ_TIMEOUT socket.soTimeout = SOCKET_READ_TIMEOUT
@ -263,6 +237,39 @@ class SmtpTransport(
} }
} }
private fun connect(): Socket {
val inetAddresses = InetAddress.getAllByName(host)
var connectException: Exception? = null
for (address in inetAddresses) {
connectException = try {
return connectToAddress(address)
} catch (e: IOException) {
Timber.w(e, "Could not connect to %s", address)
e
}
}
throw MessagingException("Cannot connect to host", connectException)
}
private fun connectToAddress(address: InetAddress): Socket {
if (K9MailLib.isDebug() && K9MailLib.DEBUG_PROTOCOL_SMTP) {
Timber.d("Connecting to %s as %s", host, address)
}
val socketAddress = InetSocketAddress(address, port)
val socket = if (connectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) {
trustedSocketFactory.createSocket(null, host, port, clientCertificateAlias)
} else {
Socket()
}
socket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT)
return socket
}
private fun readGreeting() { private fun readGreeting() {
val smtpResponse = responseParser!!.readGreeting() val smtpResponse = responseParser!!.readGreeting()
logResponse(smtpResponse) logResponse(smtpResponse)