-
Notifications
You must be signed in to change notification settings - Fork 3k
[ONME-2844] Supporting non-blocking connect() #3457
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
Conversation
A few new error codes are added to nsapi_error_t and support for non-blocking socket connect is added. Nanostack's connect call will be non-blocking. Whereas LWIP connect call is currently blocking, and it could be changed now to be non-blocking.
cc @kjbracey-arm as well |
@@ -48,6 +48,9 @@ enum nsapi_error { | |||
NSAPI_ERROR_DHCP_FAILURE = -3010, /*!< DHCP failed to complete successfully */ | |||
NSAPI_ERROR_AUTH_FAILURE = -3011, /*!< connection to access point failed */ | |||
NSAPI_ERROR_DEVICE_ERROR = -3012, /*!< failure interfacing with the network processor */ | |||
NSAPI_ERROR_IN_PROGRESS = -3013, /*!< operation (eg connect) in progress */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the distinction between NSAPI_ERROR_IN_PROGRESS and NSAPI_ERROR_WOULD_BLOCK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it, the distinctions seem to be:
"would block" - "that call had no effect, but you can try the same thing again later and it might work"
"in progress"- "that call started something, but it hasn't finished, check back for status later"
In the case of "connect", checking back after "in progress" could either be trying connect again (in which case you can expect "already in progress" or "is connected" errors), or just going ahead and trying to read/write (in which case you could get "not connected").
So "would block" means you have to try the same call again. "In progress" means you could just start trying the next call, as it will be accepted once the in-progress thing finishes (or maybe it'll even get queued).
Distinction doesn't actually matter to the blocking abstraction here though, as it does just keep calling connect().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having written that, I guess it follows that the blocking loop here could respond to "would block" by retrying. But POSIX doesn't have "would block" as a possible connect() return, and I guess this shouldn't encourage that.
Also, only interpreting new codes has the handy effect of ensuring this patch doesn't change existing behaviour for any current stacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, that makes sense. Thanks for clarifying.
Out of curiousity, is it valid to go straight to a non-blocking send loop after starting a non-blocking connect? Would send return NSAPI_ERROR_WOULD_BLOCK or NSAPI_ERROR_NO_CONNECTION at that point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be sort of be fine. BSD/POSIX would return ENOTCONN, so I'd expect stacks to give NO_CONNECTION to match.
Unfortunately in NSAPI, NSAPI will also give you NO_CONNECTION in place of ECONNFAILED, ECONNRESET or ETIMEDOUT. So you wouldn't be able to distinguish between a failed connection and one which just hadn't completed yet.
I guess you have to keep calling connect(), like this blocking loop.
And to make that work, you also have to make sure you do get a sensible error return from connect() after failure. What you wouldn't want is for it to give up on a connection in the background, and then have the next connect call just start it again.
That's generally handled by one or both of - having sticky errors on sockets, so next socket call after an error returns the error code, and/or not permitting more than 1 connect() attempt on any socket. Nanostack does the latter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update - apparently network stacks are not as consistent as I thought on this. BSD 4.4 actually doesn't return the sticky error code on connect(), and does permit a second connect, so this loop wouldn't work plugged raw into BSD.
https://stackoverflow.com/questions/17769964/linux-sockets-non-blocking-connect
https://cr.yp.to/docs/connect.html
Ew. Well, we can demand that underlying stacks handle this if they're supplying non-blocking connect. Doesn't seem unreasonable. They could incorporate their own sticky error handling or equivalent event handling, or call getsockopt(SO_ERROR) first in their connect handler.
_write_in_progress = false; | ||
|
||
/* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */ | ||
if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this check just be ret == NSAPI_ERROR_IS_CONNECTED && _timeout > 0
? What if a socket returns NSAPI_ERROR_IS_CONNECTED on the first call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scratch that, I just realized what that implies : )
This is really well done. The non-blocking connect has been missing for a while now, and this seems like a graceful way to integrate it. I am a bit concerned that when we introduce a non-blocking connect to lwip, we are going to have issues with existing programs that set the socket to non-blocking before connecting. This does seem the best path forward though. It would be nice if #3265 was merged first, since it includes a few tests on the network connect function. |
The one omission here is the non-blocking resolution - if the user passes a host name in non-blocking mode, it will block for the resolution, then proceed with a non-blocking connect. But that's another set of work, and this is consistent with other host-name-taking calls. Would be nice to do something about that some time as it stops DNS resolution working with mbed client over 6LoWPAN, which is why https://github.com/ARMmbed/mbed-os-example-client has to have |
@kjbracey-arm, that's a good point, it sounds like this is a part of several prs required to introduce a fully non-blocking connect api. Maybe we should create an issue to track this? Other than that, this pr looks good to come in as is, @hasnainvirk, thanks for the patch! |
@kjbracey-arm @c1728p9 happy with this patch? please review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worked on this with Hasnain - I'm happy with it.
A few new error codes are added to nsapi_error_t and
support for non-blocking socket connect is added.
Nanostack's connect call will be non-blocking.
Whereas LWIP connect call is currently blocking, and it could be changed now
to be non-blocking.