Unix Programming - Deleting all the datagrams in a socket

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > September 2007 > Deleting all the datagrams in a socket





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 Deleting all the datagrams in a socket
Spoon

2007-09-28, 7:30 am

Hello everyone,

Consider an internet datagram socket.
sock = socket(PF_INET, SOCK_DGRAM, 0);

This socket is bound to a local port. The OS will buffer datagrams as
they arrive, and I can recv() them into my app.

However, suppose that, at some point, I can tell that all the datagrams
buffered in the socket at this point in time are stale, i.e. my app
would simply discard them. There's no point in recv()ing them.

Is there a way to tell the kernel to discard all the messages in a
socket without having to recv() them?

(My OS is Linux 2.6.22 if it matters.)

Regards.
Rainer Weikusat

2007-09-28, 7:30 am

Spoon <root@localhost> writes:
> Consider an internet datagram socket.
> sock = socket(PF_INET, SOCK_DGRAM, 0);
>
> This socket is bound to a local port. The OS will buffer datagrams as
> they arrive, and I can recv() them into my app.
>
> However, suppose that, at some point, I can tell that all the
> datagrams buffered in the socket at this point in time are stale,
> i.e. my app would simply discard them. There's no point in recv()ing
> them.
>
> Is there a way to tell the kernel to discard all the messages in a
> socket without having to recv() them?


Closing the socket and eventually reopening an identically named one
aftwards should accomlish this.
Rick Jones

2007-09-28, 1:24 pm

> > Is there a way to tell the kernel to discard all the messages in a
[vbcol=seagreen]
> Closing the socket and eventually reopening an identically named one
> aftwards should accomlish this.


Albeit at the risk of missing messages between the time of close() and
the later bind() call.

I've always wondered, but never took the time to research/try, what
would happen if you set the SO_RCVBUF to some "Very Small Value" while
there was more than that Very Small Value's worth of data queued to
it, and then set it back up again. Of course that too runs the risk
of missing messsages, albeit perhaps for a smaller window.

However, since a UDP application is supposed to deal with the loss of
datagrams, if those windows were not opened too often, it might not be
so bad.

Finaly stream-of-consciousness typing - in some situations with UDP it
may be possible to use SO_REUSEADDR and/or SO_REUSEPORT to bind a
second socket to the same address as another. Ostensibly such a
socket created after the point of staleness detection would not
contain the stale datagrams. What remains as a question is to which
socket new datagrams would go while both were in existence. I'm sure
there is chapter and verse on that somewhere but it eludes my dimm
memory at the moment. Still, if the desired thing - newly arriving
datagrams go to the new socket (with going to the old being a
don'tcare) then one could create the new socket and close the old to
effect the "flush."

The whole thing does sort of beg the question though - what kept the
application from reading the datagrams out of the socket for so long
that they became uninteresting in the first place?

rick jones
--
portable adj, code that compiles under more than one compiler
these opinions are mine, all mine; HP might not want them anyway...
feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH...







Rainer Weikusat

2007-09-28, 7:21 pm

Rick Jones <rick.jones2@hp.com> writes:
>
>
> Albeit at the risk of missing messages between the time of close() and
> the later bind() call.


It is the purpose of a procedure which unconditionally drops whatever
is currently stored in socket buffer to 'miss messages'.

> I've always wondered, but never took the time to research/try, what
> would happen if you set the SO_RCVBUF to some "Very Small Value" while
> there was more than that Very Small Value's worth of data queued to
> it,


With Linux, the smallest 'very small value' is 256 byte. And the
actual effect would be 'quite amusing' [Linux 2.6.23-rc4], given the
original question. The socket receive buffer is set in
net/core/sock.c, sock_setsockopt, by this code (comments deleted):

case SO_RCVBUF:
if (val > sysctl_rmem_max)
val = sysctl_rmem_max;
set_rcvbuf:
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;

if ((val * 2) < SOCK_MIN_RCVBUF)
sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
else
sk->sk_rcvbuf = val * 2;
break;

As grep easily reveals, the sk->sk_rcvbuf values is not used in the
IPv4 UDP implementation. The receive path proper starts in net/ipv4/udp.c,
__udp4_lib_rcv:

int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
int proto)
{
struct sock *sk;
struct udphdr *uh = udp_hdr(skb);
unsigned short ulen;
struct rtable *rt = (struct rtable*)skb->dst;
__be32 saddr = ip_hdr(skb)->saddr;
__be32 daddr = ip_hdr(skb)->daddr;

/*
* Validate the packet.
*/
if (!pskb_may_pull(skb, sizeof(struct udphdr)))
goto drop; /* No space for header. */

ulen = ntohs(uh->len);
if (ulen > skb->len)
goto short_packet;

if (proto == IPPROTO_UDP) {

[...]

}

if (udp4_csum_init(skb, uh, proto))
goto csum_error;

[...]

sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
skb->dev->ifindex, udptable );

if (sk != NULL) {
int ret = udp_queue_rcv_skb(sk, skb);

It continues in udp_queue_rcv with:

int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
{
struct udp_sock *up = udp_sk(sk);
int rc;

[...]

if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
if (rc == -ENOMEM)
UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag);
goto drop;
}

and in sock_queue_rcv_skb (net/core/sock.c):

int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int err = 0;
int skb_len;

/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
number of warnings when compiling with -W --ANK
*/
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf) {
err = -ENOMEM;
goto out;
}

Consequently, your suggestion would (not counting minimum buffer size
issues) dutifully preserve all 'stale' messages, but refuse to receive
any new ones until the stale ones have been received.

Roughly the opposite of what was asked for.

[...]

> Finaly stream-of-consciousness typing - in some situations with UDP it
> may be possible to use SO_REUSEADDR and/or SO_REUSEPORT to bind a
> second socket to the same address as another. Ostensibly such a
> socket created after the point of staleness detection would not
> contain the stale datagrams. What remains as a question is to which
> socket new datagrams would go while both were in existence.


The relevant manpage (Linux 2.6/ socket(7)) states:

SO_REUSEADDR
Indicates that the rules used in validating addresses
supplied in a bind(2) call should allow reuse of local
addresses. For PF_INET sockets this means that a
socket may bind, except when there is an active
listening socket bound to the address.

So this wouldn't accomplish anything either.
fjblurt@yahoo.com

2007-09-29, 1:47 am

On Sep 28, 3:26 am, Spoon <root@localhost> wrote:
> Hello everyone,
>
> Consider an internet datagram socket.
> sock = socket(PF_INET, SOCK_DGRAM, 0);
>
> This socket is bound to a local port. The OS will buffer datagrams as
> they arrive, and I can recv() them into my app.
>
> However, suppose that, at some point, I can tell that all the datagrams
> buffered in the socket at this point in time are stale, i.e. my app
> would simply discard them. There's no point in recv()ing them.
>
> Is there a way to tell the kernel to discard all the messages in a
> socket without having to recv() them?


Do you really think the overhead of recv() is likely to be a problem?
It should take about as long as memcpy'ing the data, plus system call
overhead which you're going to have anyway.

I suppose you could use sendfile() from the socket to /dev/null, which
if sendfile is implemented sensibly should be more or less constant
time.

Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com