Skip to content

Commit

Permalink
Public-Auto-release: v2.20.0
Browse files Browse the repository at this point in the history
# Added
* [closes #34915, #40093] Client times out after 30 seconds and throws a ConnectionAbort error. Developers should check the error handling examples.

# Changed
* Fix deprecation warnings with newer CMake versions
* Update googletest to latest release
  • Loading branch information
blickfeld-lidar committed Jul 20, 2022
1 parent 13f3cf7 commit a461721
Show file tree
Hide file tree
Showing 23 changed files with 121 additions and 35 deletions.
9 changes: 9 additions & 0 deletions doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ influence the resulting point cloud.

### Removed

## [2.20.0] - 2022.07.20

### Added
* [closes #34915, #40093] Client times out after 30 seconds and throws a ConnectionAbort error. Developers should check the error handling examples.

### Changed
* Fix deprecation warnings with newer CMake versions
* Update googletest to latest release

## [2.19.7] - 2022.05.31

### Changed
Expand Down
Binary file modified doc/protobuf-frame-visualisation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions doc/protobuf_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ The data, such as a point cloud, are also packed in protobuf messages.

- [blickfeld/error.proto](#blickfeld/error.proto)
- [Error](#blickfeld.protocol.Error)
- [Error.ConnectionAbort](#blickfeld.protocol.Error.ConnectionAbort)
- [Error.ConnectionClosed](#blickfeld.protocol.Error.ConnectionClosed)
- [Error.Empty](#blickfeld.protocol.Error.Empty)
- [Error.HardwareError](#blickfeld.protocol.Error.HardwareError)
Expand Down Expand Up @@ -1147,6 +1148,22 @@ The format type of response is an undocumented, internal feature required for th
| time_sync_failed | [Error.TimeSyncFailed](#blickfeld.protocol.Error.TimeSyncFailed) | optional | Refer to [TimeSyncFailed](#blickfeld.protocol.Error.TimeSyncFailed) |
| no_device_discovered | [Error.NoDeviceDiscovered](#blickfeld.protocol.Error.NoDeviceDiscovered) | optional | Refer to [NoDeviceDiscovered](#blickfeld.protocol.Error.NoDeviceDiscovered) |
| not_supported | [Error.NotSupported](#blickfeld.protocol.Error.NotSupported) | optional | Refer to [NotSupported](#blickfeld.protocol.Error.NotSupported) |
| connection_abort | [Error.ConnectionAbort](#blickfeld.protocol.Error.ConnectionAbort) | optional | Refer to [ConnectionAbort](#blickfeld.protocol.Error.ConnectionAbort) |






<a name="blickfeld.protocol.Error.ConnectionAbort"></a>

### Error.ConnectionAbort
During reading, the connection to the client got aborted.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| details | [string](#string) | optional | |



Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/async_fetch_clouds/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/error_handling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/fetch_clouds/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/fetch_imu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/named_scan_pattern/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/read_from_file/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/reduced_clouds/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
##
## > Introduced in BSL v2.10 and firmware v1.9
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/set_scan_pattern/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/ssl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp/time_synchronization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp_standalone/discover/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
## LICENSE.md file in the root directory of this source tree.
##

cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp_standalone/fetch_clouds/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## This source code is licensed under the BSD-style license found in the
## LICENSE.md file in the root directory of this source tree.
##
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion protocol/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if (BF_BUILD_NPM AND NODEJS_EXECUTABLE AND NPM_EXECUTABLE)
OUTPUT ${PBJS_PATH}
OUTPUT ${PBTS_PATH}
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/npm-install
COMMAND ${NPM_EXECUTABLE} install protobufjs --prefix ${PROJECT_BINARY_DIR}/npm-install
COMMAND ${NPM_EXECUTABLE} install protobufjs@6.11.3 --prefix ${PROJECT_BINARY_DIR}/npm-install
)
add_custom_target(blickfeld-protocol-npm DEPENDS ${PBJS_PATH} DEPENDS ${PBTS_PATH})
endif()
Expand Down
12 changes: 11 additions & 1 deletion protocol/blickfeld/error.proto
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ message Error {
optional string reason = 1 [ default = "No detailed reason available." ]; // Description why this is not supported
}

/**
* During reading, the connection to the client got aborted.
*/
message ConnectionAbort {
option (e_desc) = "During reading, the connection to the client got aborted. Check the network connectivity or power state of the device.\n\tDetails: {details:%s}";

optional string details = 1;
}

oneof error {
Unknown unknown = 1; // Refer to [Unknown](#blickfeld.protocol.Error.Unknown)
NotImplemented not_implemented = 2; // Refer to [NotImplemented](#blickfeld.protocol.Error.NotImplemented)
Expand All @@ -183,7 +192,8 @@ message Error {
TimeSyncFailed time_sync_failed = 23; // Refer to [TimeSyncFailed](#blickfeld.protocol.Error.TimeSyncFailed)
NoDeviceDiscovered no_device_discovered = 24; // Refer to [NoDeviceDiscovered](#blickfeld.protocol.Error.NoDeviceDiscovered)
NotSupported not_supported = 25; // Refer to [NotSupported](#blickfeld.protocol.Error.NotSupported)
ConnectionAbort connection_abort = 26; // Refer to [ConnectionAbort](#blickfeld.protocol.Error.ConnectionAbort)
}

reserved 7 to 10, 19, 20;
}
}
2 changes: 2 additions & 0 deletions protocol/plugin/blickfeld/error.custom.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static inline protocol_exception<Error::NotInRange> CreateErrorNotInRange(std::s
static inline protocol_exception<Error::TimeSyncFailed> CreateErrorTimeSyncFailed(std::string ntp_daemon_log) { auto err = Error::TimeSyncFailed(); err.set_ntp_daemon_log(ntp_daemon_log); return protocol_exception<decltype(err)>(err); }
static inline protocol_exception<Error::NoDeviceDiscovered> CreateErrorNoDeviceDiscovered() { auto err = Error::NoDeviceDiscovered(); return protocol_exception<decltype(err)>(err); }
static inline protocol_exception<Error::NotSupported> CreateErrorNotSupported(std::string reason="No detailed reason available.") { auto err = Error::NotSupported(); err.set_reason(reason); return protocol_exception<decltype(err)>(err); }
static inline protocol_exception<Error::ConnectionAbort> CreateErrorConnectionAbort(std::string details) { auto err = Error::ConnectionAbort(); err.set_details(details); return protocol_exception<decltype(err)>(err); }


static inline void throw_typed_protocol_exception (Error err) {
Expand All @@ -53,6 +54,7 @@ case 22: throw protocol_exception<Error::NotInRange>(err.not_in_range()); break;
case 23: throw protocol_exception<Error::TimeSyncFailed>(err.time_sync_failed()); break;
case 24: throw protocol_exception<Error::NoDeviceDiscovered>(err.no_device_discovered()); break;
case 25: throw protocol_exception<Error::NotSupported>(err.not_supported()); break;
case 26: throw protocol_exception<Error::ConnectionAbort>(err.connection_abort()); break;

case Error::ERROR_NOT_SET:
default:
Expand Down
29 changes: 20 additions & 9 deletions python/blickfeld_scanner/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import time
from distutils.version import LooseVersion, StrictVersion

from .protocol import connection_pb2
from .protocol import connection_pb2, error_pb2
from .protocol.stream import connection_pb2 as stream_connection_pb2
from .protocol import options_pb2, common_pb2
from .protocol.config import algorithm_pb2
Expand All @@ -38,6 +38,8 @@ class scanner(object):
:type hostname_or_ip: str
:param port: Port on which the device is reachable the default is 8000.
:type port: int
:param timeout: Timeout in seconds until connection is aborted
:type timeout: int
:param name: Name of the device used for string representation.
:type name: str
:param key_and_cert_file: Filename containing a private key and certificate for SSL connection.
Expand All @@ -49,8 +51,9 @@ class scanner(object):
_default_port = 8000
_default_ssl_port = 8800

def __init__(self, hostname_or_ip="localhost", port=None, name=None, key_and_cert_file=None, key_and_cert=None):
def __init__(self, hostname_or_ip="localhost", port=None, timeout=30, name=None, key_and_cert_file=None, key_and_cert=None):
self.hostname_or_ip = hostname_or_ip
self.timeout = timeout
self.name = name if name is not None else self.hostname_or_ip
self.api_path = "http://" + hostname_or_ip + "/api/v1/"

Expand Down Expand Up @@ -445,7 +448,7 @@ def create_connection(self):
:return: Newly created :py:class:`blickfeld_scanner.scanner.connection`
"""
return connection(self.hostname_or_ip, self.port, self._key_and_cert)
return connection(self.hostname_or_ip, self.port, timeout=self.timeout, key_and_cert=self._key_and_cert)

def attempt_error_recovery(self):
"""> Introduced in BSL v2.13 and firmware v1.13
Expand Down Expand Up @@ -603,12 +606,14 @@ class connection(object):
:type hostname_or_ip: str
:param port: port on which the connection should be established
:type port: int
:param timeout: Timeout in seconds until connection is aborted
:type timeout: int
:param key_and_cert: String containing a private key and certificate for SSL connection
:type key_and_cert: str
:param ssl_protocol: The protocol used for an SSL connection
:type ssl_protocol: see ssl lib: `ssl.PROTOCOL_...`
"""
def __init__(self, hostname_or_ip, port, key_and_cert=None, ssl_protocol=ssl.PROTOCOL_TLS):
def __init__(self, hostname_or_ip, port, timeout, key_and_cert=None, ssl_protocol=ssl.PROTOCOL_TLS):
self._key_and_cert = key_and_cert
self.has_ssl = self._key_and_cert != None
if self.has_ssl:
Expand All @@ -627,10 +632,9 @@ def __init__(self, hostname_or_ip, port, key_and_cert=None, ssl_protocol=ssl.PRO
os.unlink(key_and_cert_file)

self._ssl_context.verify_mode = ssl.CERT_NONE
self.socket = self._ssl_context.wrap_socket(socket.create_connection((hostname_or_ip, port)), server_hostname=hostname_or_ip)
self.socket = self._ssl_context.wrap_socket(socket.create_connection((hostname_or_ip, port), timeout=timeout), server_hostname=hostname_or_ip)
else:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((hostname_or_ip, port))
self.socket = socket.create_connection((hostname_or_ip, port), timeout=timeout)

def __del__(self):
self.close()
Expand Down Expand Up @@ -690,9 +694,16 @@ def recv(self):
def __recv_all(self, n):
data = b''
while len(data) < n:
packet = self.socket.recv(n - len(data))
try:
packet = self.socket.recv(n - len(data))
except socket.timeout:
err = error_pb2.Error()
err.connection_abort.details = "Timeout after %u seconds" % (self.socket.timeout)
raise protocol_exception(err)
if not packet:
return None
err = error_pb2.Error()
err.connection_abort.details = "Receive failed"
raise protocol_exception(err)
data += packet
return data

Expand Down
48 changes: 41 additions & 7 deletions src/scanner_connection.cpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ const uint32_t scanner_connection::default_server_port = 8000;
const uint32_t scanner_connection::default_server_ssl_port = 8800;
#endif

scanner_connection::scanner_connection(asio::io_context& io_context, string hostname) :
scanner_connection::scanner_connection(asio::io_context& io_context, string hostname, std::chrono::duration<long int> timeout) :
io_context(io_context),
hostname(hostname),
timeout(timeout),
#ifdef HAVE_OPENSSL
socket(std::make_shared<asio::ip::tcp::socket>(io_context))
#else
Expand All @@ -47,9 +48,10 @@ scanner_connection::scanner_connection(asio::io_context& io_context, string host
}

#ifdef HAVE_OPENSSL
scanner_connection::scanner_connection(asio::io_context& io_context, std::string hostname, asio::ssl::context& ssl_context) :
scanner_connection::scanner_connection(asio::io_context& io_context, std::string hostname, asio::ssl::context& ssl_context, std::chrono::duration<long int> timeout) :
io_context(io_context),
hostname(hostname),
timeout(timeout),
socket(std::make_shared<asio::ssl::stream<asio::ip::tcp::socket> >(io_context, ssl_context))
{
string port = to_string(default_server_ssl_port);
Expand Down Expand Up @@ -92,12 +94,44 @@ void scanner_connection::recv(protocol::Response &resp) {
} else {
std::istream recv_stream(&input_buffer);

uint32_t size;
asio::read(socket, input_buffer, asio::transfer_exactly(sizeof(uint32_t)));
recv_stream.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
asio::read(socket, input_buffer, asio::transfer_exactly(size));
// Set up sync flags and deadline timer
auto expired = make_shared<bool>(), received = make_shared<bool>();
*expired = false, *received = false;
asio::steady_timer timer(io_context);
timer.expires_from_now(timeout);
timer.async_wait([expired, received](const asio::error_code& ec) {
*expired = !*received;
});

// Asynchronous read
asio::async_read(socket, input_buffer, asio::transfer_exactly(sizeof(uint32_t)), [this, &resp, received](const asio::error_code& ec, std::size_t length) {
if (ec) {
throw protocol::CreateErrorConnectionAbort("Failed to read message size with error code: " + ec.message());
}

uint32_t size;
std::istream recv_stream_size(&input_buffer);
recv_stream_size.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
asio::async_read(socket, input_buffer, asio::transfer_exactly(size), [this, &resp, received](const std::error_code& ec, std::size_t length) {
if (ec) {
throw protocol::CreateErrorConnectionAbort("Failed to read message buffer with error code: " + ec.message());
}

parse_response(recv_stream, resp);
std::istream recv_stream(&input_buffer);
parse_response(recv_stream, resp);

// Successful read
*received = true;
});
});

// Make asynchronous read, synchronous
io_context.reset();
while(io_context.run_one() && !*received) {
if (*expired)
throw protocol::CreateErrorConnectionAbort("Timeout after " + to_string(timeout.count()) + " seconds");
}
timer.cancel();
}
}

Expand Down
Loading

0 comments on commit a461721

Please sign in to comment.