gint er_dtls_connection_send(ErDtlsConnection *self, gpointer data, gint len) { g_return_val_if_fail(ER_IS_DTLS_CONNECTION(self), 0); int ret = 0; g_return_val_if_fail(self->priv->ssl, 0); g_return_val_if_fail(self->priv->bio, 0); LOG_TRACE(self, "locking @ send"); g_mutex_lock(&self->priv->mutex); LOG_TRACE(self, "locked @ send"); if (SSL_is_init_finished(self->priv->ssl)) { ret = SSL_write(self->priv->ssl, data, len); LOG_DEBUG(self, "data sent: input was %d B, output is %d B", len, ret); } else { LOG_WARNING(self, "tried to send data before handshake was complete"); ret = 0; } LOG_TRACE(self, "unlocking @ send"); g_mutex_unlock(&self->priv->mutex); return ret; }
void er_dtls_connection_close(ErDtlsConnection *self) { g_return_if_fail(ER_IS_DTLS_CONNECTION(self)); g_return_if_fail(self->priv->ssl); g_return_if_fail(self->priv->bio); LOG_DEBUG(self, "closing connection"); LOG_TRACE(self, "locking @ close"); g_mutex_lock(&self->priv->mutex); LOG_TRACE(self, "locked @ close"); if (self->priv->is_alive) { self->priv->is_alive = FALSE; g_cond_signal(&self->priv->condition); } LOG_TRACE(self, "unlocking @ close"); g_mutex_unlock(&self->priv->mutex); if (self->priv->thread) { g_thread_join(self->priv->thread); self->priv->thread = NULL; } LOG_DEBUG(self, "closed connection"); }
void er_dtls_connection_start_timeout(ErDtlsConnection *self) { g_return_if_fail(ER_IS_DTLS_CONNECTION(self)); ErDtlsConnectionPrivate *priv = self->priv; GError *error = NULL; gchar *thread_name = g_strdup_printf("connection_thread_%p", self); LOG_TRACE(self, "locking @ start_timeout"); g_mutex_lock(&priv->mutex); LOG_TRACE(self, "locked @ start_timeout"); LOG_INFO(self, "starting connection timeout"); priv->thread = g_thread_try_new(thread_name, (GThreadFunc) connection_timeout_thread_func, self, &error); if (error) { LOG_WARNING(self, "error creating connection thread: %s (%d)", error->message, error->code); g_clear_error(&error); } g_free(thread_name); LOG_TRACE(self, "unlocking @ start_timeout"); g_mutex_unlock(&priv->mutex); }
void er_dtls_connection_start(ErDtlsConnection *self, gboolean is_client) { g_return_if_fail(ER_IS_DTLS_CONNECTION(self)); ErDtlsConnectionPrivate *priv = self->priv; g_return_if_fail(priv->send_closure); g_return_if_fail(priv->ssl); g_return_if_fail(priv->bio); LOG_TRACE(self, "locking @ start"); g_mutex_lock(&priv->mutex); LOG_TRACE(self, "locked @ start"); priv->is_alive = TRUE; priv->timeout_set = FALSE; priv->bio_buffer = NULL; priv->bio_buffer_len = 0; priv->bio_buffer_offset = 0; priv->keys_exported = FALSE; priv->is_client = is_client; if (priv->is_client) { SSL_set_connect_state(priv->ssl); } else { SSL_set_accept_state(priv->ssl); } log_state(self, "initial state set"); openssl_poll(self); log_state(self, "first poll done"); priv->thread = NULL; LOG_TRACE(self, "unlocking @ start"); g_mutex_unlock(&priv->mutex); }
void er_dtls_connection_set_send_callback(ErDtlsConnection *self, GClosure *closure) { g_return_if_fail(ER_IS_DTLS_CONNECTION(self)); LOG_TRACE(self, "locking @ set_send_callback"); g_mutex_lock(&self->priv->mutex); LOG_TRACE(self, "locked @ set_send_callback"); self->priv->send_closure = closure; if (closure && G_CLOSURE_NEEDS_MARSHAL(closure)) { g_closure_set_marshal(closure, g_cclosure_marshal_generic); } LOG_TRACE(self, "unlocking @ set_send_callback"); g_mutex_unlock(&self->priv->mutex); }
static void on_key_received(ErDtlsConnection *connection, gpointer key, guint cipher, guint auth, GstErDtlsEnc *self) { gpointer key_dup; gchar *key_str; g_return_if_fail(GST_IS_ER_DTLS_ENC(self)); g_return_if_fail(ER_IS_DTLS_CONNECTION(connection)); self->srtp_cipher = cipher; self->srtp_auth = auth; key_dup = g_memdup(key, ER_DTLS_SRTP_MASTER_KEY_LENGTH); self->encoder_key = gst_buffer_new_wrapped(key_dup, ER_DTLS_SRTP_MASTER_KEY_LENGTH); key_str = g_base64_encode(key, ER_DTLS_SRTP_MASTER_KEY_LENGTH); GST_INFO_OBJECT(self, "received key: %s", key_str); g_free(key_str); g_signal_emit(self, signals[SIGNAL_ON_KEY_RECEIVED], 0); }
gint er_dtls_connection_process(ErDtlsConnection *self, gpointer data, gint len) { g_return_val_if_fail(ER_IS_DTLS_CONNECTION(self), 0); ErDtlsConnectionPrivate *priv = self->priv; gint result; g_return_val_if_fail(self->priv->ssl, 0); g_return_val_if_fail(self->priv->bio, 0); LOG_TRACE(self, "locking @ process"); g_mutex_lock(&priv->mutex); LOG_TRACE(self, "locked @ process"); g_warn_if_fail(!priv->bio_buffer); priv->bio_buffer = data; priv->bio_buffer_len = len; priv->bio_buffer_offset = 0; log_state(self, "process start"); if (SSL_want_write(priv->ssl)) { openssl_poll(self); log_state(self, "process want write, after poll"); } result = SSL_read(priv->ssl, data, len); log_state(self, "process after read"); openssl_poll(self); log_state(self, "process after poll"); LOG_DEBUG(self, "read result: %d", result); LOG_TRACE(self, "unlocking @ process"); g_mutex_unlock(&priv->mutex); return result; }
void er_dtls_connection_stop(ErDtlsConnection *self) { g_return_if_fail(ER_IS_DTLS_CONNECTION(self)); g_return_if_fail(self->priv->ssl); g_return_if_fail(self->priv->bio); LOG_DEBUG(self, "stopping connection"); LOG_TRACE(self, "locking @ stop"); g_mutex_lock(&self->priv->mutex); LOG_TRACE(self, "locked @ stop"); self->priv->is_alive = FALSE; LOG_TRACE(self, "signaling @ stop"); g_cond_signal(&self->priv->condition); LOG_TRACE(self, "signaled @ stop"); LOG_TRACE(self, "unlocking @ stop"); g_mutex_unlock(&self->priv->mutex); LOG_DEBUG(self, "stopped connection"); }
static int openssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { ErDtlsConnection *self; SSL *ssl; BIO *bio; gchar *pem = NULL; gboolean accepted = FALSE; ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); self = SSL_get_ex_data(ssl, connection_ex_index); g_return_val_if_fail(ER_IS_DTLS_CONNECTION(self), FALSE); pem = _er_dtls_x509_to_pem(x509_ctx->cert); if (!pem) { LOG_WARNING(self, "failed to convert received certificate to pem format"); } else { bio = BIO_new(BIO_s_mem()); if (bio) { gchar buffer[2048]; gint len; len = X509_NAME_print_ex(bio, X509_get_subject_name(x509_ctx->cert), 1, XN_FLAG_MULTILINE); BIO_read(bio, buffer, len); buffer[len] = '\0'; LOG_DEBUG(self, "Peer certificate received:\n%s", buffer); BIO_free(bio); } else { LOG_DEBUG(self, "failed to create certificate print membio"); } g_signal_emit(self, signals[SIGNAL_ON_PEER_CERTIFICATE], 0, pem, &accepted); g_free(pem); } return accepted; }