Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send message await forever #599

Open
jack8525 opened this issue Jan 4, 2024 · 11 comments · May be fixed by #600
Open

Send message await forever #599

jack8525 opened this issue Jan 4, 2024 · 11 comments · May be fixed by #600
Labels
bug Something isn't working

Comments

@jack8525
Copy link

jack8525 commented Jan 4, 2024

Where do you suspect the issue?

Issue in mesh library, e.g. packets being dropped

Version

4.1.0 (latest)

Describe the issue

_ = try? await globalMeshNetworkManager?.send(meshMessage, to: MeshAddress(sendMessageTask.address), using: applicationKey)

I send an AcknowledgedMeshMessage but get bearerDidClose error.
image
this else isn't handled, so the library awaits forever. What should I do?

@jack8525 jack8525 added the bug Something isn't working label Jan 4, 2024
@philips77
Copy link
Member

Thank you for reporting the issue. I'll look into it and come back to you.

@philips77
Copy link
Member

For Acknowledged messages there's a timer on Access Layer that should try to retransmit the message and time out eventually.

@philips77
Copy link
Member

OK. I see where the issue may occur.

AccessLayer sets the repeat & timeout timer only for acknowledge messages sent to a Unicast Address:

// Set timers for the acknowledged messages.
// Acknowledged messages sent to a Group address won't await a Status.
if message is AcknowledgedMeshMessage,
destination.address.isUnicast {
createReliableContext(for: pdu, sentFrom: element, withTtl: initialTtl, using: keySet)
}

That means, that acknowledged messages sent to a Group Address (or Virtual Address) don't get that timer set. Such messages may be sent to 0+ nodes and the transmitter can receive 0+ responses. In that case, it is the underlying layer that should notify the network manager, just like for unacknowledged messages.

However, as you pointed out, when the Acknowledged Mesh Message is unsegmented, like ConfigOnOffSet, and sending the message fails, the network manager is never notified:

if !pdu.message!.isAcknowledged {
networkManager.notifyAbout(error: error, duringSendingMessage: pdu.message!,
from: localElement, to: pdu.destination)
}

I'll prepare a fix.

@philips77
Copy link
Member

image

@philips77
Copy link
Member

Btw, for multicast addresses it is recommended not to use Acknowledged messages, but their Unacknowledged counterparts. This significantly decreases the traffic in the network.

@philips77
Copy link
Member

Hmm... I did some more digging and seems like the Network Layer doesn't throw bearerDidClose when the message is sent to a group address, as such message may be handled internally:

// Loopback interface.
if shouldLoopback(networkPdu) {
handle(incomingPdu: networkPdu.pdu, ofType: type)
// Messages sent with TTL = 1 will only be sent locally.
guard ttl != 1 else { return }
if isLocalUnicastAddress(networkPdu.destination) {
// No need to send messages targeting local Unicast Addresses.
return
}
// If the message was sent locally, don't report Bearer closer error.
try? transmitter.send(networkPdu.pdu, ofType: type)
} else {

This is the shouldLoopback method:

/// Returns whether the PDU should loop back for local processing.
///
/// - parameter networkPdu: The PDU to check.
func shouldLoopback(_ networkPdu: NetworkPdu) -> Bool {
let address = networkPdu.destination
return address.isGroup || address.isVirtual || isLocalUnicastAddress(address)
}

As you're getting that error, that means, that you're sending the message to a Unicast Address. In that case, the network manager should wait until the response is received from the target, which happens on Access Layer.
I'll leave #600 open, but don't think it's required.

@philips77
Copy link
Member

Could you say what message are you trying to send exactly, what are your network parameters (default?) and what is the destination address of the message?

@jack8525
Copy link
Author

jack8525 commented Jan 5, 2024

Thank you for your help. I just send some GenericOnOffSet to a Unicast Address when not connected.In this case, a timeout will not be thrown?

@philips77
Copy link
Member

There will be a timeout. The timeout is set using:

/// Sets the timeout for receiving a response to an acknowledged access message.
///
/// The ``MeshNetworkDelegate/meshNetworkManager(_:failedToSendMessage:from:to:error:)-7iylf``
/// callback will be called when the response is not received before the timeout expires..
///
/// - parameter timeout: The timeout after which the ``AccessError/timeout``
/// is reported. This shall be set to a minimum of 30 seconds,
/// which is also the default value.
/// - seeAlso: ``NetworkParameters/acknowledgmentMessageTimeout``
public func discardAcknowledgedMessages(after timeout: TimeInterval) {
networkParameters.acknowledgmentMessageTimeout = timeout
}

Documentatuion

@jack8525
Copy link
Author

jack8525 commented Jan 6, 2024

I found failedToSendMessage is no callback. Because Address change to MeshMessage.
After fix it.
I can handle the timeout here.

@jack8525
Copy link
Author

jack8525 commented Jan 6, 2024

image
Can I handle deliveryCallbacks here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants