|
||||||||
|
|
|||||||
![]() |
|
|
Thread Tools | Display Modes |
|
#1
|
|
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. Spoon |
|
#2
|
|||
|
|||
|
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. |
|
#3
|
|||
|
|||
|
> > 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. 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... |
|
#4
|
|||
|
|||
|
Rick Jones <(E-Mail Removed)> writes:
>> > 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. > > 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. |
|
#5
|
|||
|
|||
|
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. |
![]() |
| Tags |
| datagrams, deleting, socket |
| Thread Tools | |
| Display Modes | |
|
|