int tnet_ice_candidate_send_stun_bind_request(tnet_ice_candidate_t* self, struct sockaddr_storage* server_addr, const char* username, const char* password) { tnet_stun_message_t *request = tsk_null; tsk_buffer_t *buffer = tsk_null; int ret, sendBytes; if(!self || !server_addr || !TNET_SOCKET_IS_VALID(self->socket)){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } request = _tnet_ice_candidate_stun_create_bind_request(self, username, password); if(!request){ TSK_DEBUG_ERROR("Failed to create STUN request"); ret = -2; goto bail; } if(!(buffer = tnet_stun_message_serialize(request))){ TSK_DEBUG_ERROR("Failed to serialize STUN request"); ret = -3; goto bail; } sendBytes = tnet_sockfd_sendto(self->socket->fd, (const struct sockaddr*)server_addr, buffer->data, buffer->size);// return number of sent bytes if(sendBytes == buffer->size){ memcpy(self->stun.transac_id, request->transaction_id, sizeof(tnet_stun_transacid_t)); ret = 0; } else{ TSK_DEBUG_ERROR("Only %d bytes sent", sendBytes); ret = -4; goto bail; } bail: TSK_OBJECT_SAFE_FREE(request); TSK_OBJECT_SAFE_FREE(buffer); return 0; }
tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size) { tnet_transport_t *transport = (tnet_transport_t*)handle; int numberOfBytesSent = 0; if(!transport){ TSK_DEBUG_ERROR("Invalid server handle."); goto bail; } if(!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)){ TSK_DEBUG_ERROR("In order to use sendto() you must use an udp transport."); goto bail; } if((numberOfBytesSent = tnet_sockfd_sendto(from, to, buf, size)) <= 0){ TNET_PRINT_LAST_ERROR("sendto have failed."); goto bail; } bail: return numberOfBytesSent; }
int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr) { #if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled"); return -1; #else tnet_dtls_socket_t *socket = handle; int ret = 0, len; void* out_data; if (!socket) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_safeobj_lock(socket); // update remote address even if handshaking is completed if (remote_addr) { socket->remote.addr = *remote_addr; } if (socket->handshake_completed) { TSK_DEBUG_INFO("Handshake completed"); ret = 0; goto bail; } if (!socket->handshake_started) { if ((ret = SSL_do_handshake(socket->ssl)) != 1) { switch ((ret = SSL_get_error(socket->ssl, ret))) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_NONE: break; default: TSK_DEBUG_ERROR("DTLS handshake failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_failed); ret = -2; goto bail; } } socket->handshake_started = (ret == SSL_ERROR_NONE); // TODO: reset for renegotiation } if ((len = (int)BIO_get_mem_data(socket->wbio, &out_data)) > 0 && out_data) { if (socket->handshake_storedata) { // e.g. when TURN is enabled we have to query handshaking data and sent it via the negotiated channel if ((int)socket->handshake_data.size < len) { if (!(socket->handshake_data.ptr = tsk_realloc(socket->handshake_data.ptr, len))) { socket->handshake_data.size = 0; socket->handshake_data.count = 0; ret = -5; goto bail; } socket->handshake_data.size = len; } socket->handshake_data.count = len; memcpy(socket->handshake_data.ptr, out_data, len); } else { int sentlen = 0; tnet_port_t port; tnet_ip_t ip; tsk_bool_t is_dgram = TNET_SOCKET_TYPE_IS_DGRAM(socket->wrapped_sock->type); const uint8_t *record_ptr, *records_ptr = out_data; tsk_size_t record_size; int records_len = len; tnet_get_sockip_n_port((const struct sockaddr *)&socket->remote.addr, &ip, &port); TSK_DEBUG_INFO("DTLS data handshake to send with len = %d, from(%.*s/%d) to(%.*s/%d)", len, (int)sizeof(socket->wrapped_sock->ip), socket->wrapped_sock->ip, socket->wrapped_sock->port, (int)sizeof(ip), ip, port); //!\ IP fragmentation issues must be avoided even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, &record_ptr, &record_size)) == 0) { if (is_dgram) { sentlen += tnet_sockfd_sendto(socket->wrapped_sock->fd, (const struct sockaddr *)&socket->remote.addr, record_ptr, record_size); } else { sentlen += tnet_socket_send_stream(socket->wrapped_sock, record_ptr, record_size); } records_len -= (int)record_size; records_ptr += record_size; } TSK_DEBUG_INFO("DTLS data handshake sent len = %d", sentlen); } } BIO_reset(socket->rbio); BIO_reset(socket->wbio); if ((socket->handshake_completed = SSL_is_init_finished(socket->ssl))) { TSK_DEBUG_INFO("DTLS handshake completed"); #if HAVE_OPENSSL_DTLS_SRTP if (socket->use_srtp){ #if !defined(SRTP_MAX_KEY_LEN) # define cipher_key_length (128 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles # define cipher_salt_length (112 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles // "cipher_key_length" is also equal to srtp_profile_get_master_key_length(srtp_profile_aes128_cm_sha1_80) // "cipher_salt_length" is also srtp_profile_get_master_salt_length(srtp_profile_aes128_cm_sha1_80) # define SRTP_MAX_KEY_LEN (cipher_key_length + cipher_salt_length) #endif /* SRTP_MAX_KEY_LEN */ #define EXTRACTOR_dtls_srtp_text "EXTRACTOR-dtls_srtp" #define EXTRACTOR_dtls_srtp_text_len 19 uint8_t keying_material[SRTP_MAX_KEY_LEN << 1]; static const tsk_size_t keying_material_size = sizeof(keying_material); /*if(socket->use_srtp)*/{ SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(socket->ssl); if (!p) { TSK_DEBUG_ERROR("SSL_get_selected_srtp_profile() returned null [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } // alert user _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_profile_selected, p->name, tsk_strlen(p->name)); memset(keying_material, 0, sizeof(keying_material)); // rfc5764 - 4.2. Key Derivation ret = SSL_export_keying_material(socket->ssl, keying_material, sizeof(keying_material), EXTRACTOR_dtls_srtp_text, EXTRACTOR_dtls_srtp_text_len, tsk_null, 0, 0); if (ret != 1) { // alert listener _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_error); TSK_DEBUG_ERROR("SSL_export_keying_material() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } } // alert listener _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_data, keying_material, keying_material_size); } #endif /* HAVE_OPENSSL_DTLS_SRTP */ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_succeed); } ret = 0; // clear "ret", error will directly jump to "bail:" bail: tsk_safeobj_unlock(socket); return ret; #endif }