Fix for fake client on first GSM async SSL connection #99
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hello everyone,
I'm here to provide a fix (or its inspiration) to you great guys.
## SCENARIO
I was happily using MKRGSM library to register on GSM/GPRS and connect to HTTPS host for data transfer, asynchronously. So far so good.
I updated MKRGSM and Arduino SAMD library to latest version (respectively 1.4.2 and 1.8.3; unfortunately I can't tell the previously installed version, they should be 1.3.3 and 1.6.21 but I really cannot bet on it), and noticed that first connection to the HTTPS host started to give back a not-connected client despite the "ready()" cheering it was all OK.
## ENVIRONMENT
IDE: Visual Studio w/ Visual Micro extension
Arduino SAMD library: 1.8.3
MKRGSM library: 1.4.2
## REQUIREMENTS
## WHAT'S GOING ON
I debugged and found the problem was introduced along with the GSMSSLClient being able to import root certificates. In short what happens is that if one tries to connect asynchronously to SSL host, the ready method (only on first connection attempt) returns 1 after it loads the certificates but before it library actually creates a new socket for the connection.
In deep this happens:
Calling
GSMSSLClient::connect(...)
sets state for classGSMSSLClient
and forwards to itsconnectSSL
that in turn forwards toGSMClient::connect(...)
.Now, in
GSMClient::connect(...)
is the following code:The flow closes any previous opened socket and wait for it. Then it moves to set the new state for
GSMClient
to "create socket". This works only in synchronous mode.If client is declared "asynchronous", the flow quits right away there where is the flag comment (leaving
GSMClient::_state
equal to 0) because thatready
will handle theGSMSSLClient::ready()
that imports the certificates so it'll return 0 for sure (as it is working) so quitting theGSMClient::connect(...)
method.Then the snippet in
GSMSSLClient::ready()
:rightly moves the control to
GSMClient
when certificates are loaded, but at the first connection attemptGSMClient::_state
is 0 (as stated above, that isCLIENT_STATE_IDLE
), so the code inGSMClient::ready()
:returns and you have a
ready()
saying "It's all OK" when actually there's no socket ready, andclient.connected()
returnsfalse
indeed. This leads to bugs as users expect "ready" to say "OK" when client is actually OK, when instead it is not.## THE FIX
My first solution to this is simple (opened to improvements!), I'd replace the code in
GSMClient::connect()
:with
because I think there's no clue on returning from
connect
method while connection has not been initiated yet, even in asynchronous mode.## HOW TO REPRODUCE
I'm providing the following self-contained sketch to test this.
Just remember to provide PIN for SIM, APN credentials and an HTTPS URL (I use an AWS HTTPS API gateway test endpoint for example).
When bug shows you should read
"Er, no. Client is not connected actually."
.When bug does not show you should read
"Client is connected, fine."
.Essay is over. HTH. Thank you.