lwip-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-devel] Extended udp_recv callback


From: Jakob Stoklund Olesen
Subject: Re: [lwip-devel] Extended udp_recv callback
Date: Wed, 14 Jan 2009 11:36:29 +0100
User-agent: Thunderbird 2.0.0.19 (X11/20090105)

Kieran Mansley wrote:
> On Tue, 2009-01-13 at 18:16 +0100, Jakob Stoklund Olesen wrote:
>> The mDNSResponder code for Posix, Mac OS X, and VxWorks uses the
>> recvmsg() syscall and struct cmsghdr. I am not familiar with this API,
>> it looks quite complicated. See recvmsg(2) and cmsg(3).

[...]

> We wouldn't be able to do the full version of that, no, but we might be
> able to do a reduced set, or something similar.  I think it's worthy of
> further investigation, even if only to make the extended API that is
> being discussed a bit more like the recvmsg and cmsg API.

Something like recvmsg() would have to be implemented at the socket
layer, right? It is very similar to recv() and recvfrom(). They share a
man page.

I have tried to find documentation on the contents of struct cmsghdr.
This seems to be quite hard. I believe it can be used to pass on any
kind of lower-layer information.

>From Stevens, "TCP/IP Illustrated, Volume 2": In BSD, if you set the
socket option IP_RECVSTADDR, you will get a cmsg entry with
cmsg_level=IPPROTO_IP, cmsg_type=IP_RECVSTADDR, cmsg_data=destination IP
address.

>From Stevens, "Advanced Programming in the UNIX Environment": In 4.3BSD
REno, call sendmsg() with cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS to
pass a file descriptor between processes. I assume this requires a
PF_UNIX socket or a FIFO or something.

>From the mDNSResponder Posix port: When cmsg_level=IPPROTO_IP we may get
the following values for cmsg_type:

IP_PKTINFO -> struct in_pktinfo 
IP_RECVDSTADDR -> struct in_addr (as Stevens)
IP_RECVIF -> struct sockaddr_dl
IP_RECVTTL -> unsigned char
IP_TTL -> unsigned char
IPV6_PKTINFO -> struct in6_pktinfo
IPV6_HOPLIMIT -> int

>From /usr/include/linux/in.h on a Linux-2.6 system:

#define IP_TOS          1
#define IP_TTL          2
#define IP_HDRINCL      3
#define IP_OPTIONS      4
#define IP_ROUTER_ALERT 5
#define IP_RECVOPTS     6
#define IP_RETOPTS      7
#define IP_PKTINFO      8
#define IP_PKTOPTIONS   9
#define IP_MTU_DISCOVER 10
#define IP_RECVERR      11
#define IP_RECVTTL      12
#define IP_RECVTOS      13
#define IP_MTU          14
#define IP_FREEBIND     15
#define IP_IPSEC_POLICY 16
#define IP_XFRM_POLICY  17
#define IP_PASSSEC      18

As far as I can tell, if you call setsockopt() with the above values,
the corresponding cmsghdr will be available from recvmsg().


Here is what I propose:

I will add this to opt.h:

/**
 * UDP_RAW_RECV_CALLBACK==1: Enable the udp_set_raw_recv_callback()
 * API function. This makes it possible to register UDP receive
 * callbacks with access to the IP header and receiving interface.
 */
#ifndef UDP_RAW_RECV_CALLBACK
#define UDP_RAW_RECV_CALLBACK           0
#endif


I will create an extra UDP callback prototype in udp.h:

#if UDP_RAW_RECV_CALLBACK
/** UDP raw receive callback function.
 *
 * This is an alternative UDP callback for applications that need
 * detailed information from the IP layer such as destination IP
 * address, TTL etc. A udp_raw_recv_callback_t is set by calling
 * udp_set_raw_recv_callback() instead of udp_recv().
 *
 * port is in host byte order, iphdr is untouched, and all fields are
 * in network byte order. The IP source address is available as
 * iphdr->src.
 *
 * The callback is responsible for freeing the pbuf if it's not used
 * any more.
 *
 * @param arg user supplied argument (udp_pcb.recv_arg)
 * @param pcb the udp_pcb which received data
 * @param p the packet buffer that was received
 * @param port the remote port from which the packet was received
 * @param iphdr the raw IP header of the packet
 * @param netif the interface that received the packet
 */
typedef void (*udp_raw_recv_callback_t)(
    void *arg,
    struct udp_pcb *pcb,
    struct pbuf *p,
    u16_t port,
    const struct ip_hdr *iphdr,
    struct netif *netif);
#endif /* UDP_RAW_RECV_CALLBACK */


And the following implementation in udp_input():


#if UDP_RAW_RECV_CALLBACK
        if (pcb->flags & UDP_FLAGS_RAW_RECV_CALLBACK) {
          ((udp_raw_recv_callback_t)pcb->recv)(
            pcb->recv_arg, pcb, p, src, iphdr, inp);
        } else
#endif /* UDP_RAW_RECV_CALLBACK */
        {
          pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
        }


Thus, when UDP_RAW_RECV_CALLBACK==0 everything works as before. When
UDP_RAW_RECV_CALLBACK==1 udp_recv() still works exactly as before, but
with a small runtime overhead (the extra if in udp_input()). You get
this alternative to udp_recv():

#if UDP_RAW_RECV_CALLBACK
void udp_set_raw_recv_callback(
  struct udp_pcb *pcb,
  udp_raw_recv_callback_t recv,
  void *recv_arg);
#endif /* UDP_RAW_RECV_CALLBACK */

Code that uses udp_recv() will not need to be changed either way.

I am not very familiar with the lwIP socket layer -- I am not using it.
I believe you could implement most of the recvmsg() functionality by
extending struct netbuf to also hold ip_hdr and netif pointers. The
ip_hdr wouĺd give you access to IP_TOS, IP_TTL, IP_OPTIONS, and
IP_RECVSTADDR.

Unfortunately I cannot offer to write recvmsg() for you, but I believe
the udp_raw_recv_callback_t provides the proper foundation to do so.

I have a working patch that implements UDP_RAW_RECV_CALLBACK. Should I
submit it?


Regards,
/stoklund




reply via email to

[Prev in Thread] Current Thread [Next in Thread]