Exemplo n.º 1
0
/**
 * 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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
/**
 * 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;
}
Exemplo n.º 7
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, &param);
		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, &param) ) {
			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());
}