}
/**
- * raw_socket_close - Close a socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error, see errno
- */
-int raw_socket_close(struct Connection *conn)
-{
- return close(conn->fd);
-}
-
-/**
- * raw_socket_read - Read data from a socket
- * @param conn Connection to a server
- * @param buf Buffer to store the data
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes read
- * @retval -1 Error, see errno
- */
-int raw_socket_read(struct Connection *conn, char *buf, size_t len)
-{
- int rc;
-
- mutt_sig_allow_interrupt(1);
- rc = read(conn->fd, buf, len);
- if (rc == -1)
- {
- mutt_error(_("Error talking to %s (%s)"), conn->account.host, strerror(errno));
- SigInt = 0;
- }
- mutt_sig_allow_interrupt(0);
-
- if (SigInt)
- {
- mutt_error(_("Connection to %s has been aborted"), conn->account.host);
- SigInt = 0;
- rc = -1;
- }
-
- return rc;
-}
-
-/**
- * raw_socket_write - Write data to a socket
- * @param conn Connection to a server
- * @param buf Buffer to read into
- * @param count Number of bytes to read
- * @retval >0 Success, number of bytes written
- * @retval -1 Error, see errno
- */
-int raw_socket_write(struct Connection *conn, const char *buf, size_t count)
-{
- int rc;
-
- mutt_sig_allow_interrupt(1);
- rc = write(conn->fd, buf, count);
- if (rc == -1)
- {
- mutt_error(_("Error talking to %s (%s)"), conn->account.host, strerror(errno));
- SigInt = 0;
- }
- mutt_sig_allow_interrupt(0);
-
- if (SigInt)
- {
- mutt_error(_("Connection to %s has been aborted"), conn->account.host);
- SigInt = 0;
- rc = -1;
- }
-
- return rc;
-}
-
-/**
- * raw_socket_poll - Checks whether reads would block
- * @param conn Connection to a server
- * @param wait_secs How long to wait for a response
- * @retval >0 There is data to read
- * @retval 0 Read would block
- * @retval -1 Connection doesn't support polling
- */
-int raw_socket_poll(struct Connection *conn, time_t wait_secs)
-{
- fd_set rfds;
- unsigned long wait_millis;
- struct timeval tv, pre_t, post_t;
-
- if (conn->fd < 0)
- return -1;
-
- wait_millis = wait_secs * 1000UL;
-
- while (true)
- {
- tv.tv_sec = wait_millis / 1000;
- tv.tv_usec = (wait_millis % 1000) * 1000;
-
- FD_ZERO(&rfds);
- FD_SET(conn->fd, &rfds);
-
- gettimeofday(&pre_t, NULL);
- const int rc = select(conn->fd + 1, &rfds, NULL, NULL, &tv);
- gettimeofday(&post_t, NULL);
-
- if (rc > 0 || (rc < 0 && errno != EINTR))
- return rc;
-
- if (SigInt)
- mutt_query_exit();
-
- wait_millis += (pre_t.tv_sec * 1000UL) + (pre_t.tv_usec / 1000);
- const unsigned long post_t_millis = (post_t.tv_sec * 1000UL) + (post_t.tv_usec / 1000);
- if (wait_millis <= post_t_millis)
- return 0;
- wait_millis -= post_t_millis;
- }
-}
-
-/**
- * raw_socket_open - Open a socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error
+ * raw_socket_open - Open a socket - Implements Connection::conn_open()
*/
int raw_socket_open(struct Connection *conn)
{
return 0;
}
+
+/**
+ * raw_socket_read - Read data from a socket - Implements Connection::conn_read()
+ */
+int raw_socket_read(struct Connection *conn, char *buf, size_t len)
+{
+ int rc;
+
+ mutt_sig_allow_interrupt(1);
+ rc = read(conn->fd, buf, len);
+ if (rc == -1)
+ {
+ mutt_error(_("Error talking to %s (%s)"), conn->account.host, strerror(errno));
+ SigInt = 0;
+ }
+ mutt_sig_allow_interrupt(0);
+
+ if (SigInt)
+ {
+ mutt_error(_("Connection to %s has been aborted"), conn->account.host);
+ SigInt = 0;
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/**
+ * raw_socket_write - Write data to a socket - Implements Connection::conn_write()
+ */
+int raw_socket_write(struct Connection *conn, const char *buf, size_t count)
+{
+ int rc;
+
+ mutt_sig_allow_interrupt(1);
+ rc = write(conn->fd, buf, count);
+ if (rc == -1)
+ {
+ mutt_error(_("Error talking to %s (%s)"), conn->account.host, strerror(errno));
+ SigInt = 0;
+ }
+ mutt_sig_allow_interrupt(0);
+
+ if (SigInt)
+ {
+ mutt_error(_("Connection to %s has been aborted"), conn->account.host);
+ SigInt = 0;
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/**
+ * raw_socket_poll - Checks whether reads would block - Implements Connection::conn_poll()
+ */
+int raw_socket_poll(struct Connection *conn, time_t wait_secs)
+{
+ fd_set rfds;
+ unsigned long wait_millis;
+ struct timeval tv, pre_t, post_t;
+
+ if (conn->fd < 0)
+ return -1;
+
+ wait_millis = wait_secs * 1000UL;
+
+ while (true)
+ {
+ tv.tv_sec = wait_millis / 1000;
+ tv.tv_usec = (wait_millis % 1000) * 1000;
+
+ FD_ZERO(&rfds);
+ FD_SET(conn->fd, &rfds);
+
+ gettimeofday(&pre_t, NULL);
+ const int rc = select(conn->fd + 1, &rfds, NULL, NULL, &tv);
+ gettimeofday(&post_t, NULL);
+
+ if (rc > 0 || (rc < 0 && errno != EINTR))
+ return rc;
+
+ if (SigInt)
+ mutt_query_exit();
+
+ wait_millis += (pre_t.tv_sec * 1000UL) + (pre_t.tv_usec / 1000);
+ const unsigned long post_t_millis = (post_t.tv_sec * 1000UL) + (post_t.tv_usec / 1000);
+ if (wait_millis <= post_t_millis)
+ return 0;
+ wait_millis -= post_t_millis;
+ }
+}
+
+/**
+ * raw_socket_close - Close a socket - Implements Connection::conn_close()
+ */
+int raw_socket_close(struct Connection *conn)
+{
+ return close(conn->fd);
+}
TAILQ_ENTRY(Connection) entries;
void *sockdata;
- int (*conn_read)(struct Connection *conn, char *buf, size_t len);
+
+ /**
+ * conn_open - Open a socket Connection
+ * @param conn Connection to a server
+ * @retval 0 Success
+ * @retval -1 Error
+ */
+ int (*conn_open) (struct Connection *conn);
+ /**
+ * conn_read - Read from a socket Connection
+ * @param conn Connection to a server
+ * @param buf Buffer to store the data
+ * @param len Number of bytes to read
+ * @retval >0 Success, number of bytes read
+ * @retval -1 Error, see errno
+ */
+ int (*conn_read) (struct Connection *conn, char *buf, size_t len);
+ /**
+ * conn_write - Write to a socket Connection
+ * @param conn Connection to a server
+ * @param buf Buffer to read into
+ * @param len Number of bytes to read
+ * @retval >0 Success, number of bytes written
+ * @retval -1 Error, see errno
+ */
int (*conn_write)(struct Connection *conn, const char *buf, size_t count);
- int (*conn_open)(struct Connection *conn);
+ /**
+ * conn_poll - Check whether a socket read would block
+ * @param conn Connection to a server
+ * @param wait_secs How long to wait for a response
+ * @retval >0 There is data to read
+ * @retval 0 Read would block
+ * @retval -1 Connection doesn't support polling
+ */
+ int (*conn_poll) (struct Connection *conn, time_t wait_secs);
+ /**
+ * conn_close - Close a socket Connection
+ * @param conn Connection to a server
+ * @retval 0 Success
+ * @retval -1 Error, see errno
+ */
int (*conn_close)(struct Connection *conn);
- int (*conn_poll)(struct Connection *conn, time_t wait_secs);
};
#endif /* MUTT_CONN_CONNECTION_H */
/* restore connection's underlying methods */
conn->sockdata = sasldata->sockdata;
conn->conn_open = sasldata->msasl_open;
- conn->conn_close = sasldata->msasl_close;
conn->conn_read = sasldata->msasl_read;
conn->conn_write = sasldata->msasl_write;
conn->conn_poll = sasldata->msasl_poll;
+ conn->conn_close = sasldata->msasl_close;
/* release sasl resources */
sasl_dispose(&sasldata->saslconn);
/* preserve old functions */
sasldata->sockdata = conn->sockdata;
sasldata->msasl_open = conn->conn_open;
- sasldata->msasl_close = conn->conn_close;
sasldata->msasl_read = conn->conn_read;
sasldata->msasl_write = conn->conn_write;
sasldata->msasl_poll = conn->conn_poll;
+ sasldata->msasl_close = conn->conn_close;
/* and set up new functions */
conn->sockdata = sasldata;
conn->conn_open = mutt_sasl_conn_open;
- conn->conn_close = mutt_sasl_conn_close;
conn->conn_read = mutt_sasl_conn_read;
conn->conn_write = mutt_sasl_conn_write;
conn->conn_poll = mutt_sasl_conn_poll;
+ conn->conn_close = mutt_sasl_conn_close;
}
/**
/* underlying socket data */
void *sockdata;
- int (*msasl_open)(struct Connection *conn);
+ int (*msasl_open) (struct Connection *conn);
int (*msasl_close)(struct Connection *conn);
- int (*msasl_read)(struct Connection *conn, char *buf, size_t len);
+ int (*msasl_read) (struct Connection *conn, char *buf, size_t len);
int (*msasl_write)(struct Connection *conn, const char *buf, size_t count);
- int (*msasl_poll)(struct Connection *conn, time_t wait_secs);
+ int (*msasl_poll) (struct Connection *conn, time_t wait_secs);
};
#endif /* MUTT_CONN_SASL_H */
* open up another connection to the same server in this session */
static STACK_OF(X509) *SslSessionCerts = NULL;
+static int ssl_socket_close(struct Connection *conn);
+
/**
* struct SslSockData - SSL socket data
*/
return -1;
}
-/**
- * ssl_socket_close - Close an SSL connection
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error, see errno
- */
-static int ssl_socket_close(struct Connection *conn)
-{
- struct SslSockData *data = conn->sockdata;
-
- if (data)
- {
- if (data->isopen)
- SSL_shutdown(data->ssl);
-
- /* hold onto this for the life of neomutt, in case we want to reconnect.
- * The purist in me wants a mutt_exit hook. */
- SSL_free(data->ssl);
- SSL_CTX_free(data->ctx);
- FREE(&conn->sockdata);
- }
-
- return raw_socket_close(conn);
-}
-
/**
* x509_get_part - Retrieve from X509 data
* @param name Name of data to retrieve
return 0;
}
-/**
- * ssl_socket_read - Read data from an SSL socket
- * @param conn Connection to a server
- * @param buf Buffer to store the data
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes read
- * @retval -1 Error, see errno
- */
-static int ssl_socket_read(struct Connection *conn, char *buf, size_t len)
-{
- struct SslSockData *data = conn->sockdata;
- int rc;
-
- rc = SSL_read(data->ssl, buf, len);
- if (rc <= 0 || errno == EINTR)
- {
- if (errno == EINTR)
- {
- rc = -1;
- }
- data->isopen = 0;
- ssl_err(data, rc);
- }
-
- return rc;
-}
-
-/**
- * ssl_socket_write - Write data to an SSL socket
- * @param conn Connection to a server
- * @param buf Buffer to read into
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes written
- * @retval -1 Error, see errno
- */
-static int ssl_socket_write(struct Connection *conn, const char *buf, size_t len)
-{
- struct SslSockData *data = conn->sockdata;
- int rc;
-
- rc = SSL_write(data->ssl, buf, len);
- if (rc <= 0 || errno == EINTR)
- {
- if (errno == EINTR)
- {
- rc = -1;
- }
- ssl_err(data, rc);
- }
-
- return rc;
-}
-
/**
* ssl_get_client_cert - Get the client certificate for an SSL connection
* @param ssldata SSL socket data
}
/**
- * ssl_socket_open - Open an SSL socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error
+ * ssl_socket_open - Open an SSL socket - Implements Connection::conn_open()
*/
static int ssl_socket_open(struct Connection *conn)
{
- int ret;
-
if (raw_socket_open(conn) < 0)
return -1;
- ret = ssl_setup(conn);
+ int ret = ssl_setup(conn);
if (ret)
raw_socket_close(conn);
return ret;
}
+/**
+ * ssl_socket_read - Read data from an SSL socket - Implements Connection::conn_read()
+ */
+static int ssl_socket_read(struct Connection *conn, char *buf, size_t len)
+{
+ struct SslSockData *data = conn->sockdata;
+ int rc;
+
+ rc = SSL_read(data->ssl, buf, len);
+ if (rc <= 0 || errno == EINTR)
+ {
+ if (errno == EINTR)
+ {
+ rc = -1;
+ }
+ data->isopen = 0;
+ ssl_err(data, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * ssl_socket_write - Write data to an SSL socket - Implements Connection::conn_write()
+ */
+static int ssl_socket_write(struct Connection *conn, const char *buf, size_t len)
+{
+ struct SslSockData *data = conn->sockdata;
+ int rc;
+
+ rc = SSL_write(data->ssl, buf, len);
+ if (rc <= 0 || errno == EINTR)
+ {
+ if (errno == EINTR)
+ {
+ rc = -1;
+ }
+ ssl_err(data, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * ssl_socket_close - Close an SSL connection - Implements Connection::conn_close()
+ */
+static int ssl_socket_close(struct Connection *conn)
+{
+ struct SslSockData *data = conn->sockdata;
+
+ if (data)
+ {
+ if (data->isopen)
+ SSL_shutdown(data->ssl);
+
+ /* hold onto this for the life of neomutt, in case we want to reconnect.
+ * The purist in me wants a mutt_exit hook. */
+ SSL_free(data->ssl);
+ SSL_CTX_free(data->ctx);
+ FREE(&conn->sockdata);
+ }
+
+ return raw_socket_close(conn);
+}
+
/**
* mutt_ssl_starttls - Negotiate TLS over an already opened connection
* @param conn Connection to a server
*/
int mutt_ssl_starttls(struct Connection *conn)
{
- int ret;
-
if (ssl_init())
return -1;
- ret = ssl_setup(conn);
+ int ret = ssl_setup(conn);
/* hmm. watch out if we're starting TLS over any method other than raw. */
conn->conn_read = ssl_socket_read;
conn->conn_open = ssl_socket_open;
conn->conn_read = ssl_socket_read;
conn->conn_write = ssl_socket_write;
- conn->conn_close = ssl_socket_close;
conn->conn_poll = raw_socket_poll;
+ conn->conn_close = ssl_socket_close;
return 0;
}
#define CERT_SEP "-----BEGIN"
+static int tls_socket_close(struct Connection *conn);
+
/**
* struct TlsSockData - TLS socket data
*/
return 0;
}
-/**
- * tls_socket_read - Read data from a TLS socket
- * @param conn Connection to a server
- * @param buf Buffer to store the data
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes read
- * @retval -1 Error, see errno
- */
-static int tls_socket_read(struct Connection *conn, char *buf, size_t len)
-{
- struct TlsSockData *data = conn->sockdata;
- int rc;
-
- if (!data)
- {
- mutt_error(_("Error: no TLS socket open"));
- return -1;
- }
-
- do
- {
- rc = gnutls_record_recv(data->state, buf, len);
- if ((rc < 0 && gnutls_error_is_fatal(rc) == 1) || rc == GNUTLS_E_INTERRUPTED)
- {
- mutt_error("tls_socket_read (%s)", gnutls_strerror(rc));
- return -1;
- }
- } while (rc == GNUTLS_E_AGAIN);
-
- return rc;
-}
-
-/**
- * tls_socket_write - Write data to a TLS socket
- * @param conn Connection to a server
- * @param buf Buffer to read into
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes written
- * @retval -1 Error, see errno
- */
-static int tls_socket_write(struct Connection *conn, const char *buf, size_t len)
-{
- struct TlsSockData *data = conn->sockdata;
- size_t sent = 0;
-
- if (!data)
- {
- mutt_error(_("Error: no TLS socket open"));
- return -1;
- }
-
- do
- {
- const int ret = gnutls_record_send(data->state, buf + sent, len - sent);
- if (ret < 0)
- {
- if (gnutls_error_is_fatal(ret) == 1 || ret == GNUTLS_E_INTERRUPTED)
- {
- mutt_error("tls_socket_write (%s)", gnutls_strerror(ret));
- return -1;
- }
- return ret;
- }
- sent += ret;
- } while (sent < len);
-
- return sent;
-}
-
-/**
- * tls_socket_close - Close a TLS socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error, see errno
- */
-static int tls_socket_close(struct Connection *conn)
-{
- struct TlsSockData *data = conn->sockdata;
- if (data)
- {
- /* shut down only the write half to avoid hanging waiting for the remote to respond.
- *
- * RFC5246 7.2.1. "Closure Alerts"
- *
- * It is not required for the initiator of the close to wait for the
- * responding close_notify alert before closing the read side of the
- * connection.
- */
- gnutls_bye(data->state, GNUTLS_SHUT_WR);
-
- gnutls_certificate_free_credentials(data->xcred);
- gnutls_deinit(data->state);
- FREE(&conn->sockdata);
- }
-
- return raw_socket_close(conn);
-}
-
/**
* tls_starttls_close - Close a TLS connection
* @param conn Connection to a server
}
/**
- * tls_socket_open - Open a TLS socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error
+ * tls_socket_open - Open a TLS socket - Implements Connection::conn_open()
*/
static int tls_socket_open(struct Connection *conn)
{
return 0;
}
+/**
+ * tls_socket_read - Read data from a TLS socket - Implements Connection::conn_read()
+ */
+static int tls_socket_read(struct Connection *conn, char *buf, size_t len)
+{
+ struct TlsSockData *data = conn->sockdata;
+ int rc;
+
+ if (!data)
+ {
+ mutt_error(_("Error: no TLS socket open"));
+ return -1;
+ }
+
+ do
+ {
+ rc = gnutls_record_recv(data->state, buf, len);
+ if ((rc < 0 && gnutls_error_is_fatal(rc) == 1) || rc == GNUTLS_E_INTERRUPTED)
+ {
+ mutt_error("tls_socket_read (%s)", gnutls_strerror(rc));
+ return -1;
+ }
+ } while (rc == GNUTLS_E_AGAIN);
+
+ return rc;
+}
+
+/**
+ * tls_socket_write - Write data to a TLS socket - Implements Connection::conn_write()
+ */
+static int tls_socket_write(struct Connection *conn, const char *buf, size_t len)
+{
+ struct TlsSockData *data = conn->sockdata;
+ size_t sent = 0;
+
+ if (!data)
+ {
+ mutt_error(_("Error: no TLS socket open"));
+ return -1;
+ }
+
+ do
+ {
+ const int ret = gnutls_record_send(data->state, buf + sent, len - sent);
+ if (ret < 0)
+ {
+ if (gnutls_error_is_fatal(ret) == 1 || ret == GNUTLS_E_INTERRUPTED)
+ {
+ mutt_error("tls_socket_write (%s)", gnutls_strerror(ret));
+ return -1;
+ }
+ return ret;
+ }
+ sent += ret;
+ } while (sent < len);
+
+ return sent;
+}
+
+/**
+ * tls_socket_close - Close a TLS socket - Implements Connection::conn_close()
+ */
+static int tls_socket_close(struct Connection *conn)
+{
+ struct TlsSockData *data = conn->sockdata;
+ if (data)
+ {
+ /* shut down only the write half to avoid hanging waiting for the remote to respond.
+ *
+ * RFC5246 7.2.1. "Closure Alerts"
+ *
+ * It is not required for the initiator of the close to wait for the
+ * responding close_notify alert before closing the read side of the
+ * connection.
+ */
+ gnutls_bye(data->state, GNUTLS_SHUT_WR);
+
+ gnutls_certificate_free_credentials(data->xcred);
+ gnutls_deinit(data->state);
+ FREE(&conn->sockdata);
+ }
+
+ return raw_socket_close(conn);
+}
+
/**
* mutt_ssl_socket_setup - Set up SSL socket mulitplexor
* @param conn Connection to a server
};
/**
- * tunnel_socket_open - Open a tunnel socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error
+ * tunnel_socket_open - Open a tunnel socket - Implements Connection::conn_open()
*/
static int tunnel_socket_open(struct Connection *conn)
{
}
/**
- * tunnel_socket_close - Close a tunnel socket
- * @param conn Connection to a server
- * @retval 0 Success
- * @retval -1 Error, see errno
- */
-static int tunnel_socket_close(struct Connection *conn)
-{
- struct TunnelData *tunnel = conn->sockdata;
- int status;
-
- close(tunnel->readfd);
- close(tunnel->writefd);
- waitpid(tunnel->pid, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status))
- {
- mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
- WEXITSTATUS(status), NONULL(mutt_str_sysexit(WEXITSTATUS(status))));
- }
- FREE(&conn->sockdata);
-
- return 0;
-}
-
-/**
- * tunnel_socket_read - Read data from a tunnel socket
- * @param conn Connection to a server
- * @param buf Buffer to store the data
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes read
- * @retval -1 Error, see errno
+ * tunnel_socket_read - Read data from a tunnel socket - Implements Connection::conn_read()
*/
static int tunnel_socket_read(struct Connection *conn, char *buf, size_t len)
{
}
/**
- * tunnel_socket_write - Write data to a tunnel socket
- * @param conn Connection to a server
- * @param buf Buffer to read into
- * @param len Number of bytes to read
- * @retval >0 Success, number of bytes written
- * @retval -1 Error, see errno
+ * tunnel_socket_write - Write data to a tunnel socket - Implements Connection::conn_write()
*/
static int tunnel_socket_write(struct Connection *conn, const char *buf, size_t len)
{
}
/**
- * tunnel_socket_poll - Checks whether tunnel reads would block
- * @param conn Connection to a server
- * @param wait_secs How long to wait for a response
- * @retval >0 There is data to read
- * @retval 0 Read would block
- * @retval -1 Connection doesn't support polling
+ * tunnel_socket_poll - Checks whether tunnel reads would block - Implements Connection::conn_poll()
*/
static int tunnel_socket_poll(struct Connection *conn, time_t wait_secs)
{
return rc;
}
+/**
+ * tunnel_socket_close - Close a tunnel socket - Implements Connection::conn_close()
+ */
+static int tunnel_socket_close(struct Connection *conn)
+{
+ struct TunnelData *tunnel = conn->sockdata;
+ int status;
+
+ close(tunnel->readfd);
+ close(tunnel->writefd);
+ waitpid(tunnel->pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status))
+ {
+ mutt_error(_("Tunnel to %s returned error %d (%s)"), conn->account.host,
+ WEXITSTATUS(status), NONULL(mutt_str_sysexit(WEXITSTATUS(status))));
+ }
+ FREE(&conn->sockdata);
+
+ return 0;
+}
+
/**
* mutt_tunnel_socket_setup - sets up tunnel connection functions
* @param conn Connection to assign functions to