diff --git a/CHANGELOG.md b/CHANGELOG.md index 395c9c54a2..53e82638cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +## 6.3.0 + +### FEATURES + +- New cloud event API that supports sending and receiving up to 16K of data in an event [#2840](https://github.com/particle-iot/device-os/pull/2840) +- Electron 2 platform support [#2844](https://github.com/particle-iot/device-os/pull/2844) + +### ENHANCEMENTS +- [wiring] Generate an error when using `EEPROM` with `String` objects as `String` contains dynamically allocated data on heap [#2855](https://github.com/particle-iot/device-os/pull/2855) +- [network] Postpone `Ethernet` interface initialization to allow STARTUP() call to override pin configuration without a reset [#2848](https://github.com/particle-iot/device-os/pull/2848) + +### BUGFIXES + +- Prevent low-level WiFI network buffer overflow [#2853](https://github.com/particle-iot/device-os/pull/2853) +- [Gen 3] Increase main stack size from 2K to 4K [#2851](https://github.com/particle-iot/device-os/pull/2851) +- Thread-safe `__cxa_guard_acquire`/`__cxa_guard_release` implementation [#2851](https://github.com/particle-iot/device-os/pull/2851) +- [build] Fix section size calculations for paths containing section-like names [#2852](https://github.com/particle-iot/device-os/pull/2852) + +### INTERNAL +- [test] wiring/no_fixture_long_running: update network tests to stress test large packets up to MTU size once max MTU is figured out [#2855](https://github.com/particle-iot/device-os/pull/2855) +- [test] communication/long_publish: adds a long running publish test [#2854](https://github.com/particle-iot/device-os/pull/2854) +- [build] Add asserts to linker files to make sure that stack sizes match the expected values [#2851](https://github.com/particle-iot/device-os/pull/2851) +- Stub `atexit` to free up flash space used by global object destructors [#2851](https://github.com/particle-iot/device-os/pull/2851) + ## 6.2.1 ### FEATURES diff --git a/build/release.sh b/build/release.sh index 0a98e6be5c..517785c376 100755 --- a/build/release.sh +++ b/build/release.sh @@ -1,7 +1,7 @@ #!/bin/bash set -o errexit -o pipefail -o noclobber -o nounset -VERSION=${VERSION:="6.3.0-rc.1"} +VERSION=${VERSION:="6.3.0"} function display_help () { diff --git a/build/version.mk b/build/version.mk index 8df5f78d83..5160604b1c 100755 --- a/build/version.mk +++ b/build/version.mk @@ -1,7 +1,7 @@ -VERSION_STRING = 6.3.0-rc.1 +VERSION_STRING = 6.3.0 # PRODUCT_FIRMWARE_VERSION reported by default # FIXME: Unclear if this is used, PRODUCT_FIRMWARE_VERSION defaults to 65535 every release -VERSION = 6300 +VERSION = 6302 CFLAGS += -DSYSTEM_VERSION_STRING=$(VERSION_STRING) diff --git a/communication/inc/dtls_session_persist.h b/communication/inc/dtls_session_persist.h index c5cf2cfebe..214684102e 100644 --- a/communication/inc/dtls_session_persist.h +++ b/communication/inc/dtls_session_persist.h @@ -155,6 +155,9 @@ class __attribute__((packed)) SessionPersistOpaque : public SessionPersistData void clear_use_count() { use_counter = 0; } int use_count() { return use_counter; } bool has_expired() { return use_counter >= MAXIMUM_SESSION_USES; } + void set_use_count_once() { + use_counter = MAXIMUM_SESSION_USES; + } static const int MAXIMUM_SESSION_USES = 3; }; diff --git a/communication/inc/spark_protocol_functions.h b/communication/inc/spark_protocol_functions.h index a355a4fcdd..fd5f053363 100644 --- a/communication/inc/spark_protocol_functions.h +++ b/communication/inc/spark_protocol_functions.h @@ -248,7 +248,8 @@ namespace ProtocolCommands { WAKE = 1, // Deprecated, use PING instead DISCONNECT = 2, TERMINATE = 3, - PING = 4 + PING = 4, + MOVE_CONNECTION = 5 }; }; diff --git a/communication/src/dtls_message_channel.cpp b/communication/src/dtls_message_channel.cpp index 0edb515dda..a9df7e6121 100644 --- a/communication/src/dtls_message_channel.cpp +++ b/communication/src/dtls_message_channel.cpp @@ -575,10 +575,17 @@ ProtocolError DTLSMessageChannel::command(Command command, void* arg) reset_session(); return IO_ERROR_DISCARD_SESSION; //force re-establish - case MOVE_SESSION: + case MOVE_SESSION: { + bool once = false; + if (arg && *((bool*)arg)) { + once = true; + } move_session = true; + if (once) { + sessionPersist.set_use_count_once(); + } break; - + } case LOAD_SESSION: sessionPersist.restore(callbacks.restore); break; diff --git a/communication/src/dtls_protocol.h b/communication/src/dtls_protocol.h index 2834bba4d8..93f6ec5aed 100644 --- a/communication/src/dtls_protocol.h +++ b/communication/src/dtls_protocol.h @@ -115,6 +115,15 @@ class DTLSProtocol : public Protocol } return r; } + case ProtocolCommands::MOVE_CONNECTION: { + LOG(INFO, "Moving connection (session move + ping)"); + int r = ProtocolError::NO_ERROR; + bool once = true; // Use session only once, if migration fails it will be invalidated immediately + if (!(r = channel.command(Channel::MOVE_SESSION, &once))) { + return this->command(ProtocolCommands::PING, 0, nullptr); + } + return r; + } default: return ProtocolError::UNKNOWN; } diff --git a/modules/shared/system_module_version.mk b/modules/shared/system_module_version.mk index 5179cd2d5c..bdda36281f 100644 --- a/modules/shared/system_module_version.mk +++ b/modules/shared/system_module_version.mk @@ -1,6 +1,6 @@ # Skip to next 100 every v0.x.0 release (e.g. 108 for v0.6.2 to 200 for v0.7.0-rc.1) # Bump by 1 for every prerelease or release with the same v0.x.* base. -COMMON_MODULE_VERSION ?= 6300 +COMMON_MODULE_VERSION ?= 6302 SYSTEM_PART1_MODULE_VERSION ?= $(COMMON_MODULE_VERSION) RELEASE_080_MODULE_VERSION_BASE ?= 300 diff --git a/system/inc/system_version.h b/system/inc/system_version.h index 4dba0ba32c..b05847332b 100644 --- a/system/inc/system_version.h +++ b/system/inc/system_version.h @@ -225,7 +225,9 @@ extern "C" { #define SYSTEM_VERSION_v620 SYSTEM_VERSION_DEFAULT(6, 2, 0) #define SYSTEM_VERSION_v621 SYSTEM_VERSION_DEFAULT(6, 2, 1) #define SYSTEM_VERSION_v630RC1 SYSTEM_VERSION_RC(6, 3, 0, 1) -#define SYSTEM_VERSION SYSTEM_VERSION_v630RC1 +#define SYSTEM_VERSION_v630RC2 SYSTEM_VERSION_RC(6, 3, 0, 2) +#define SYSTEM_VERSION_v630 SYSTEM_VERSION_DEFAULT(6, 3, 0) +#define SYSTEM_VERSION SYSTEM_VERSION_v630 /** * Previously we would set the least significant byte to 0 for the final release, but to make @@ -415,6 +417,8 @@ extern "C" { #define SYSTEM_VERSION_620 #define SYSTEM_VERSION_621 #define SYSTEM_VERSION_630RC1 +#define SYSTEM_VERSION_630RC2 +#define SYSTEM_VERSION_630 typedef struct __attribute__((packed)) SystemVersionInfo { diff --git a/system/src/system_cloud_connection.cpp b/system/src/system_cloud_connection.cpp index 59d321bda1..4315290060 100644 --- a/system/src/system_cloud_connection.cpp +++ b/system/src/system_cloud_connection.cpp @@ -361,3 +361,22 @@ int system_cloud_get_inet_family_keepalive(int af, unsigned int* value) { return 0; } + +int system_cloud_move_connection(network_handle_t network) { + if (system_cloud_is_connected(nullptr)) { // XXX: this is not a bool! + return SYSTEM_ERROR_INVALID_STATE; + } + + LOG(INFO, "Attempting to move cloud connection to interface %u", network); + + int r = system_cloud_rebind(network); + if (r) { + LOG(WARN, "Cloud connection rebind to %u failed err=%d", network, r); + return r; + } + r = spark_protocol_command(spark_protocol_instance(), ProtocolCommands::MOVE_CONNECTION); + if (r) { + LOG(WARN, "Protocol connection move failed err=%d", r); + } + return r; +} diff --git a/system/src/system_cloud_connection.h b/system/src/system_cloud_connection.h index 97ddac0d16..0d084a4226 100644 --- a/system/src/system_cloud_connection.h +++ b/system/src/system_cloud_connection.h @@ -27,6 +27,7 @@ #if HAL_PLATFORM_IFAPI #include "netdb_hal.h" #endif // HAL_PLATFORM_IFAPI +#include "system_network.h" #ifdef __cplusplus extern "C" { @@ -53,6 +54,8 @@ int system_multicast_announce_presence(void* reserved); int system_cloud_set_inet_family_keepalive(int af, unsigned int value, int flags); int system_cloud_get_inet_family_keepalive(int af, unsigned int* value); sock_handle_t system_cloud_get_socket_handle(); +int system_cloud_move_connection(network_handle_t network); +int system_cloud_rebind(network_handle_t network); #if HAL_PLATFORM_IFAPI int system_cloud_resolv_address(int protocol, const ServerAddress* address, sockaddr* saddrCache, addrinfo** info, CloudServerAddressType* type, bool useCachedAddrInfo); diff --git a/system/src/system_cloud_connection_compat.cpp b/system/src/system_cloud_connection_compat.cpp index 79ec47e7d3..6fe2bc88ae 100644 --- a/system/src/system_cloud_connection_compat.cpp +++ b/system/src/system_cloud_connection_compat.cpp @@ -328,5 +328,8 @@ sock_handle_t system_cloud_get_socket_handle() return s_state.socket; } +int system_cloud_rebind(network_handle_t network) { + return SYSTEM_ERROR_NOT_SUPPORTED; +} #endif /* !HAL_USE_SOCKET_HAL_POSIX && HAL_USE_SOCKET_HAL_COMPAT */ diff --git a/system/src/system_cloud_connection_posix.cpp b/system/src/system_cloud_connection_posix.cpp index 8fa30aeb05..51ecf03cd0 100644 --- a/system/src/system_cloud_connection_posix.cpp +++ b/system/src/system_cloud_connection_posix.cpp @@ -382,4 +382,27 @@ sock_handle_t system_cloud_get_socket_handle() return s_state.socket; } +int system_cloud_rebind(network_handle_t network) { + if (s_state.socket < 0) { + return SYSTEM_ERROR_INVALID_STATE; + } + + if (network == NETWORK_INTERFACE_ALL) { + return SYSTEM_ERROR_INVALID_ARGUMENT; + } + + // Bind to specific netif + struct ifreq ifr = {}; + if_index_to_name(network, ifr.ifr_name); + + auto sockOptRet = sock_setsockopt(s_state.socket, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)); + if (sockOptRet) { + LOG(WARN, "Failed to bind cloud socket to interface %u error: %d", network, sockOptRet); + } else { + LOG(INFO, "Re-bound cloud socket to iface %u (\"%s\")", network, ifr.ifr_name); + } + + return !sockOptRet ? SYSTEM_ERROR_NONE : SYSTEM_ERROR_NETWORK; +} + #endif /* HAL_USE_SOCKET_HAL_POSIX */ diff --git a/system/src/system_connection_manager.cpp b/system/src/system_connection_manager.cpp index 6ac9a0ec74..5b6592a4c8 100644 --- a/system/src/system_connection_manager.cpp +++ b/system/src/system_connection_manager.cpp @@ -319,6 +319,15 @@ int ConnectionManager::checkCloudConnectionNetwork() { } // If best candidate doesn't match current network interface - reconnect LOG(TRACE, "Best network interface for cloud connection changed (to %s) - move the cloud session", netifToName(best)); + if (best != NETWORK_INTERFACE_ALL) { + int r = system_cloud_move_connection(best); + if (!r) { + return 0; + } else { + LOG(WARN, "Failed to move connection err=%d, fallback to reconnect", r); + } + } + // Fallback to disconnect/connect auto options = CloudDisconnectOptions().reconnect(true); auto systemOptions = options.toSystemOptions(); spark_cloud_disconnect(&systemOptions, nullptr); diff --git a/system/system-versions.md b/system/system-versions.md index 94d8a1f2f0..d3a9b830f7 100644 --- a/system/system-versions.md +++ b/system/system-versions.md @@ -200,6 +200,8 @@ | 3100 | 6200 | 6.2.0 | Argon, Boron, B SoM, B5 SoM, Tracker, Tracker M, E Som X, M SoM, P2 | | 3101 | 6201 | 6.2.1 | Argon, Boron, B SoM, B5 SoM, Tracker, Tracker M, E Som X, M SoM, P2 | | 3101 | 6300 | 6.3.0-rc.1 | Argon, Boron, B SoM, B5 SoM, Tracker, Tracker M, E Som X, M SoM, P2 | +| 3101 | 6301 | 6.3.0-rc.2 | Argon, Boron, B SoM, B5 SoM, Tracker, Tracker M, E Som X, M SoM, P2 | +| 3101 | 6302 | 6.3.0 | Argon, Boron, B SoM, B5 SoM, Tracker, Tracker M, E Som X, M SoM, P2 | [1] For 0.8.0-rc.1, The v101 bootloader was also released in the Github releases as v200. Thus the next released bootloader in the 0.8.x line should be v201. As of 4/5/2018: 22 device had v200 bootloaders. diff --git a/user/tests/integration/slo/connect_time/connect_time.cpp b/user/tests/integration/slo/connect_time/connect_time.cpp index 8d58666a5d..3bb42ba3d2 100644 --- a/user/tests/integration/slo/connect_time/connect_time.cpp +++ b/user/tests/integration/slo/connect_time/connect_time.cpp @@ -368,14 +368,16 @@ DEFINE_WARM_BOOT_TEST(08) test(publish_and_validate_stats) { #if Wiring_Cellular - Cellular.on(); - assertTrue(waitFor(network().isOn, TEST_MAX_TIMEOUT)); - // Exclude 2G and non-production devices from the SLO validation - CellularDevice devInfo = {}; - devInfo.size = sizeof(devInfo); - assertEqual(cellular_device_info(&devInfo, nullptr), 0); - if (devInfo.dev == DEV_SARA_G350 || devInfo.dev == DEV_QUECTEL_EG91_NA) { - stats.excludeFromSloValidation = true; + if (network() == Cellular) { + Cellular.on(); + assertTrue(waitFor(network().isOn, TEST_MAX_TIMEOUT)); + // Exclude 2G and non-production devices from the SLO validation + CellularDevice devInfo = {}; + devInfo.size = sizeof(devInfo); + assertEqual(cellular_device_info(&devInfo, nullptr), 0); + if (devInfo.dev == DEV_SARA_G350 || devInfo.dev == DEV_QUECTEL_EG91_NA) { + stats.excludeFromSloValidation = true; + } } #endif // Wiring_Cellular const size_t n = serializeStatsAsJson(nullptr /* buf */, 0 /* size */);