/** * Callback function to process the SSL handshake. */ static gboolean ssl_connect_cb(gint sk, gpointer user_data) { gint l; gboolean res; HybridSslConnection *ssl_conn = (HybridSslConnection*)user_data; if (!SSL_set_fd(ssl_conn->ssl, sk)) { hybrid_debug_error("ssl", "add ssl to tcp socket:%s", ERR_reason_error_string(ERR_get_error())); return FALSE; } ssl_conn->sk = sk; SSL_set_connect_state(ssl_conn->ssl); ssl_reconnect: l = SSL_connect(ssl_conn->ssl); switch (SSL_get_error(ssl_conn->ssl, l)) { case SSL_ERROR_NONE: goto ssl_ok; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: usleep(100); goto ssl_reconnect; case SSL_ERROR_SYSCALL: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SSL: default: ERR_print_errors_fp(stderr); goto ssl_err; break; } ssl_ok: if (HYBRID_OK != ssl_verify_certs(ssl_conn->ssl)) { return FALSE; } res = ssl_conn->conn_cb(ssl_conn, ssl_conn->conn_data); return res; ssl_err: { // TODO network error } return FALSE; }
HybridSslConnection* hybrid_ssl_connect_with_fd(gint sk, ssl_callback func, gpointer user_data) { gint l; SSL *ssl; BIO *sbio; BIO *buf_io; BIO *ssl_bio; SSL_CTX *ssl_ctx; HybridSslConnection *ssl_conn; SSL_load_error_strings(); SSL_library_init(); if (!(ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) { hybrid_debug_error("ssl", "initialize SSL CTX: %s", ERR_reason_error_string(ERR_get_error())); return NULL; } if (!(ssl = ssl_new_with_certs(ssl_ctx))) { return NULL; } if (!SSL_set_fd(ssl, sk)) { hybrid_debug_error("ssl", "add ssl to tcp socket:%s", ERR_reason_error_string(ERR_get_error())); return NULL; } sbio = BIO_new(BIO_s_socket()); BIO_set_fd(sbio, sk, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio); SSL_set_connect_state(ssl); reconnect: l = SSL_connect(ssl); switch (SSL_get_error(ssl, l)) { case SSL_ERROR_NONE: goto ssl_conn_sk_ok; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: usleep(100); goto reconnect; case SSL_ERROR_SYSCALL: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SSL: default: hybrid_debug_error("ssl", "ssl hand-shake error:%s", ERR_reason_error_string(ERR_get_error())); return NULL; } ssl_conn_sk_ok: if (HYBRID_OK != ssl_verify_certs(ssl)) { return NULL; } SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); buf_io = BIO_new(BIO_f_buffer()); ssl_bio = BIO_new(BIO_f_ssl()); BIO_set_ssl(ssl_bio, ssl, BIO_NOCLOSE); BIO_push(buf_io, ssl_bio); ssl_conn = g_new0(HybridSslConnection, 1); ssl_conn->sk = sk; ssl_conn->ssl = ssl; ssl_conn->ssl_ctx = ssl_ctx; ssl_conn->conn_cb = func; ssl_conn->conn_data = user_data; ssl_conn->rbio = buf_io; ssl_conn->wbio = sbio; if (func) { func(ssl_conn, user_data); } return ssl_conn; }