-
Notifications
You must be signed in to change notification settings - Fork 7k
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
net: zstream API to abstract socket transport protocols (e.g. TCP vs TLS) #5985
Conversation
Codecov Report
@@ Coverage Diff @@
## master #5985 +/- ##
==========================================
+ Coverage 64.61% 65.08% +0.47%
==========================================
Files 421 422 +1
Lines 40296 39443 -853
Branches 6803 6651 -152
==========================================
- Hits 26037 25673 -364
+ Misses 11126 10687 -439
+ Partials 3133 3083 -50
Continue to review full report at Codecov.
|
Note that this includes #5981 as an inter-dependency. |
zstream_sock_init(&stream_sock, sock); | ||
stream = (zstream)&stream_sock; | ||
|
||
stream->api->write(stream, REQUEST, SSTRLEN(REQUEST)); |
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.
So, that's how it looks. #5900 mentioned this matter, now we can consider exact variants of look&feel:
stream->vt->write(stream, ...) - from "vtable"
stream->meth->write(stream, ...) - from "method"
These aren't much better/different from api
IMHO. Note that besides these (repeating), and extra var also needs to be introduced: stream = (zstream)&stream_sock
.
CALL_METH(stream, write, ...)
This still looks uglier IMHO. Also, realistically that would be ZSTREAM_CALL_METH().
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.
Naming something ZSTREAM_CALL_METH() would make it uncallable: meth, not even once.
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.
Using the stream struct like it is super ugly actually. I'd rather see inline functions to hide this.
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'd rather see inline functions to hide this.
Indeed, the winner is: zstream_write(), zstream_read(), etc. I'll add them.
@@ -1,4 +1,10 @@ | |||
# This makefile builds the sample for a POSIX system, like Linux | |||
|
|||
INC = -I$(ZEPHYR_BASE)/include |
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.
Are we still maintaining Makefiles?
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.
Maintaining? No. They just work ;-).
P.S. This Makefile is for POSIX, not for Zephyr. Obviously, there're no cmakes and ninjas in POSIX.
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 like the general idea of a streaming API, but I'm not really sold on the idea of having it only for sockets. It looks kind of like WinSock, where some things are available for sockets, but not for regular files. We might be better off with a discussion on file descriptions/file descriptors that involve the whole system (the FS API, networking, etc).
Well, this WIP PR comes out of pretty extensive discussion in #5900. In summary, the usecase is to abstract away differences of communicating between TCP and TLS sockets. But the proposed interface is exactly generalized to support any method of peer-to-peer communication (#5900 gives an example talking TLS over SPI). So, I'm not sure where idea that it's "only for sockets" comes from. |
19d9231
to
1745b16
Compare
Perhaps from the PR's title: "net: zstream API to abstract socket transport protocols (e.g. TCP vs TLS)" This PR appears to be trying to solve a different problem than bridging the missing gaps between net_app and BSD sockets (i.e., mainly, adding secure sockets), as there is no client/server setup, TLS configuration or connection management functionality here (yet?). A new generic stream interface for Zephyr might be a fine idea, but it would help to understand what current problems in Zephyr it is solving. As the updated http_get sample shows, it results in mixed abstraction levels, calling some lower level socket APIs, then maybe secure socket setup APIs (TBD?), then some stream APIs, all in the same program. The link provided in #5900 (https://www.openbsd.org/papers/linuxconfau2017-libtls/#slide-16) seems to be a reasonable API that tries to address the problem at hand. Maybe it can be generalize somewhat, but something like this seems more intuitive. |
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 did not see anything about mbedtls, but it is going to be exposing tls from mbedtls right? It already provides a way to link a socket to its context (the adaptation needs to be done though). Would mbedtls get link to socket via zstream_socket, and itself be exposed to user via (some) zstream_tls?
Overall, the base idea is actually solving a bit more than just tls. net_app tried to be the application level API for networking, but failed as it gathered everything in one struct, so it was bloated etc... Here it's split it 2: a common API, and a specialized "object" (I don't like this wording in C but well) implementing it. That specialization could be tls in our case. That reminds me some python package actually. Btw: zstream_ prefix: a bit too lengthy. What about zio_ ?
The problem is that it's taking the problem by the easiest part: read, write, flush and close.
But TLS will needs way more than that, and dedicated stuff such as configure and handshake for instance, are annoying parts. How is this approach going to address such requirements?
Other specialization would also come up with their own requirements. This will become quickly a nightmare to keep things generalized. In the end you'll have specialization of a base block, so different than others that besides the prefix name, nothing will be really compatible.
Trying to abstract too much sometime is an open door for bloating up things (we are supposed to run on constrained system). I am not entirely sure we need that kind of approach. Maybe one api doing one thing and doing it well would be just enough, as @GAnthony pointed it.
zstream_sock_init(&stream_sock, sock); | ||
stream = (zstream)&stream_sock; | ||
|
||
stream->api->write(stream, REQUEST, SSTRLEN(REQUEST)); |
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.
Using the stream struct like it is super ugly actually. I'd rather see inline functions to hide this.
I'm not sure if it's worth to go down this word-picking way, because formally, that title doesn't contain the word "only" still. I tried to answer @lpereira concerns, explaining that this PR is a WIP for #5900. I'm sorry for not marking the title as "[WIP]" the day it was submitted, which might caused confusion (now done). If I can disambiguate the intent of this PR even better, I'd gladly accept suggestions.
Yes, as the description of this PR says, it's "This is first iteration of work on #5900". Of course, first iteration means it's very initial steps on implementing it. If that's not clear enough, please suggest a better wording. I'm on the other hand a strong believer in the "release early, release often" process, which may allow more streamlined development cycle for all interested parties. |
1745b16
to
30da280
Compare
The latest push implements @tbursztyka's hint of adding inline function wrappers for virtual method calls, so there's now That also pretty much goes half-way towards @GAnthony's idea of reusing POSIX calls for TLS operations. So yes, now potentially someone very keen could do |
I don't see my work as trying to "bridging the gap between net_app and BSD sockets". Adding the missing features of streamlined TLS support, yes.
Client/server setup is part of BSD Sockets per se, many applications use it directly and don't need any special APIs. Such APIs can be added, but they're separate matter from abstracting TLS communication, I'm trying to tackle one problem at time.
TLS support in works, and as I mentioned, my plan is to focus on TLS communication, not configuration. On the latter front, we'll need help and support from our security people anyway. (To clarify how I see that, I definitely going to add something in that vein, and do my homework on that, but even after that I expect that security people may (among many other choices): a) shoot it down and say they rather do it themselves; b) us having a nice few-months go-between to get it right). |
Yup. As a status update, I was finishing writing that down and preparing to get my first crash with it, when I peeked at the mbedTLS code and found a couple of, well, issues. So, I'm taking excursion into that: #6025 , Mbed-TLS/mbedtls#1356 . |
Yeah, as a full disclosure, the ideas put forward here were tested and tried in MicroPython previously.
Well, let's consider them tentative names for now and discuss later. As for "zio", that's pretty precious, generic name, are you sure you'd like waste on this, relatively specific thing? |
30da280
to
0b59d56
Compare
I'm sorry again that I didn't make that obvious enough. I'd think that you would be the party to whom the intent behind this PR (and its prompt posting) would be clear: it shows what kind of changes you would need to apply to your patch #5854 to get 90% of TLS support in (90% of our part, there's also security people's part). Let me give a specific example: you would need to replace this line: https://github.com/zephyrproject-rtos/zephyr/pull/5854/files#diff-5364c0b04abf6f5bdd7374608c7f5f1eR270 with (per the latest API iteration as of today) with zsock_read(). The remaining 10% is answering questions like |
0b59d56
to
053e540
Compare
The latest push add initial prototype of TLS stream implementation. Few points:
|
I don't think this assessment is fair. After all, as long as there're abstraction levels at all, they will be mixed in the same program. "Mixed" is however the wrong word here, they aren't "mixed", but "layered" and "structured". Such approach is know as "software design using patterns" (https://en.wikipedia.org/wiki/Software_design_pattern). And that's what being used here. http_get is very simple program, so indeed uses all levels in a single function. In more complex programs, different abstractions are intended to be used in different functions. To emphasize that distinction and alleviate confusion, in the latest commit, "samples: sockets: http_get: Further conversion to use use TLS stream.", I split the single function in 2. http_request() accepts a stream object as a parameter and works solely with it, implementing "business logic" (HTTP GET request handling in this case). The purpose of the main() function is thus to perform the needed object construction and initialization. This is known is https://en.wikipedia.org/wiki/Dependency_injection design pattern, and indeed the one I'm trying to follow when designing this API.
That's how net_app was designed - pack everything under a "common API". Now concerns with that API are well known (one is "it packs too much things"). As I mentioned, I'd like to take a chance to redesign things, based on the experiences with that API. And it's fair to say that so far I'm trying to keep separate things separate, while abstracting common behavior to polymorphic interfaces. It's also fair to expect we may eventually meet with net_app's approach somewhere in the middle. But premature commonality complicates the design and analysis. |
I now did a bit of this homework and created such a ticket: #6086 |
053e540
to
f029f97
Compare
"zstream" is a new API to allow byte-stream communication abstracting and polymorphic to the underlying transport. Its primary purpose is to abstract network protocol communication over plain TCP and TLS sockets, but the API should be generic enough to abstract communication over other point-to-point byte-oriented transports, e.g. UART or SPI. The patch also includes reference implementation of a stream "class" for SOCK_STREAM (i.e. plain TCP) sockets. Also includes zstream_writeall() convenience function. This function is useful for blocking streams, to account for possibility of short writes. This function will write exactly as many bytes as requested by user, by repeating the operation with remaining data in case as short write(s) happen, unless an error happens before all data is written. The number of bytes actually written is returned using the out-pointer argument (it can be smaller than requested if error occurred). Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Provides simple wrappers around mbedTLS APIs to configure system-wide settings and few convenience wrappers for common operations. Majority of settings would be still configured using mbedTLS APIs directly. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
A number of (HTTPS) sites on the modern Internet mandate use of forward secrecy via ephemeral key exchange (DHE and ECDHE cyphersuites). Elabling such cyphersuites how leads to increased code size, mbedTLS heap usage, and runtime overheads, so enabling them in the existing config-mini-tls1_2.h doesn't seem like a good idea. Instead, create a new config, config-tls1_2.h, which includes config-mini-tls1_2.h, and enables more options. The idea of this file is to provide configuration as compatible as possible with modern state of TLS 1.2 usage on the Internet, so more options can be enabled in the future. In the meantime, this config enables DHE by default, because it leads to a moderate code size increase (~5K x86). However, DHE cyphersuites are known to be slow during handshake phase (up to 3 times slower than with ephemeral key exchanges, based on reports for OpenSSL). ECDHE is known to be faster (~50% time overhead), but leads to much higher code impact (~15K). So, for now only DHE is enabled. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This implements communication methods of TLS. TLS configuration is handled by the separate "tls_conf" module. It accepts mbedtls_ssl_config*, which can be configured e.g. using tls_conf module. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This sample is a port of samples/net/sockets/big_http_download. It thus supports TLS and downloading of files over HTTPS. It's configured to work with real-world sites on the Internet, and thus requires quite large TLS buffer size and various ciphers enabled, thus requiring lots of RAM and ROM, so can run only on high-end boards. Known supported boards are qemu_x86 and frdm_k64f. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
These exemplifies changes needed to convert a normal socket based application to use zstream API instead. (Note that this exactly this application is not intended to be converted, it's just a convinient base to show changes required). Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
These exemplifies changes needed to convert a normal socket based application to use zstream API instead. (Note that this exactly this application is not intended to be converted, it's just a convinient base to show changes required). Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
An API for adapting synchronous BSD socket APIs to applications requiring asynchronous callbacks. Created to ease migration of asynchronous Zephyr IP protocols from net_app/net_context to BSD sockets. Initially, this supports client side TCP sockets, to enable porting the mqtt publisher sample to BSD sockets. Todo: - add UDP async sendto/recvfrom - add server support: accept/listen - handle nonblocking send socket failures (EWOULDBLOCK, EAGAIN, etc). - ensure IPV6 is supported. Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
Goals are to: - provide an example of a non-trivial Zephyr IP protocol working over standard BSD sockets. - enhance portability: since the mqtt code is based on a standard API, it can have value beyond the Zephyr project. - port mqtt with minimal change to the existing Zephyr mqtt API. Design Notes: - the async_socket library is introduced to adapt the synchronous BSD socket APIs to the asynchronous mqtt library. - the async_socket library can be expanded in the future and used for porting other Zephyr asynchronous IP protocols. Validated: - samples/net/mqtt_publisher on qemu_x86 (non-secure sockets only). Todo: - Port TLS support - Fix tests/net/lib/mqtt_* test cases and validate. Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
After the port of mqtt to BSD sockets, there is no need for an mqtt application to include net_context.h. Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
is this still relevant? |
@pfalcon ping |
Closing given that #9007 was merged upstream. |
This is
iteratitive(iterations now squashed) work on #5900