Skip to content

Conversation

@askawu
Copy link

@askawu askawu commented Aug 9, 2017

Support sendto() and recvfrom() for datagram socket.

@askawu askawu force-pushed the sendto_and_recvfrom branch from fa1c014 to 3d25f3a Compare August 9, 2017 11:12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add {} always, even on one liners. this is a zephyr style requirement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a getter function anymore as you are appending data as well in the process, you'll have to rename this one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverse the order of all the 5 lines above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lines break are cheap and help for code readability, add empty lines after variable declaration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{} needed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use IS_ENABLED with this CONFIG option, in the test right below.

Do the same for ipv4 also

Copy link
Contributor

@pfalcon pfalcon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a quick reply, this seems more complex than intuitively expected.

My intuition can be wrong of course, but one issue I see is trying to resolve "default local bind for UDP" issue on BSD sockets level. This isn't good approach. We should resolve as many as possible issues on net_context (i.e. native Z API level), to make sure that it, and any levels above it benefit from it.

I introduced a framework for default local binding in #817, and applied it to net_context_connect(). It was on my TODO to apply it to UDP use cases which don't require explicit connect(), but that slipped.

So, I'd recommend to use the same approach and already introduced functions from #817 to handle unbound UDP context in net_context_send(to)() and net_context_recv().

Just as send/recv operations are usually on critical path, I'd suggest calling bind_default() only on UDP paths (as TCP should be already bound in connect()).

The above would be a separate PR. And actually, I'd suggest making inet_pton() fix (good catch!) its own PR too.

Copy link
Member

@jukkar jukkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not have anything extra, Tomasz pretty much commented everything already.

@jukkar
Copy link
Member

jukkar commented Aug 9, 2017

I introduced a framework for default local binding in #817, and applied it to net_context_connect(). It was on my TODO to apply it to UDP use cases which don't require explicit connect(), but that slipped.

Indeed, good point.

@jukkar jukkar added the net label Aug 10, 2017
@askawu
Copy link
Author

askawu commented Aug 10, 2017

@tbursztyka , I will correct the coding style problem. Thanks
@pfalcon , at the beginning, I tried to auto bind the local address by bind_default() in net context and it worked. But it become complicated when registering the recv callback before sendto(). Anyway, I will make the inet_pton patch as a new PR and see if I can make auto bind work for UDP in net context.

@askawu askawu force-pushed the sendto_and_recvfrom branch from 3d25f3a to 5aaee19 Compare August 23, 2017 10:05
@pfalcon
Copy link
Contributor

pfalcon commented Sep 13, 2017

@askawu: Any updates here? Would you like me to give a try to resolving auto-bind issue for UDP sockets?

@askawu
Copy link
Author

askawu commented Sep 14, 2017

@pfalcon, I updated the patch but I forgot to update the PR. Can you help to check if a81cbe2 makes sense to you? bind_default() is used to auto bind UDP soccket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would definitely suggest to call this only for UDP case, there's no need to do an extra call for TCP case. There're 2 ways to do that:

  1. If we care about source addr to be bound for offloading case, then just add bind_default() block wrapped in #if defined(CONFIG_NET_UDP) after existing #if defined(CONFIG_NET_TCP) right below.
  2. If we can cheat on offloading case, can reuse existing if (net_context_get_ip_proto(context) == IPPROTO_UDP) far below.

@jukkar : What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jukkar: Thanks for the reply, but it's "either/or" type of question (either way 1 above, or way 2) ;-). Please suggest which way to go.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GAnthony : Maybe you can suggest here something too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the second one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about returning the address len in *addrlen? If you didn't intend to do that, why is it passed by pointer?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the address size isn't necessary to be a pointer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'd say "it's useful to return the actual addrlen". Because otherwise, we probably don't even need to pass it in - struct sockaddr can accommodate both IPv4 and IPv6 addresses.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used to prevent out of bound access. For example, the address is IPv6 but a sockaddr_in variable is passed in. I know it's rare but the caller might make a mistake. In such case, an error will be returned, so I probably don't need to return the actual addrlen.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I assume you considered various usecases for this function, so sounds good. (And we can change it later if found useful.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once semantics of *addrlen figure out (comment below), this docstring should describe what gets there on input, what on output.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't appear to be correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do it differently - zsock_send() should just call to zsock_sendto() with NULL dest address. Given that there's issue with length returned (previous comment), you might need to it like that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this line here? (And not in zsock_send()? zsock_send() and zsock_sendto() should behave the same, and as noted previously, the way to ensure that is make one tail-call another).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption is, for TCP case, zsock_connect() will be called first and callback will be registered at that time. So I only add it in zsock_sendto().

If we make zsock_send() and zsock_send() in adhoc way, any idea to prevent the registering the callback twice? Is there a proper way in net context to check if the callback has been registered?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Yep, there're some non-obvious points which only come to attention when you dig deeper into things. (Which may hint that there should be a code comment about it!)

If we make zsock_send() and zsock_send() in adhoc way, any idea to prevent the registering the callback twice? Is there a proper way in net context to check if the callback has been registered?

Well, so you already register a callback here multiple times - each call to sendto() will lead to callback being registered. If that works, then testing for UDP and setting it in send() should also work.

But overall, that's a similar problem to bind_default(). I'd say, making send() to tail-cal to sendto() is more priority than avoiding duplicate setting if recv callback. Let's try to optimize it as we can now (i.e. set it in send*() only for UDP case), and I already accept that we'll need a much later pass over the socket code to see how we can optimize things.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is right. zsock_send() should be done like this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this conditionalizing, leading to code duplication? If we (may) need a packet header, let's keep it here, and consistently remove in zsock_recvfrom.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I prefer to keep the packet header for both cases. But I found zsock_recv_stream() needs to be modified a lot because packet header isn't dropped. I will modify this to prefer consistency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, you may be right - and we can't return src addr for an arbitrary TCP recv anyway (only for recv() which starts to consume a new packet). Well, that's why it's useful to know why something was implemented this or that way, so having extra info in the commit messages or PR comments is helpful. And yeah, I'd appreciate your giving another thought to trying to avoid that code duplication - if it will lead to only more code being added, sure, it's ok to leave it like that.

@pfalcon
Copy link
Contributor

pfalcon commented Sep 21, 2017

@askawu: Thanks for refactors so far, and sorry for the delay with the review.

Well, unfortunately it's still not there IMHO, some issues need fixing, and some things can be redone in an easier/cleaner way. Per-commit comments:

net: pkt: Add net_pkt_get_src_addr()

I was surprised that such a function needs to be introduced. How did we do it before? I checked echo_server and yeah, it picks src addr (to be dst addr on reply) in an adhoc way. @jukkar , how do you deal with it in http server? Would the func above be useful there, would you refactor to use it?

net: context: Bind default address for UDP

My usual suggestion goes here: please split unrelated patches to a standalobe PRs to allow for quicker review cycle. I also suggest to optimize TCP case (for which we know that context is already bound). There's a pending question to @jukkar how to best do that.

net: sockets: Implement sendto() and recvfrom()

zsock_recvfrom() is implemented like it should be - by making zsock_recv() to dispatch to it. There's still a code duplication to optimize though.

But instead of doing the same for zsock_sendto() and zsock_send(), it's done in adhoc way, which in particular leads to a bug with return length. Please redo the same way as zsock_recvfrom()/zsock_recv(). Besides being easier and cleaner that way, that's also definitely a requirement for socket offloading, I hope @GAnthony can second on that.

Thanks!

@askawu
Copy link
Author

askawu commented Sep 22, 2017

@pfalcon, Thanks for the comments. I will think about how to make zsock_send() and zsock_sendto() easier.
@jukkar, Can you help to review 8296c76? I would like to know if there's a better way to get the src address from the packet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pkt might not have context specified so this is error prone.
Family can be get using net_pkt_family(pkt) instead. For protocol, we could get that information from IP header, or we could store it to net_pkt header when packet is received. We have been trying to avoid increasing the size of net_pkt so first option could be done here.

So depending on family, the UDP/TCP information can be get like this
proto = NET_IPV6_HDR(pkt)->nexthdr;
or
proto = NET_IPV4_HDR(pkt)->proto;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you move this block before checking UDP/TCP, then you could add the proto resolving here.

@jukkar
Copy link
Member

jukkar commented Sep 27, 2017

I was surprised that such a function needs to be introduced. How did we do it before? I checked echo_server and yeah, it picks src addr (to be dst addr on reply) in an adhoc way. @jukkar , how do you deal with it in http server? Would the func above be useful there, would you refactor to use it?

That function sounds useful to have, +1 for that.

@jukkar
Copy link
Member

jukkar commented Sep 27, 2017

I also suggest to optimize TCP case (for which we know that context is already bound). There's a pending question to @jukkar how to best do that.

I must have missed this question, could you elaborate what was this question about?

Aska Wu added 2 commits September 28, 2017 15:06
Introduce net_pkt_get_src_addr() as a helper function to get the source
address and port from the packet header.

Signed-off-by: Aska Wu <[email protected]>
This patch makes net_context_sendto() work independently without calling
net_context_connect() first. It will bind default address and port if
necessary.

Also, since receive callback should be provided before sending data in
order to receive the response, bind default address and port to prevent
providing an unbound address and port to net_conn_register().

Signed-off-by: Aska Wu <[email protected]>
Aska Wu added 2 commits September 28, 2017 15:07
sendto() and recvfrom() are often used with datagram socket.

sendto() is based on net_context_sendto() and recvfrom() is based on
zsock_recv() with parsing source address from the packet header.

Signed-off-by: Aska Wu <[email protected]>
- Add test cases of ipv4/ipv6 sendto() and recvfrom()
- Set the main stack size to 2048 to enable both ipv4 and ipv6 on
  qemu_x86.
- Use net app for network setup.

Signed-off-by: Aska Wu <[email protected]>
@askawu askawu force-pushed the sendto_and_recvfrom branch from 047224c to d73c931 Compare September 28, 2017 07:14
@askawu
Copy link
Author

askawu commented Sep 28, 2017

Update:

  • net_pkt_get_src_addr() should use the family and protocol from packet header instead of the value in net context.
  • Bind default address and port only for UDP
  • Refactor zsock_send() and zsock_sendto() to remove the duplicated code.

Copy link
Member

@jukkar jukkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@pfalcon pfalcon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for all the refactoring!

@tbursztyka : Your comments also should have been addressed, can you please have a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants