diff --git a/src/openssl/tls.c b/src/openssl/tls.c index a3267c52..ad940ef8 100644 --- a/src/openssl/tls.c +++ b/src/openssl/tls.c @@ -404,6 +404,39 @@ getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_ return GETDNS_RETURN_GOOD; } +getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8_t* buf, size_t to_write, size_t* written) +{ + int swritten; + + if (!conn || !conn->ssl || !written) + return -GETDNS_RETURN_INVALID_PARAMETER; + + ERR_clear_error(); + swritten = SSL_write(conn->ssl, buf, to_write); + if (swritten <= 0) { + switch(SSL_get_error(conn->ssl, swritten)) { + case SSL_ERROR_WANT_READ: + /* SSL_write will not do partial writes, because + * SSL_MODE_ENABLE_PARTIAL_WRITE is not default, + * but the write could fail because of renegotiation. + * In that case SSL_get_error() will return + * SSL_ERROR_WANT_READ or, SSL_ERROR_WANT_WRITE. + * Return for retry in such cases. + */ + return GETDNS_RETURN_TLS_WANT_READ; + + case SSL_ERROR_WANT_WRITE: + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } + } + + *written = swritten; + return GETDNS_RETURN_GOOD; +} + getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s) { if (!s || !s->ssl) diff --git a/src/openssl/tls.h b/src/openssl/tls.h index 44a50bd2..dda05030 100644 --- a/src/openssl/tls.h +++ b/src/openssl/tls.h @@ -120,6 +120,21 @@ getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* */ getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read); +/** + * Write to TLS. + * + * @param conn the connection. + * @param buf the buffer to write from. + * @param to_write the number of bytes to write. + * @param written the number of bytes written. + * @return GETDNS_RETURN_GOOD if some bytes were read. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_WANT_READ if handshake isn't finished. + * @return GETDNS_RETURN_TLS_WANT_WRITE if the write needs to be retried. + * @return GETDNS_RETURN_GENERIC_ERROR if write failed. + */ +getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8_t* buf, size_t to_write, size_t* written); + getdns_return_t _getdns_tls_session_free(_getdns_tls_session* s); getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict); diff --git a/src/stub.c b/src/stub.c index 28d2e983..75ee576d 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1359,10 +1359,10 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, getdns_network_req *netreq) { size_t pkt_len; - ssize_t written; + size_t written; uint16_t query_id; intptr_t query_id_intptr; - SSL* tls_obj = upstream->tls_obj->ssl; + _getdns_tls_connection* tls_obj = upstream->tls_obj; uint16_t padding_sz; int q = tls_connected(upstream); @@ -1437,7 +1437,6 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, * Lets see how much of it we can write */ /* TODO[TLS]: Handle error cases, partial writes, renegotiation etc. */ - ERR_clear_error(); #if INTERCEPT_COM_DS /* Intercept and do not sent out COM DS queries. For debugging * purposes only. Never commit with this turned on. @@ -1454,22 +1453,16 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, written = pkt_len + 2; } else #endif - written = SSL_write(tls_obj, netreq->query - 2, pkt_len + 2); - if (written <= 0) { - /* SSL_write will not do partial writes, because - * SSL_MODE_ENABLE_PARTIAL_WRITE is not default, - * but the write could fail because of renegotiation. - * In that case SSL_get_error() will return - * SSL_ERROR_WANT_READ or, SSL_ERROR_WANT_WRITE. - * Return for retry in such cases. - */ - switch (SSL_get_error(tls_obj, written)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - return STUB_TCP_RETRY; - default: - return STUB_TCP_ERROR; - } + switch ((int)_getdns_tls_connection_write(tls_obj, netreq->query - 2, pkt_len + 2, &written)) { + case GETDNS_RETURN_GOOD: + break; + + case GETDNS_RETURN_TLS_WANT_READ: + case GETDNS_RETURN_TLS_WANT_WRITE: + return STUB_TCP_RETRY; + + default: + return STUB_TCP_ERROR; } /* We were able to write everything! Start reading. */ return (int) query_id;