/** * gnutls_heartbeat_get_timeout: * @session: is a #gnutls_session_t structure. * * This function will return the milliseconds remaining * for a retransmission of the previously sent ping * message. This function is useful when ping is used in * non-blocking mode, to estimate when to call gnutls_heartbeat_ping() * if no packets have been received. * * Returns: the remaining time in milliseconds. * * Since: 3.1.2 **/ unsigned int gnutls_heartbeat_get_timeout(gnutls_session_t session) { struct timespec now; unsigned int diff; gettime(&now); diff = timespec_sub_ms(&now, &session->internals.hb_ping_sent); if (diff >= session->internals.hb_actual_retrans_timeout_ms) return 0; else return session->internals.hb_actual_retrans_timeout_ms - diff; }
static ssize_t _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel, size_t size, gnutls_pull_func pull_func, unsigned int *ms) { size_t left; ssize_t i = 0; size_t max_size = max_record_recv_size(session); uint8_t *ptr; gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; int ret; struct timespec t1, t2; unsigned int diff; session->internals.direction = 0; *bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session)); if (!*bufel) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } ptr = (*bufel)->msg.data; left = size; while (left > 0) { if (ms && *ms > 0) { ret = _gnutls_io_check_recv(session, *ms); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_gettime(&t1); } reset_errno(session); i = pull_func(fd, &ptr[size - left], left); if (i < 0) { int err = get_errno(session); _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n", (int) i, fd, errno, session->internals.errnum); if (err == EAGAIN || err == EINTR) { if (size - left > 0) { _gnutls_read_log ("READ: returning %d bytes from %p\n", (int) (size - left), fd); goto finish; } ret = errno_to_gerr(err, 0); goto cleanup; } else { gnutls_assert(); ret = GNUTLS_E_PULL_ERROR; goto cleanup; } } else { _gnutls_read_log("READ: Got %d bytes from %p\n", (int) i, fd); if (i == 0) break; /* EOF */ } left -= i; (*bufel)->msg.size += i; if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) { gnutls_gettime(&t2); diff = timespec_sub_ms(&t2, &t1); if (diff < *ms) *ms -= diff; else { ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT); goto cleanup; } } } finish: _gnutls_read_log("READ: read %d bytes from %p\n", (int) (size - left), fd); if (size - left == 0) _mbuffer_xfree(bufel); return (size - left); cleanup: _mbuffer_xfree(bufel); return ret; }
static ssize_t _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel, gnutls_pull_func pull_func, unsigned int *ms) { ssize_t i, ret; uint8_t *ptr; struct timespec t1, t2; size_t max_size, recv_size; gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; unsigned int diff; max_size = max_record_recv_size(session); recv_size = max_size; session->internals.direction = 0; if (ms && *ms > 0) { ret = _gnutls_io_check_recv(session, *ms); if (ret < 0) return gnutls_assert_val(ret); gnutls_gettime(&t1); } *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session)); if (*bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ptr = (*bufel)->msg.data; reset_errno(session); i = pull_func(fd, ptr, recv_size); if (i < 0) { int err = get_errno(session); _gnutls_read_log("READ: %d returned from %p, errno=%d\n", (int) i, fd, err); ret = errno_to_gerr(err, 1); goto cleanup; } else { _gnutls_read_log("READ: Got %d bytes from %p\n", (int) i, fd); if (i == 0) { /* If we get here, we likely have a stream socket. * That assumption may not work on DCCP. */ gnutls_assert(); ret = 0; goto cleanup; } _mbuffer_set_udata_size(*bufel, i); } if (ms && *ms > 0) { gnutls_gettime(&t2); diff = timespec_sub_ms(&t2, &t1); if (diff < *ms) *ms -= diff; else { ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT); goto cleanup; } } _gnutls_read_log("READ: read %d bytes from %p\n", (int) i, fd); return i; cleanup: _mbuffer_xfree(bufel); return ret; }
static int client_send_params(gnutls_session_t session, gnutls_buffer_t extdata, const gnutls_psk_client_credentials_t cred) { int ret, ext_offset = 0; uint8_t binder_value[MAX_HASH_SIZE]; size_t spos; gnutls_datum_t username = {NULL, 0}; gnutls_datum_t user_key = {NULL, 0}, rkey = {NULL, 0}; gnutls_datum_t client_hello; unsigned next_idx; const mac_entry_st *prf_res = NULL; const mac_entry_st *prf_psk = NULL; struct timespec cur_time; uint32_t ticket_age, ob_ticket_age; int free_username = 0; psk_auth_info_t info = NULL; unsigned psk_id_len = 0; unsigned binders_len, binders_pos; if (((session->internals.flags & GNUTLS_NO_TICKETS) || session->internals.tls13_ticket.ticket.data == NULL) && (!cred || !_gnutls_have_psk_credentials(cred, session))) { return 0; } binders_len = 0; /* placeholder to be filled later */ spos = extdata->length; ret = _gnutls_buffer_append_prefix(extdata, 16, 0); if (ret < 0) return gnutls_assert_val(ret); /* First, let's see if we have a session ticket to send */ if (!(session->internals.flags & GNUTLS_NO_TICKETS) && session->internals.tls13_ticket.ticket.data != NULL) { /* We found a session ticket */ if (unlikely(session->internals.tls13_ticket.prf == NULL)) { _gnutls13_session_ticket_unset(session); ret = gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); goto cleanup; } prf_res = session->internals.tls13_ticket.prf; gnutls_gettime(&cur_time); if (unlikely(_gnutls_timespec_cmp(&cur_time, &session->internals. tls13_ticket. arrival_time) < 0)) { gnutls_assert(); _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Check whether the ticket is stale */ ticket_age = timespec_sub_ms(&cur_time, &session->internals.tls13_ticket. arrival_time); if (ticket_age / 1000 > session->internals.tls13_ticket.lifetime) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } ret = compute_psk_from_ticket(&session->internals.tls13_ticket, &rkey); if (ret < 0) { _gnutls13_session_ticket_unset(session); goto ignore_ticket; } /* Calculate obfuscated ticket age, in milliseconds, mod 2^32 */ ob_ticket_age = ticket_age + session->internals.tls13_ticket.age_add; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, session->internals.tls13_ticket.ticket.data, session->internals.tls13_ticket.ticket.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, ob_ticket_age)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + session->internals.tls13_ticket.ticket.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_res); } ignore_ticket: if (cred && _gnutls_have_psk_credentials(cred, session)) { gnutls_datum_t tkey; if (cred->binder_algo == NULL) { gnutls_assert(); ret = gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); goto cleanup; } prf_psk = cred->binder_algo; ret = _gnutls_find_psk_key(session, cred, &username, &tkey, &free_username); if (ret < 0) { gnutls_assert(); goto cleanup; } if (username.size == 0 || username.size > UINT16_MAX) { ret = gnutls_assert_val(GNUTLS_E_INVALID_PASSWORD); goto cleanup; } if (!free_username) { /* we need to copy the key */ ret = _gnutls_set_datum(&user_key, tkey.data, tkey.size); if (ret < 0) { gnutls_assert(); goto cleanup; } } else { user_key.data = tkey.data; user_key.size = tkey.size; } ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1); if (ret < 0) { gnutls_assert(); goto cleanup; } info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK); assert(info != NULL); memcpy(info->username, username.data, username.size); info->username[username.size] = 0; if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16, username.data, username.size)) < 0) { gnutls_assert(); goto cleanup; } /* Now append the obfuscated ticket age */ if ((ret = _gnutls_buffer_append_prefix(extdata, 32, 0)) < 0) { gnutls_assert(); goto cleanup; } psk_id_len += 6 + username.size; binders_len += 1 + _gnutls_mac_get_algo_len(prf_psk); } /* if no tickets or identities to be sent */ if (psk_id_len == 0) { /* reset extensions buffer */ extdata->length = spos; return 0; } _gnutls_write_uint16(psk_id_len, &extdata->data[spos]); binders_pos = extdata->length-spos; ext_offset = _gnutls_ext_get_extensions_offset(session); /* Compute the binders. extdata->data points to the start * of this client hello. */ assert(extdata->length >= sizeof(mbuffer_st)); assert(ext_offset >= (ssize_t)sizeof(mbuffer_st)); ext_offset -= sizeof(mbuffer_st); client_hello.data = extdata->data+sizeof(mbuffer_st); client_hello.size = extdata->length-sizeof(mbuffer_st); next_idx = 0; ret = _gnutls_buffer_append_prefix(extdata, 16, binders_len); if (ret < 0) { gnutls_assert_val(ret); goto cleanup; } if (prf_res && rkey.size > 0) { ret = compute_psk_binder(session, prf_res, binders_len, binders_pos, ext_offset, &rkey, &client_hello, 1, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = rkey.data; session->key.binders[next_idx].psk.size = rkey.size; rkey.data = NULL; session->key.binders[next_idx].prf = prf_res; session->key.binders[next_idx].resumption = 1; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK resumption identity (%d)\n", session, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_res->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } session->internals.hsk_flags |= HSK_TLS13_TICKET_SENT; } if (prf_psk && user_key.size > 0 && info) { ret = compute_psk_binder(session, prf_psk, binders_len, binders_pos, ext_offset, &user_key, &client_hello, 0, binder_value); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Associate the selected pre-shared key with the session */ gnutls_free(session->key.binders[next_idx].psk.data); session->key.binders[next_idx].psk.data = user_key.data; session->key.binders[next_idx].psk.size = user_key.size; user_key.data = NULL; session->key.binders[next_idx].prf = prf_psk; session->key.binders[next_idx].resumption = 0; session->key.binders[next_idx].idx = next_idx; _gnutls_handshake_log("EXT[%p]: sent PSK identity '%s' (%d)\n", session, info->username, next_idx); next_idx++; /* Add the binder */ ret = _gnutls_buffer_append_data_prefix(extdata, 8, binder_value, prf_psk->output_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: if (free_username) _gnutls_free_datum(&username); _gnutls_free_temp_key_datum(&user_key); _gnutls_free_temp_key_datum(&rkey); return ret; }
static void test_ciphersuite_kx(const char *cipher_prio, unsigned pk) { /* Server stuff. */ gnutls_anon_server_credentials_t s_anoncred; gnutls_session_t server; int sret, cret; const char *str; char *suite = NULL; /* Client stuff. */ gnutls_anon_client_credentials_t c_anoncred; gnutls_certificate_credentials_t c_certcred, s_certcred; gnutls_session_t client; /* Need to enable anonymous KX specifically. */ int ret; struct benchmark_st st; struct timespec tr_start, tr_stop; double avg, sstddev; gnutls_priority_t priority_cache; total_diffs_size = 0; /* Init server */ gnutls_certificate_allocate_credentials(&s_certcred); gnutls_anon_allocate_server_credentials(&s_anoncred); ret = 0; if (pk == GNUTLS_PK_RSA_PSS) ret = gnutls_certificate_set_x509_key_mem(s_certcred, &server_rsa_pss_cert, &server_key, GNUTLS_X509_FMT_PEM); else if (pk == GNUTLS_PK_RSA) ret = gnutls_certificate_set_x509_key_mem(s_certcred, &server_cert, &server_key, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "Error in %d: %s\n", __LINE__, gnutls_strerror(ret)); exit(1); } ret = 0; if (pk == GNUTLS_PK_ECDSA) ret = gnutls_certificate_set_x509_key_mem(s_certcred, &server_ecc_cert, &server_ecc_key, GNUTLS_X509_FMT_PEM); else if (pk == GNUTLS_PK_EDDSA_ED25519) ret = gnutls_certificate_set_x509_key_mem(s_certcred, &server_ed25519_cert, &server_ed25519_key, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "Error in %d: %s\n", __LINE__, gnutls_strerror(ret)); exit(1); } /* Init client */ gnutls_anon_allocate_client_credentials(&c_anoncred); gnutls_certificate_allocate_credentials(&c_certcred); start_benchmark(&st); ret = gnutls_priority_init(&priority_cache, cipher_prio, &str); if (ret < 0) { fprintf(stderr, "Error in %s\n", str); exit(1); } do { gnutls_init(&server, GNUTLS_SERVER); ret = gnutls_priority_set(server, priority_cache); if (ret < 0) { fprintf(stderr, "Error in setting priority: %s\n", gnutls_strerror(ret)); exit(1); } gnutls_credentials_set(server, GNUTLS_CRD_ANON, s_anoncred); gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, s_certcred); gnutls_transport_set_push_function(server, server_push); gnutls_transport_set_pull_function(server, server_pull); gnutls_transport_set_ptr(server, (gnutls_transport_ptr_t) server); reset_buffers(); gnutls_init(&client, GNUTLS_CLIENT); ret = gnutls_priority_set(client, priority_cache); if (ret < 0) { fprintf(stderr, "Error in setting priority: %s\n", gnutls_strerror(ret)); exit(1); } gnutls_credentials_set(client, GNUTLS_CRD_ANON, c_anoncred); gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, c_certcred); gnutls_transport_set_push_function(client, client_push); gnutls_transport_set_pull_function(client, client_pull); gnutls_transport_set_ptr(client, (gnutls_transport_ptr_t) client); gettime(&tr_start); HANDSHAKE(client, server); gettime(&tr_stop); if (suite == NULL) suite = gnutls_session_get_desc(server); gnutls_deinit(client); gnutls_deinit(server); total_diffs[total_diffs_size++] = timespec_sub_ms(&tr_stop, &tr_start); if (total_diffs_size > sizeof(total_diffs)/sizeof(total_diffs[0])) abort(); st.size += 1; } while (benchmark_must_finish == 0); fprintf(stdout, "%38s ", suite); gnutls_free(suite); stop_benchmark(&st, "transactions", 1); gnutls_priority_deinit(priority_cache); avg = calc_avg(total_diffs, total_diffs_size); sstddev = calc_sstdev(total_diffs, total_diffs_size, avg); printf("%32s %.2f ms, sample variance: %.2f)\n", "(avg. handshake time:", avg, sstddev); gnutls_anon_free_client_credentials(c_anoncred); gnutls_anon_free_server_credentials(s_anoncred); }
/** * gnutls_heartbeat_ping: * @session: is a #gnutls_session_t structure. * @data_size: is the length of the ping payload. * @max_tries: if flags is %GNUTLS_HEARTBEAT_WAIT then this sets the number of retransmissions. Use zero for indefinite (until timeout). * @flags: if %GNUTLS_HEARTBEAT_WAIT then wait for pong or timeout instead of returning immediately. * * This function sends a ping to the peer. If the @flags is set * to %GNUTLS_HEARTBEAT_WAIT then it waits for a reply from the peer. * * Note that it is highly recommended to use this function with the * flag %GNUTLS_HEARTBEAT_WAIT, or you need to handle retransmissions * and timeouts manually. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. * * Since: 3.1.2 **/ int gnutls_heartbeat_ping(gnutls_session_t session, size_t data_size, unsigned int max_tries, unsigned int flags) { int ret; unsigned int retries = 1, diff; struct timespec now; if (data_size > MAX_HEARTBEAT_LENGTH) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); if (gnutls_heartbeat_allowed (session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND) == 0) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* resume previous call if interrupted */ if (session->internals.record_send_buffer.byte_length > 0 && session->internals.record_send_buffer.head != NULL && session->internals.record_send_buffer.head->type == GNUTLS_HEARTBEAT) return _gnutls_io_write_flush(session); switch (session->internals.hb_state) { case SHB_SEND1: if (data_size > DEFAULT_PAYLOAD_SIZE) data_size -= DEFAULT_PAYLOAD_SIZE; else data_size = 0; _gnutls_buffer_reset(&session->internals.hb_local_data); ret = _gnutls_buffer_resize(&session->internals. hb_local_data, data_size); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_rnd(GNUTLS_RND_NONCE, session->internals.hb_local_data.data, data_size); if (ret < 0) return gnutls_assert_val(ret); gettime(&session->internals.hb_ping_start); session->internals.hb_local_data.length = data_size; session->internals.hb_state = SHB_SEND2; case SHB_SEND2: session->internals.hb_actual_retrans_timeout_ms = session->internals.hb_retrans_timeout_ms; retry: ret = heartbeat_send_data(session, session->internals.hb_local_data. data, session->internals.hb_local_data. length, HEARTBEAT_REQUEST); if (ret < 0) return gnutls_assert_val(ret); gettime(&session->internals.hb_ping_sent); if (!(flags & GNUTLS_HEARTBEAT_WAIT)) { session->internals.hb_state = SHB_SEND1; break; } session->internals.hb_state = SHB_RECV; case SHB_RECV: ret = _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL, 0, NULL, session->internals. hb_actual_retrans_timeout_ms); if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) { session->internals.hb_state = SHB_SEND1; break; } else if (ret == GNUTLS_E_TIMEDOUT) { retries++; if (max_tries > 0 && retries > max_tries) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(ret); } gettime(&now); diff = timespec_sub_ms(&now, &session->internals. hb_ping_start); if (diff > session->internals.hb_total_timeout_ms) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(GNUTLS_E_TIMEDOUT); } session->internals.hb_actual_retrans_timeout_ms *= 2; session->internals.hb_actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; session->internals.hb_state = SHB_SEND2; goto retry; } else if (ret < 0) { session->internals.hb_state = SHB_SEND1; return gnutls_assert_val(ret); } } return 0; }
void MeterS0::counter_thread() { // _hwif exists and open() succeeded print(log_finest, "Counter thread started with %s hwif", name().c_str(), _hwif->is_blocking() ? "blocking" : "non blocking"); bool is_blocking = _hwif->is_blocking(); { // set thread priority to highest and SCHED_FIFO scheduling class // ignore any errors int policy; struct sched_param param; pthread_getschedparam(pthread_self(), &policy, ¶m); policy = SCHED_FIFO; // different approach would be PR_SET_TIMERSLACK with 1ns (default 50us) param.sched_priority = sched_get_priority_max(policy); if (0!= pthread_setschedparam(pthread_self(), policy, ¶m) ) { print(log_error, "failed to set policy to SCHED_FIFO for counter_thread", name().c_str()); } } // read current state from hwif: (this is needed for gpio if as well to reset waitForImpulse after startup (see bug #229) int cur_state = _hwif->status(); int last_state = (cur_state >= 0) ? cur_state : 0; // use current state if it is valid else assume low edge const int nonblocking_delay_ns = _nonblocking_delay_ns; while(!_counter_thread_stop) { if (is_blocking) { bool timeout = false; if (_hwif->waitForImpulse( timeout )) { // something has happened on the hardwareinterface (hwif) // because of the bouncing of the contact we still can not decide if it is a rising edge event // that's why we have to debounce first... if (!timeout && (_debounce_delay_ms > 0) ){ // nanosleep _debounce_delay_ms struct timespec ts; ts.tv_sec = _debounce_delay_ms/1000; ts.tv_nsec = (_debounce_delay_ms%1000)*1e6; struct timespec rem; while ( (-1 == nanosleep(&ts, &rem)) && (errno == EINTR) ) { ts = rem; } } // ... and then going on with our work struct timespec temp_ts; clock_gettime(CLOCK_REALTIME, &temp_ts); _ms_last_impulse = timespec_sub_ms(temp_ts, _time_last_ref); // uses atomic operator= if (_hwif->status()!=0) { // check if value of gpio is set (or not supported/error (-1) for e.g. UART HWIF -> rising edge event (or error in case we accept the trigger) if (_hwif_dir && ( _hwif_dir->status()>0 ) ) // check if second hardware interface has caused the event ++_impulses_neg; else // main hardware interface caused the event ++_impulses; } } } else { // non-blocking case: int state = _hwif->status(); if ((state >= 0) && (state != last_state)) { if (last_state == 0) { // low->high edge found // auch hier muss wahrscheinlich erst das debouncing erfolgen, bevor es zur Auswertung kommt !! if (_hwif_dir && (_hwif_dir->status()>0)) ++_impulses_neg; else ++_impulses; if (_debounce_delay_ms > 0){ // nanosleep _debounce_delay_ms struct timespec ts; ts.tv_sec = _debounce_delay_ms/1000; ts.tv_nsec = (_debounce_delay_ms%1000)*1e6; struct timespec rem; while ( (-1 == nanosleep(&ts, &rem)) && (errno == EINTR) ) { ts = rem; } } } last_state = state; } else { // error reading gpio status or status same as previous one struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = nonblocking_delay_ns; // 5*(1e3) needed for up to 30kHz! 1e3 -> <1mhz, 1e4 -> <100kHz, 1e5 -> <10kHz nanosleep(&ts, NULL); // we can ignore any errors here } } // non blocking case } // while print(log_finest, "Counter thread stopped with %d imp", name().c_str(), _impulses.load()); }