summaryrefslogtreecommitdiff
path: root/worker/imap/worker.go
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2022-04-30 01:08:58 +0200
committerRobin Jarry <robin@jarry.cc>2022-05-04 14:07:15 +0200
commitb29293d7b53c73629911ec75b2ec5954d365feed (patch)
tree78c31ee55d9fce81007fb3c436b8241fb3ed14f5 /worker/imap/worker.go
parentb92efe4cd944c97bf8310ca47d4edbef968cfaae (diff)
downloadaerc-b29293d7b53c73629911ec75b2ec5954d365feed.zip
imap: add timeout to tcp connect functions
Extract the tcp connection details and timeout the tcp connect functions (net.ResolveTCPAddr and net.DialTCP). If timed out, ensure that the connection is properly closed. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'worker/imap/worker.go')
-rw-r--r--worker/imap/worker.go130
1 files changed, 10 insertions, 120 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 1ff6341..eabaae0 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -1,9 +1,7 @@
package imap
import (
- "crypto/tls"
"fmt"
- "net"
"net/url"
"time"
@@ -25,6 +23,7 @@ func init() {
var (
errUnsupported = fmt.Errorf("unsupported command")
+ errClientNotReady = fmt.Errorf("client not ready")
errNotConnected = fmt.Errorf("not connected")
errAlreadyConnected = fmt.Errorf("already connected")
)
@@ -93,6 +92,15 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
var reterr error // will be returned at the end, needed to support idle
+ // when client is nil allow only certain messages to be handled
+ if w.client == nil {
+ switch msg.(type) {
+ case *types.Connect, *types.Reconnect, *types.Disconnect, *types.Configure:
+ default:
+ return errClientNotReady
+ }
+ }
+
// set connection timeout for calls to imap server
if w.client != nil {
w.client.Timeout = w.config.connection_timeout
@@ -251,124 +259,6 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
}
}
-func (w *IMAPWorker) connect() (*client.Client, error) {
- var (
- conn *net.TCPConn
- c *client.Client
- )
-
- addr, err := net.ResolveTCPAddr("tcp", w.config.addr)
- if err != nil {
- return nil, err
- }
-
- conn, err = net.DialTCP("tcp", nil, addr)
- if err != nil {
- return nil, err
- }
-
- if w.config.connection_timeout > 0 {
- end := time.Now().Add(w.config.connection_timeout)
- err = conn.SetDeadline(end)
- if err != nil {
- return nil, err
- }
- }
- if w.config.keepalive_period > 0 {
- err = w.setKeepaliveParameters(conn)
- if err != nil {
- return nil, err
- }
- }
-
- serverName, _, _ := net.SplitHostPort(w.config.addr)
- tlsConfig := &tls.Config{ServerName: serverName}
-
- switch w.config.scheme {
- case "imap":
- c, err = client.New(conn)
- if err != nil {
- return nil, err
- }
- if !w.config.insecure {
- if err = c.StartTLS(tlsConfig); err != nil {
- return nil, err
- }
- }
- case "imaps":
- tlsConn := tls.Client(conn, tlsConfig)
- c, err = client.New(tlsConn)
- if err != nil {
- return nil, err
- }
- default:
- return nil, fmt.Errorf("Unknown IMAP scheme %s", w.config.scheme)
- }
-
- c.ErrorLog = w.worker.Logger
-
- if w.config.user != nil {
- username := w.config.user.Username()
- password, hasPassword := w.config.user.Password()
- if !hasPassword {
- // TODO: ask password
- }
-
- if w.config.oauthBearer.Enabled {
- if err := w.config.oauthBearer.Authenticate(
- username, password, c); err != nil {
- return nil, err
- }
- } else if err := c.Login(username, password); err != nil {
- return nil, err
- }
- }
-
- c.SetDebug(w.worker.Logger.Writer())
-
- if _, err := c.Select(imap.InboxName, false); err != nil {
- return nil, err
- }
-
- return c, nil
-}
-
-// Set additional keepalive parameters.
-// Uses new interfaces introduced in Go1.11, which let us get connection's file
-// descriptor, without blocking, and therefore without uncontrolled spawning of
-// threads (not goroutines, actual threads).
-func (w *IMAPWorker) setKeepaliveParameters(conn *net.TCPConn) error {
- err := conn.SetKeepAlive(true)
- if err != nil {
- return err
- }
- // Idle time before sending a keepalive probe
- err = conn.SetKeepAlivePeriod(w.config.keepalive_period)
- if err != nil {
- return err
- }
- rawConn, e := conn.SyscallConn()
- if e != nil {
- return e
- }
- err = rawConn.Control(func(fdPtr uintptr) {
- fd := int(fdPtr)
- // Max number of probes before failure
- err := lib.SetTcpKeepaliveProbes(fd, w.config.keepalive_probes)
- if err != nil {
- w.worker.Logger.Printf(
- "cannot set tcp keepalive probes: %v\n", err)
- }
- // Wait time after an unsuccessful probe
- err = lib.SetTcpKeepaliveInterval(fd, w.config.keepalive_interval)
- if err != nil {
- w.worker.Logger.Printf(
- "cannot set tcp keepalive interval: %v\n", err)
- }
- })
- return err
-}
-
func (w *IMAPWorker) Run() {
for {
select {