Skip to content

Commit 6901fe5

Browse files
Refactor and test fixes
Signed-off-by: pierantoniomerlino <pierantonio.merlino@eurotech.com>
1 parent 80d8c60 commit 6901fe5

11 files changed

Lines changed: 401 additions & 833 deletions

File tree

kura/org.eclipse.kura.nm/src/main/java/org/eclipse/kura/nm/ModemManagerDbusWrapper.java

Lines changed: 22 additions & 294 deletions
Large diffs are not rendered by default.
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Eurotech and/or its affiliates and others
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Eurotech
12+
*******************************************************************************/
13+
package org.eclipse.kura.nm;
14+
15+
import java.util.Objects;
16+
import java.util.Optional;
17+
import java.util.concurrent.Executors;
18+
import java.util.concurrent.ScheduledExecutorService;
19+
import java.util.concurrent.ScheduledFuture;
20+
import java.util.concurrent.TimeUnit;
21+
import java.util.concurrent.atomic.AtomicBoolean;
22+
23+
import org.eclipse.kura.nm.enums.MMModemState;
24+
import org.freedesktop.dbus.exceptions.DBusException;
25+
import org.freedesktop.dbus.exceptions.DBusExecutionException;
26+
import org.freedesktop.modemmanager1.Modem;
27+
import org.freedesktop.networkmanager.Device;
28+
import org.freedesktop.networkmanager.settings.Connection;
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
32+
public class ModemTaskScheduler {
33+
34+
private static final Logger logger = LoggerFactory.getLogger(ModemTaskScheduler.class);
35+
36+
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
37+
private final NetworkManagerDbusWrapper networkManager;
38+
private final ModemManagerDbusWrapper modemManager;
39+
private final Device device;
40+
private final Connection connection;
41+
private final int maxFail;
42+
private final int holdoff;
43+
private final boolean autoconnect;
44+
private final int resetDelayMinutes;
45+
private final String deviceId;
46+
47+
private ScheduledFuture<?> connectionHandler;
48+
private ScheduledFuture<?> resetHandler;
49+
private AtomicBoolean isConnectionScheduled = new AtomicBoolean(false);
50+
private AtomicBoolean isResetScheduled = new AtomicBoolean(false);
51+
private Optional<String> mmDbusPath;
52+
private int delay = 0;
53+
54+
public ModemTaskScheduler(NetworkManagerDbusWrapper networkManager, ModemManagerDbusWrapper modemManager,
55+
Connection connection, Device device, String deviceId, NetworkProperties properties) {
56+
this.networkManager = Objects.requireNonNull(networkManager);
57+
this.modemManager = Objects.requireNonNull(modemManager);
58+
this.device = Objects.requireNonNull(device);
59+
this.connection = Objects.requireNonNull(connection);
60+
this.resetDelayMinutes = properties.get(Integer.class, "net.interface.%s.config.resetTimeout", deviceId);
61+
this.autoconnect = properties.get(Boolean.class, "net.interface.%s.config.persist", deviceId);
62+
this.holdoff = properties.get(Integer.class, "net.interface.%s.config.holdoff", deviceId);
63+
this.maxFail = properties.get(Integer.class, "net.interface.%s.config.maxFail", deviceId);
64+
this.deviceId = deviceId;
65+
66+
this.delay = this.holdoff != 0 && this.maxFail != 0 ? this.holdoff * this.maxFail : 90;
67+
try {
68+
this.mmDbusPath = this.networkManager.getModemManagerDbusPath(this.device.getObjectPath());
69+
} catch (DBusException e) {
70+
logger.warn("Could not get ModemManager dbus path for device {} because: ", this.device.getObjectPath(), e);
71+
this.mmDbusPath = Optional.empty();
72+
}
73+
}
74+
75+
public void scheduleConnection() {
76+
if (isConnectionScheduled.get() || !this.autoconnect) {
77+
return;
78+
}
79+
logger.info("Schedule connection for modem {} with path {}", this.deviceId, this.device.getObjectPath());
80+
this.isConnectionScheduled.set(true);
81+
this.connectionHandler = this.scheduler.schedule(() -> tryConnection(1), 0, TimeUnit.SECONDS);
82+
}
83+
84+
private void tryConnection(int attemptNumber) {
85+
try {
86+
logger.debug("Connection attempt {} for modem {} with path {} ...", attemptNumber, this.deviceId,
87+
this.device.getObjectPath());
88+
this.networkManager.activateConnection(this.connection, this.device);
89+
if (isModemConnected()) {
90+
logger.info("Connection for modem {} successful", this.deviceId);
91+
if (this.connectionHandler != null) {
92+
this.connectionHandler.cancel(true);
93+
}
94+
this.isConnectionScheduled.set(false);
95+
} else {
96+
logger.warn("Could not activate connection for modem {} with path {}", this.deviceId,
97+
this.device.getObjectPath());
98+
scheduleConnectInternal(attemptNumber);
99+
}
100+
} catch (DBusException | DBusExecutionException e) {
101+
logger.warn("Could not activate connection for modem {} with path {} because: ", this.deviceId,
102+
this.device.getObjectPath(), e);
103+
scheduleConnectInternal(attemptNumber);
104+
}
105+
}
106+
107+
private void scheduleConnectInternal(int attemptNumber) {
108+
if (attemptNumber < this.maxFail) {
109+
this.connectionHandler = this.scheduler.schedule(() -> this.tryConnection(attemptNumber + 1), this.holdoff,
110+
TimeUnit.SECONDS);
111+
} else {
112+
this.connectionHandler = this.scheduler.schedule(() -> tryConnection(1), this.delay, TimeUnit.SECONDS);
113+
}
114+
}
115+
116+
public void scheduleReset() {
117+
if (isResetScheduled.get() || this.resetDelayMinutes <= 0) {
118+
return;
119+
}
120+
logger.info("Schedule reset for modem {} with path {}", this.deviceId, this.device.getObjectPath());
121+
this.isResetScheduled.set(true);
122+
this.resetHandler = this.scheduler.schedule(() -> {
123+
try {
124+
if (!isModemConnected()) {
125+
if (this.connectionHandler != null) {
126+
this.connectionHandler.cancel(true);
127+
}
128+
if (this.mmDbusPath.isPresent()) {
129+
Modem modem = this.modemManager.getModem(mmDbusPath.get());
130+
modem.Reset();
131+
logger.info("Modem reset successful for modem {} with path {}", this.deviceId,
132+
this.device.getObjectPath());
133+
}
134+
}
135+
} catch (DBusException | DBusExecutionException e) {
136+
logger.warn("Could not reset modem {} with path {} because: ", this.deviceId,
137+
this.device.getObjectPath(), e);
138+
}
139+
this.isResetScheduled.set(false);
140+
}, this.resetDelayMinutes, TimeUnit.MINUTES);
141+
}
142+
143+
public void cancelAndShutdown() {
144+
cancel();
145+
this.scheduler.shutdownNow();
146+
}
147+
148+
public void cancel() {
149+
if (this.connectionHandler != null) {
150+
this.connectionHandler.cancel(true);
151+
}
152+
if (this.resetHandler != null) {
153+
this.resetHandler.cancel(true);
154+
}
155+
this.isConnectionScheduled.set(false);
156+
this.isResetScheduled.set(false);
157+
}
158+
159+
public Device getDevice() {
160+
return this.device;
161+
}
162+
163+
private boolean isModemConnected() throws DBusException {
164+
if (!this.mmDbusPath.isPresent()) {
165+
return false;
166+
}
167+
MMModemState modemState = this.modemManager.getMMModemState(mmDbusPath.get());
168+
return MMModemState.MM_MODEM_STATE_CONNECTED.equals(modemState);
169+
}
170+
}

kura/org.eclipse.kura.nm/src/main/java/org/eclipse/kura/nm/NMDbusConnector.java

Lines changed: 9 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.eclipse.kura.net.wifi.WifiSecurity;
3636
import org.eclipse.kura.nm.configuration.NMSettingsConverter;
3737
import org.eclipse.kura.nm.enums.MMModemLocationSource;
38-
import org.eclipse.kura.nm.enums.MMModemState;
3938
import org.eclipse.kura.nm.enums.NMDeviceState;
4039
import org.eclipse.kura.nm.enums.NMDeviceType;
4140
import org.eclipse.kura.nm.signal.handlers.DeviceCreationLock;
@@ -139,8 +138,8 @@ protected boolean configurationEnforcementIsActive() {
139138
&& this.configurationEnforcementHandlerIsArmed;
140139
}
141140

142-
protected boolean failedModemResetTimerIsActive(String modemId) {
143-
return this.modemManager.isMMFailedModemResetTimerArmed(modemId);
141+
protected boolean modemTaskHandlerIsPresent(String modemId) {
142+
return this.modemManager.isModemTaskHandlerActive(modemId);
144143
}
145144

146145
public void checkPermissions() {
@@ -358,7 +357,7 @@ ip4configProperties, ip6configProperties, new AccessPointsProperties(activeAcces
358357
public synchronized void apply(Map<String, Object> networkConfiguration) throws DBusException {
359358
try {
360359
configurationEnforcementDisable();
361-
this.modemManager.resetHandlersDisable();
360+
this.modemManager.modemTaskHandlerDisable();
362361
doApply(networkConfiguration);
363362
this.cachedConfiguration = networkConfiguration;
364363
} finally {
@@ -373,7 +372,7 @@ public synchronized void apply() throws DBusException {
373372
}
374373
try {
375374
configurationEnforcementDisable();
376-
this.modemManager.resetHandlersDisable();
375+
this.modemManager.modemTaskHandlerDisable();
377376
doApply(this.cachedConfiguration);
378377
} finally {
379378
configurationEnforcementEnable();
@@ -390,7 +389,7 @@ public synchronized void apply(String deviceId) throws DBusException {
390389
}
391390
try {
392391
configurationEnforcementDisable();
393-
this.modemManager.resetHandlersDisable(deviceId);
392+
this.modemManager.modemTaskHandlerDisable(deviceId);
394393
doApply(deviceId, this.cachedConfiguration);
395394
} finally {
396395
configurationEnforcementEnable();
@@ -561,31 +560,8 @@ private void enableInterface(String deviceId, NetworkProperties properties, Devi
561560
connection = Optional.of(createdConnection);
562561
}
563562

564-
// boolean activationSucceeded = true;
565-
// try {
566-
// this.modemManager.failedModemResetTimerCancel(deviceId);
567-
// // this.modemManager.modemConnectionTaskCancel(deviceId);
568-
// this.modemManager.connectionHandlersDisable(deviceId);
569-
// this.networkManager.activateConnection(connection.get(), device);
570-
// dsLock.waitForSignal();
571-
// } catch (DBusExecutionException e) {
572-
// logger.warn("Couldn't complete activation of {} interface, caused by:", deviceId, e);
573-
// activationSucceeded = false;
574-
// }
575-
//
576-
// // Housekeeping
577-
// List<Connection> availableConnections = this.networkManager.getAvaliableConnections(device);
578-
// for (Connection availableConnection : availableConnections) {
579-
// if (!connection.get().getObjectPath().equals(availableConnection.getObjectPath())) {
580-
// availableConnection.Delete();
581-
// }
582-
// }
583-
584563
if (deviceType == NMDeviceType.NM_DEVICE_TYPE_MODEM) {
585-
this.modemManager.failedModemResetTimerCancel(deviceId);
586-
// this.modemManager.modemConnectionTaskCancel(deviceId);
587-
this.modemManager.connectionHandlersDisable(deviceId);
588-
564+
this.modemManager.modemTaskHandlerDisable(deviceId);
589565
Optional<String> mmDbusPath = this.networkManager.getModemManagerDbusPath(device.getObjectPath());
590566
if (!mmDbusPath.isPresent()) {
591567
return;
@@ -599,52 +575,16 @@ private void enableInterface(String deviceId, NetworkProperties properties, Devi
599575
return;
600576
}
601577

602-
// int resetDelayMinutes = properties.get(Integer.class, "net.interface.%s.config.resetTimeout", deviceId);
603-
// boolean autoconnect = properties.get(Boolean.class, "net.interface.%s.config.persist", deviceId);
604-
int holdoff = properties.get(Integer.class, "net.interface.%s.config.holdoff", deviceId);
605-
int maxFail = properties.get(Integer.class, "net.interface.%s.config.maxFail", deviceId);
606-
607578
logger.info("Modem {} activated. Starting monitoring task...", deviceId);
608-
this.modemManager.modemConnectionTask(deviceId, this.modemManager, this.networkManager, connection.get(),
609-
device, maxFail, holdoff, autoconnect, resetDelayMinutes); // maybe change to handler...
610-
611-
// this.modemManager.resetHandlerEnable(deviceId, mmDbusPath, resetDelayMinutes, device.getObjectPath());
612-
//
613-
//
614-
//
615-
// if (autoconnect) {
616-
// logger.info("Modem {} configured for autoconnect. Starting connection task...", deviceId);
617-
// this.modemManager.modemConnectionTask(deviceId, this.networkManager, connection.get(), device, maxFail,
618-
// holdoff);
619-
// }
620-
//
621-
// // If a modem connection fails at the first try, it stays in the failed state, thus not triggering the
622-
// usual
623-
// // modem reset procedure. So, start a reset timer here.
624-
// if (!activationSucceeded && isModemFailed(mmDbusPath.get())) {
625-
// logger.info("Modem {} in failed state or unavailable. Scheduling modem reset in {} minutes ...",
626-
// device.getObjectPath(), resetDelayMinutes);
627-
//
628-
// this.modemManager.failedModemResetTimerSchedule(deviceId, mmDbusPath, resetDelayMinutes);
629-
//
630-
// // if (autoconnect) {
631-
// // logger.info("Modem {} configured for autoconnect. Starting connection task...", deviceId);
632-
// // this.modemManager.modemConnectionTask(deviceId, this.networkManager, connection.get(), device,
633-
// // maxFail, holdoff);
634-
// // }
635-
// }
579+
this.modemManager.modemTaskHandler(deviceId, this.modemManager, this.networkManager, connection.get(),
580+
device, properties);
636581

637582
} else {
638-
boolean activationSucceeded = true;
639583
try {
640-
// this.modemManager.failedModemResetTimerCancel(deviceId);
641-
// // this.modemManager.modemConnectionTaskCancel(deviceId);
642-
// this.modemManager.connectionHandlersDisable(deviceId);
643584
this.networkManager.activateConnection(connection.get(), device);
644585
dsLock.waitForSignal();
645586
} catch (DBusExecutionException e) {
646587
logger.warn("Couldn't complete activation of {} interface, caused by:", deviceId, e);
647-
activationSucceeded = false;
648588
}
649589
}
650590

@@ -656,48 +596,6 @@ private void enableInterface(String deviceId, NetworkProperties properties, Devi
656596
}
657597
}
658598

659-
// if (deviceType == NMDeviceType.NM_DEVICE_TYPE_MODEM) { // add checks for reset and autoconnect
660-
// int delayMinutes = properties.get(Integer.class, "net.interface.%s.config.resetTimeout", deviceId);
661-
// Optional<String> mmDbusPath = this.networkManager.getModemManagerDbusPath(device.getObjectPath());
662-
//
663-
// if (delayMinutes == 0 || !mmDbusPath.isPresent()) {
664-
// return;
665-
// }
666-
//
667-
// this.modemManager.resetHandlerEnable(deviceId, mmDbusPath, delayMinutes, device.getObjectPath());
668-
//
669-
// boolean autoconnect = properties.get(Boolean.class, "net.interface.%s.config.persist", deviceId);
670-
// int holdoff = properties.get(Integer.class, "net.interface.%s.config.holdoff", deviceId);
671-
// int maxFail = properties.get(Integer.class, "net.interface.%s.config.maxFail", deviceId);
672-
//
673-
// if (autoconnect) {
674-
// logger.info("Modem {} configured for autoconnect. Starting connection task...", deviceId);
675-
// this.modemManager.modemConnectionTask(deviceId, this.networkManager, connection.get(), device, maxFail,
676-
// holdoff);
677-
// }
678-
//
679-
// // If a modem connection fails at the first try, it stays in the failed state, thus not triggering the usual
680-
// // modem reset procedure. So, start a reset timer here.
681-
// if (!activationSucceeded && isModemFailed(mmDbusPath.get())) {
682-
// logger.info("Modem {} in failed state or unavailable. Scheduling modem reset in {} minutes ...",
683-
// device.getObjectPath(), delayMinutes);
684-
//
685-
// this.modemManager.failedModemResetTimerSchedule(deviceId, mmDbusPath, delayMinutes);
686-
//
687-
// // if (autoconnect) {
688-
// // logger.info("Modem {} configured for autoconnect. Starting connection task...", deviceId);
689-
// // this.modemManager.modemConnectionTask(deviceId, this.networkManager, connection.get(), device,
690-
// // maxFail, holdoff);
691-
// // }
692-
// }
693-
//
694-
// }
695-
696-
}
697-
698-
private boolean isModemFailed(String mmDbusPath) throws DBusException {
699-
MMModemState modemState = this.modemManager.getMMModemState(mmDbusPath);
700-
return MMModemState.MM_MODEM_STATE_FAILED.equals(modemState);
701599
}
702600

703601
private void createVirtualInterface(String deviceId, NetworkProperties properties, NMDeviceType deviceType)
@@ -761,8 +659,7 @@ private void disable(Optional<Device> optDevice, String deviceId) throws DBusExc
761659
logger.warn("Can't disable missing device {}", deviceId);
762660
return;
763661
}
764-
this.modemManager.failedModemResetTimerCancel(deviceId);
765-
this.modemManager.modemConnectionTaskCancel(deviceId);
662+
this.modemManager.modemTaskHandlerDisable(deviceId);
766663
Device device = optDevice.get();
767664
Optional<Connection> appliedConnection = this.networkManager.getAppliedConnection(device);
768665

0 commit comments

Comments
 (0)