Skip to content

Commit

Permalink
Completly stop driver and free all resources with network:stop/0 on E…
Browse files Browse the repository at this point in the history
…SP32

Adds a destroy callback to the ESP32 network driver to completely stop the
driver and free all network resources when network:stop/0 is used.  Previosly
the driver was not being stopped internally and resources were not freed when
the gen_server was stopped, causing instability, and possible crashes when
event callbacks were triggered, but there was no process alive to handle them.

Closes atomvm#643

Signed-off-by: Winford <winford@object.stream>
  • Loading branch information
UncleGrumpy committed Jun 4, 2024
1 parent c31b1aa commit 456b427
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fix several uses of free on prevously released memory on ESP32, under certain error condition using
`network:start/1`, that would lead to a hard crash of the VM.
- Fix a bug in ESP32 network driver where the low level driver was not being stopped and resoureces were not freed
when `network:stop/0` was used, see issue [#643](https://github.com/atomvm/AtomVM/issues/643)

## [0.6.2] - 25-05-2024

Expand Down
2 changes: 2 additions & 0 deletions libs/eavmlib/src/network.erl
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ handle_info(Msg, State) ->

%% @hidden
terminate(_Reason, _State) ->
Ref = make_ref(),
network_port ! {?SERVER, Ref, stop},
ok.

%%
Expand Down
56 changes: 53 additions & 3 deletions src/platforms/esp32/components/avm_builtins/network_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ enum network_cmd
NetworkInvalidCmd = 0,
// TODO add support for scan, ifconfig
NetworkStartCmd,
NetworkRssiCmd
NetworkRssiCmd,
NetworkStopCmd
};

static const AtomStringIntPair cmd_table[] = {
{ ATOM_STR("\x5", "start"), NetworkStartCmd },
{ ATOM_STR("\x4", "rssi"), NetworkRssiCmd },
{ ATOM_STR("\x4", "stop"), NetworkStopCmd },
SELECT_INT_DEFAULT(NetworkInvalidCmd)
};

Expand Down Expand Up @@ -758,12 +760,51 @@ static void start_network(Context *ctx, term pid, term ref, term config)
if (!IS_NULL_PTR(ap_wifi_config)) {
set_dhcp_hostname(ap_wifi_interface, "AP", interop_kv_get_value(ap_config, dhcp_hostname_atom, ctx->global));
}

//
// Done -- send an ok so the FSM can proceed
//
port_send_reply(ctx, pid, ref, OK_ATOM);
}

static void stop_network(Context *ctx)
{
// Stop unregister event callbacks so they dont trigger during shutdown.
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler);

esp_netif_t *sta_wifi_interface = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
esp_netif_t *ap_wifi_interface = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");

// Disconnect STA if connected to access point
if ((sta_wifi_interface != NULL) && (esp_netif_is_netif_up(sta_wifi_interface))) {
esp_err_t err = esp_wifi_disconnect();
if (UNLIKELY(err == ESP_FAIL)) {
ESP_LOGE(TAG, "ESP FAIL error while disconnecting from AP, continuing network shutdown...");
}
}

// Stop and deinit the WiFi driver, these only return OK, or not init error (fine to ignore).
esp_wifi_stop();
esp_wifi_deinit();

// Stop sntp (ignore OK, or not configured error)
esp_sntp_stop();

// Delete network event loop
esp_err_t err = esp_event_loop_delete_default();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Invalid state error while deleting event loop, continuing network shutdown...");
}

// Destroy existing netif interfaces
if (ap_wifi_interface != NULL) {
esp_netif_destroy_default_wifi(ap_wifi_interface);
}
if (sta_wifi_interface != NULL) {
esp_netif_destroy_default_wifi(sta_wifi_interface);
}
}

static void get_sta_rssi(Context *ctx, term pid, term ref)
{
size_t tuple_reply_size = PORT_REPLY_SIZE + TUPLE_SIZE(2);
Expand All @@ -784,11 +825,11 @@ static void get_sta_rssi(Context *ctx, term pid, term ref)
port_ensure_available(ctx, tuple_reply_size);
term reply = port_create_tuple2(ctx, make_atom(ctx->global, ATOM_STR("\x4", "rssi")), rssi);
port_send_reply(ctx, pid, ref, reply);

}

static NativeHandlerResult consume_mailbox(Context *ctx)
{
bool cmd_terminate = false;
Message *message = mailbox_first(&ctx->mailbox);
term msg = message->message;

Expand Down Expand Up @@ -821,6 +862,10 @@ static NativeHandlerResult consume_mailbox(Context *ctx)
case NetworkRssiCmd:
get_sta_rssi(ctx, pid, ref);
break;
case NetworkStopCmd:
cmd_terminate = true;
stop_network(ctx);
break;

default: {
ESP_LOGE(TAG, "Unrecognized command: %x", cmd);
Expand All @@ -847,7 +892,7 @@ static NativeHandlerResult consume_mailbox(Context *ctx)

mailbox_remove_message(&ctx->mailbox, &ctx->heap);

return NativeContinue;
return cmd_terminate ? NativeTerminate : NativeContinue;
}

//
Expand Down Expand Up @@ -883,6 +928,11 @@ Context *network_driver_create_port(GlobalContext *global, term opts)
return ctx;
}

//
// Destructor
//


#ifdef CONFIG_AVM_ENABLE_NETWORK_PORT_DRIVER

REGISTER_PORT_DRIVER(network, network_driver_init, NULL, network_driver_create_port)
Expand Down

0 comments on commit 456b427

Please sign in to comment.