Unix Programming - Sendto(2) Never Reaches Wire

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > February 2005 > Sendto(2) Never Reaches Wire





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Sendto(2) Never Reaches Wire
Michael B Allen

2005-02-20, 6:20 pm

I'm writing some async dns client code. I've noticed that if I send a
quick succession of 5 requests sometimes [1] the first two never reach
the wire even though sendto(2) correctly reports the number of bytes written
and select(2) claims the socket is writeable for each call. This isn't
a problem because the retry code can compensate but it happends pretty
consistently on my Linux 2.4.28 x86 laptop so I'm wondering if there's a
way to avoid it. Is this normal for a sendto implementation? Can someone
recommend a technique to maybe ensure a little higher success rate?

Thanks,
Mike

[1] If I run tests back to back within a few seconds all requests are
sent successfully but if I wait a few minutes the first two packets
never reach the wire.
David Schwartz

2005-02-20, 6:20 pm


"Michael B Allen" <mba2000@ioplex.com> wrote in message
news:pan.2005.02.19.00.16.59.510514.19230@ioplex.com...

> I'm writing some async dns client code. I've noticed that if I send a
> quick succession of 5 requests sometimes [1] the first two never reach
> the wire even though sendto(2) correctly reports the number of bytes
> written
> and select(2) claims the socket is writeable for each call. This isn't
> a problem because the retry code can compensate but it happends pretty
> consistently on my Linux 2.4.28 x86 laptop so I'm wondering if there's a
> way to avoid it. Is this normal for a sendto implementation? Can someone
> recommend a technique to maybe ensure a little higher success rate?


If you want to use UDP, you must take responsibility for transmit
pacing. Otherwise, use TCP and let the kernel do it for you. Do not send a
quick succession of requests, pace them evenly, and backoff if you see
packet loss.

DS


Michael B Allen

2005-02-20, 6:20 pm

On Sat, 19 Feb 2005 02:00:38 -0500, David Schwartz wrote:

>
> If you want to use UDP, you must take responsibility for transmit
> pacing. Otherwise, use TCP and let the kernel do it for you. Do not send
> a quick succession of requests, pace them evenly, and backoff if you see
> packet loss.


Ok, well because my code is async I can't "see packet loss" until I call
my getbyname function the second time without the async flag to collect
responses from the cache. I guess I just shouldn't use it to lookup more
than 2 or 3 addresses at a time.

Otherwise I suppose the correct way to lookup many addresses at once
is really to put more than one question resource record into each
PDU. Actually can you put multiple question records in the same query
*for different domains* w/ recursion desired? The server would have to
split the query and then reconstitute the answer. I wonder.

Thanks,
Mike
Barry Margolin

2005-02-20, 6:20 pm

In article <pan.2005.02.19.00.16.59.510514.19230@ioplex.com>,
Michael B Allen <mba2000@ioplex.com> wrote:

> I'm writing some async dns client code. I've noticed that if I send a
> quick succession of 5 requests sometimes [1] the first two never reach
> the wire even though sendto(2) correctly reports the number of bytes written
> and select(2) claims the socket is writeable for each call. This isn't
> a problem because the retry code can compensate but it happends pretty
> consistently on my Linux 2.4.28 x86 laptop so I'm wondering if there's a
> way to avoid it. Is this normal for a sendto implementation? Can someone
> recommend a technique to maybe ensure a little higher success rate?
>
> Thanks,
> Mike
>
> [1] If I run tests back to back within a few seconds all requests are
> sent successfully but if I wait a few minutes the first two packets
> never reach the wire.


My guess is the destination address isn't in the ARP cache when you send
the first request. And that the OS will only buffer one packet while
waiting for the ARP response, so if you send additional packets in quick
succession they replace each other.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
James Antill

2005-02-20, 6:20 pm

On Sat, 19 Feb 2005 03:17:20 -0500, Michael B Allen wrote:

> On Sat, 19 Feb 2005 02:00:38 -0500, David Schwartz wrote:
>
>
> Ok, well because my code is async I can't "see packet loss" until I call
> my getbyname function the second time without the async flag to collect
> responses from the cache. I guess I just shouldn't use it to lookup more
> than 2 or 3 addresses at a time.


You can try upping the txqueuelen (ifconfig eth0 txqueuelen 1000), I know
it was around 100 (too small) at certain points in 2.4.x (but I don't
use a vanilla kernel, so I can't help more than that).

> Otherwise I suppose the correct way to lookup many addresses at once
> is really to put more than one question resource record into each
> PDU. Actually can you put multiple question records in the same query
> *for different domains* w/ recursion desired? The server would have to
> split the query and then reconstitute the answer. I wonder.


You can't put multiple queries for the same domain, or at least bind
doesn't work that way (I too thought you'd be able to do that).
You can use TCP[1] ... although, again, bind screws this up so if one
query blocks for too long it'll block all the queries behind it and
timeout the connection *sigh*.

[1] http://www.and.org/vstr/examples/ex_dns.c

--
James Antill -- james@and.org
Need an efficient and powerful string library for C?
http://www.and.org/vstr/

Michael B Allen

2005-02-20, 6:20 pm

On Sat, 19 Feb 2005 11:41:31 -0500, Barry Margolin wrote:

>
> My guess is the destination address isn't in the ARP cache when you send
> the first request. And that the OS will only buffer one packet while
> waiting for the ARP response, so if you send additional packets in quick
> succession they replace each other.


Yup. I bet that's exactly what's happening. Which means I probably *can*
do more than 2 or 3 async queries at the same time because once the ARP
cache is hot (has the DNS server / gateway's address) the success rate
should be much higher.

Thanks,
Mike
David Schwartz

2005-02-20, 6:20 pm


"Michael B Allen" <mba2000@ioplex.com> wrote in message
news:pan.2005.02.19.16.41.37.235900.22883@ioplex.com...

> Yup. I bet that's exactly what's happening. Which means I probably *can*
> do more than 2 or 3 async queries at the same time because once the ARP
> cache is hot (has the DNS server / gateway's address) the success rate
> should be much higher.


You will, unfortunately, really want to write your own transmit pacing
algorithm. When packets are going through, you can up the rate. When they're
not, you should lower it.

You may be able to get away with a simpler algorithm. Before sending the
next packet, impose a delay that goes down as the number of waiting packets
goes up. This is usually adequate.

DS


Michael B Allen

2005-02-20, 6:20 pm

On Sat, 19 Feb 2005 17:26:35 -0500, David Schwartz wrote:

> You may be able to get away with a simpler algorithm. Before sending the
> next packet, impose a delay that goes down as the number of waiting
> packets goes up. This is usually adequate.


Mmm, good idea. You mean impose a delay that goes up as the number of
outstanding requests goes up? I use a hashmap to store responses by
txnid. When a response comes in I just decode the txnid and lookup the
response object into which the data is decoded. So I could just do:

if ((n = hashmap_size(&cli->rsptbl)) > N_MIN) {
usleep(n);
}

But I have noticed that usleep on my Linux 2.4 system doesn't work
well with values less than 100 (seems to return immediately) so I don't
know how well this would work in practice. Maybe I should just make the
delay static:

if (hashmap_size(&cli->rsptbl) > N) {
usleep(100);
}

Mike
David Schwartz

2005-02-20, 6:20 pm


"Michael B Allen" <mba2000@ioplex.com> wrote in message
news:pan.2005.02.20.01.46.22.473130.27115@ioplex.com...
> On Sat, 19 Feb 2005 17:26:35 -0500, David Schwartz wrote:
>
[vbcol=seagreen]
> Mmm, good idea. You mean impose a delay that goes up as the number of
> outstanding requests goes up?


No, down. Otherwise, requests can back up without limit. If you have ten
requests waiting, wait a tenth of a second. If you five requests waiting,
wait a fifth. This is simpler than other algorithms and usually adequate.

> I use a hashmap to store responses by
> txnid. When a response comes in I just decode the txnid and lookup the
> response object into which the data is decoded. So I could just do:
>
> if ((n = hashmap_size(&cli->rsptbl)) > N_MIN) {
> usleep(n);
> }
>
> But I have noticed that usleep on my Linux 2.4 system doesn't work
> well with values less than 100 (seems to return immediately) so I don't
> know how well this would work in practice. Maybe I should just make the
> delay static:


Just keep track of when you sent the last packet, and usleep if and only
if it's too soon to send another. The algorithm will have to define what
'too soon' is, of course.

> if (hashmap_size(&cli->rsptbl) > N) {
> usleep(100);
> }


That may be suitable for your application, it's hard to say.

DS


David Schwartz

2005-02-23, 7:54 am


"Michael B Allen" <mba2000@ioplex.com> wrote in message
news:pan.2005.02.19.03.17.19.987225.20842@ioplex.com...

[vbcol=seagreen]
> Ok, well because my code is async I can't "see packet loss" until I call
> my getbyname function the second time without the async flag to collect
> responses from the cache. I guess I just shouldn't use it to lookup more
> than 2 or 3 addresses at a time.


I think it'd be better to design your function to tolerate multiple
calls and sensibly manage transmit pacing.

> Otherwise I suppose the correct way to lookup many addresses at once
> is really to put more than one question resource record into each
> PDU. Actually can you put multiple question records in the same query
> *for different domains* w/ recursion desired? The server would have to
> split the query and then reconstitute the answer. I wonder.


I don't think that's legal, but I'm not sure.

DS


Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com