On Monday 02 March 2015 10:07:42 Thiago Macieira wrote:
> > Yes, these interfaces are really effectively map to internal file handles.
> 
> I'd much rather use the if_index / sin6_scope_id interface ID, since it's a 
> global number. The user won't be confused by a different index.
> 
> An alternative is to not provide indexes and instead just operate on
> pointers.
> 
> PS: your suggestion implies a non-thread-safe global state, which may not
> be  suitable for libraries that want to operate when new interfaces are
> detected and connected.

The only solution I can see for both issues is to use an opaque structure and 
operate on pointers to them. That will imply adding attribute getters as well 
as a free/dispose function.

I imagine we'll have:

ITVTInterface *itvt_interface_enumerate(void);
ITVTInterface *itvt_interface_next(ITVTInterface *);
void itvt_interface_free(ITVTInterface *);
bool itvt_interface_is_same(ITVTInterface *, ITVTInterface *);
bool itvt_interface_has_default_route(ITVTInterface *);
char *itvt_interface_name(ITVTInterface *);
enum ITVTInterfaceTechnology itvt_interface_technology(ITVTInterface *);
int itvt_interface_index(ITVTInterface *);

ITVTInterfaceList *itvt_interface_list_new_empty(void);
ITVTInterfaceList *itvt_interface_list_new_full(void);
void itvt_interface_list_clear(ITVTInterfaceList **);
void itvt_interface_list_add(ITVTInterfaceList **, ITVTInterface *);
void itvt_interface_list_remove(ITVTInterfaceList **, ITVTInterface *);

For Linux systems, ITVTInterface is a regular node in a list or array that 
contains the information copied from struct ifaddr (net/if.h) for IP-based 
interfaces and equivalent for other technologies. Every time you call 
itvt_interfaces_enumerate, it'll poll again and you'll get a new pointer. 
That's why I had to add the "is_same" function call so they can be compared.

For memory-constrained systems, the structure would not be opaque and we'd 
have a global array with the known interfaces. That way, for those systems, 
some or all of the functions may be inline. E.g.:

static inline char *itvt_interface_name(ITVTInterface *iface)
{
        return iface->name;
}

I'd also "abuse" the ITVTInterfaceList pointer by storing a bitfield of the 
known interfaces, which limits us to 31 entries in the list.

static inline int _itvt_interface_internal_index(ITVTInterface *iface)
{
        extern ITVTInterface _itvt_interface_global[31];
        return iface - _itvt_interface_global + 1;
}

ITVTInterfaceList *itvt_interface_list_new_empty(void)
{
        // bit 0 set means "positive list"
        return (ITVTInterfaceList *)1;
}

ITVTInterfaceList *itvt_interface_list_new_full(void)
{
        // biit 0 clear means "negative list"
        return (ITVTInterfaceList *)~1;
}

void itvt_interface_list_clear(ITVTInterfaceList **plist)
{
        size_t val = (size_t)*plist;
        if (val & 1)
                *plist = itvt_interface_list_new_empty();
        else
                *plist = itvt_interface_list_new_full();
}

void itvt_interface_list_add(ITVTInterfaceList **plist, ITVTInterface *iface)
{
        size_t val = (size_t)*plist;
        if (val & 1)
                val |= _itvt_interface_internal_index(iface);
        else
                val &= ~_itvt_interface_internal_index(iface);
        *plist = (ITVTInterfaceList *)val;
}

void itvt_interface_list_remove(ITVTInterfaceList **plist, ITVTInterface 
*iface)
{
        size_t val = (size_t)*plist;
        if (val & 1)
                val &= ~ _itvt_interface_internal_index(iface);
        else
                val |= _itvt_interface_internal_index(iface);
        *plist = (ITVTInterfaceList *)val;
}

Bug: if you add all 31 interfaces to the negative list, the pointer becomes 
null. This can be mitigated by limiting to 30 interfaces, so we could use 
another bit to indicate positive / negative, in addition to always setting bit 
0 to force the pointer not to be null.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

Reply via email to