UNIX Network Programming Volume 1, Third Edition [Electronic resources] : The Sockets Networking API نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

UNIX Network Programming Volume 1, Third Edition [Electronic resources] : The Sockets Networking API - نسخه متنی

Addison Wesley

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










18.6 Interface Name and Index Functions


RFC 3493 [Gilligan et al. 2003] defines four functions that deal with interface names and indexes. These four functions are used in many places where it is necessary to describe an interface. They were introduced for use with the IPv6 API, as we will describe in Chapters 21 and 27, but we find interface indexes in the IPv4 API as well (e.g., in the IP_RECVIF call, or in AF_LINK sockaddrs seen on the routing socket). The basic concept is that each interface has a unique name and a unique positive index (0 is never used as an index).

#include <net/if.h>

unsigned int if_nametoindex (const char *

ifname );

Returns: positive interface index if OK, 0 on error

char *if_indextoname (unsigned int

ifindex , char *

ifname );

Returns: pointer to interface name if OK, NULL on error

struct if_nameindex *if_nameindex (void);

Returns: non-null pointer if OK, NULL on error

void if_freenameindex(struct if_nameindex *

ptr );

if_nametoindex returns the index of the interface whose name is

ifname . if_indextoname returns a pointer to the interface name given its

ifindex . The

ifname argument points to a buffer of size IFNAMSIZ (defined by including the <net/if.h> header; also shown in Figure 17.2) that the caller must allocate to hold the result, and this pointer is also the return value upon success.

if_nameindex returns a pointer to an array of if_nameindex structures as follows:



struct if_nameindex {
unsigned int if_index; /* 1, 2, ... */
char *if_name; /* null-terminated name: "le0", ... */
};


The final entry in this array contains a structure with an if_index of 0 and an if_name that is a null pointer. The memory for this array, along with the names pointed to by the array members, is dynamically obtained and is returned by calling if_freenameindex.

We now provide an implementation of these four functions using routing sockets.


if_nametoindex Function


Figure 18.18 shows the if_nametoindex function.

Figure 18.18 Return an interface index given its name.

libroute/if_nametoindex.c


1 #include "unpifi.h"
2 #include "unproute.h"
3 unsigned int
4 if_nametoindex(const char *name)
5 {
6 unsigned int idx, namelen;
7 char *buf, *next, *lim;
8 size_t len;
9 struct if_msghdr *ifm;
10 struct sockaddr *sa, *rti_info[RTAX_MAX];
11 struct sockaddr_dl *sdl;
12 if ( (buf = net_rt_iflist(0, 0, &len)) == NULL)
13 return (0);
14 namelen = strlen(name);
15 lim = buf + len;
16 for (next = buf; next < lim; next += ifm->ifm_msglen) {
17 ifm = (struct if_msghdr *) next;
18 if (ifm->ifm_type == RTM_IFINFO) {
19 sa = (struct sockaddr *) (ifm + 1);
20 get_rtaddrs (ifm->ifm_addrs, sa, rti_info);
21 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
22 if (sa->sa_family == AF_LINK) {
23 sdl = (struct sockaddr_dl *) sa;
24 if (sdl->sdl_nlen == namelen
25 && strncmp (&sdl->sdl_data [0], name,
26 sdl->sdl_nlen) == 0) {
27 idx = sdl->sdl_index; /* save before free() */
28 free(buf);
29 return (idx);
30 }
31 }
32 }
33 }
34 }
35 free(buf);
36 return (0); /* no match for name */
37 }


Get interface list

1213 Our net_rt_iflist function returns the interface list.


Process only RTM_IFINFO messages

1730 We process the messages in the buffer (Figure 18.14), looking only for the RTM_IFINFO messages. When we find one, we call our get_rtaddrs function to set up the pointers to the socket address structures, and if an interface name structure is present (the RTAX_IFP element of the rti_info array), the interface name is compared to the argument.


if_indextoname Function


The next function, if_indextoname, is shown in Figure 18.19.

Figure 18.19 Return an interface name given its index.

libroute/if_indextoname.c


1 #include "unpifi.h"
2 #include "unproute.h"
3 char *
4 if_indextoname(unsigned int idx, char *name)
5 {
6 char *buf, *next, *lim;
7 size_t len;
8 struct if_msghdr *ifm;
9 struct sockaddr *sa, *rti_info [RTAX_MAX];
10 struct sockaddr_dl *sdl;
11 if ( (buf = net_rt_iflist(0, idx, &len)) == NULL)
12 return (NULL);
13 lim = buf + len;
14 for (next = buf; next < lim; next += ifm->ifm_msglen) {
15 ifm = (struct if_msghdr *) next;
16 if (ifm->ifm_type == RTM_IFINFO) {
17 sa = (struct sockaddr *) (ifm + 1);
18 get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
19 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
20 if (sa->sa_family == AF_LINK) {
21 sdl = (struct sockaddr_dl *) sa;
22 if (sdl->sdl_index == idx) {
23 int slen = min(IFNAMSIZ - 1, sdl->sdl_nlen);
24 strncpy(name, sdl->sdl_data, slen);
25 name[slen] = 0; /* null terminate */
26 free(buf);
27 return (name);
28 }
29 }
30 }
31 }
32 }
33 free(buf);
34 return (NULL); /* no match for index */
35 }

This function is nearly identical to the previous function, but instead of looking for an interface name, we compare the interface index against the caller's argument. Also, the second argument to our net_rt_iflist function is the desired index, so the result should contain the information for only the desired interface. When a match is found, the interface name is returned and it is also null-terminated.


if_nameindex Function


The next function, if_nameindex, returns an array of if_nameindex structures containing all the interface names and indexes. It is shown in Figure 18.20.

Figure 18.20 Return all the interface names and indexes.

libroute/if_nameindex.c


1 #include "unpifi.h"
2 #include "unproute.h"
3 struct if_nameindex *
4 if_nameindex (void)
5 {
6 char *buf, *next, *lim;
7 size_t len;
8 struct if_msghdr *ifm;
9 struct sockaddr *sa, *rti_info [RTAX_MAX];
10 struct sockaddr_dl *sdl;
11 struct if_nameindex *result, *ifptr;
12 char *namptr;
13 if ( (buf = net_rt_iflist (0, 0, &len) ) == NULL)
14 return (NULL);
15 if ( (result = malloc (len) ) == NULL) /* overestimate */
16 return (NULL);
17 ifptr = result;
18 namptr = (char *) result + len; /* names start at end of buffer */
19 lim = buf + len;
20 for (next = buf; next < lim; next += ifm->ifm_msglen) {
21 ifm = (struct if_msghdr *) next;
22 if (ifm->ifm_type == RTM_IFINFO) {
23 sa = (struct sockaddr *) (ifm + 1);
24 get_rtaddrs (ifm->ifm_addrs, sa, rti_info);
25 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
26 if (sa->sa_family == AF_LINK) {
27 sdl = (struct sockaddr_dl *) sa;
28 namptr -= sdl->sdl_nlen + 1;
29 strncpy (namptr, &sdl->sdl_data[0], sdl->sdl_nlen);
30 namptr [sdl->sdl_nlen] = 0; /* null terminate */
31 ifptr->if_name = namptr;
32 ifptr->if_index = sdl->sdl_index;
33 ifptr++;
34 }
35 }
36 }
37 }
38 ifptr->if_name = NULL; /* mark end of array of structs */
39 ifptr->if_index = 0;
40 free (buf);
41 return (result); /* caller must free() this when done */
42 }


Get interface list, allocate room for result

1318 We call our net_rt_iflist function to return the interface list. We also use the returned size as the size of the buffer that we allocate to contain the array of if_nameindex structures we return. This is an overestimate, but it is simpler than making two passes through the interface list: one to count the number of interfaces and the total sizes of the names and another to fill in the information. We create the if_nameindex array at the beginning of this buffer and store the interface names starting at the end of the buffer.


Process only RTM_IFINFO messages

2336 We process all the messages looking for RTM_IFINFO messages and the datalink socket address structures that follow. The interface name and index are stored in the array we are building.


Terminate array

3839 The final entry in the array has a null if_name and an index of 0.


if_freenameindex Function


The final function, shown in Figure 18.21, frees the memory that was allocated for the array of if_nameindex structures and the names contained therein.

Figure 18.21 Free the memory allocated by if_nameindex.

libroute/if_nameindex.c


43 void
44 if_freenameindex(struct if_nameindex *ptr)
45 {
46 free(ptr);
47 }

This function is trivial because we stored both the array of structures and the names in the same buffer. If we had called malloc for each name, to free the memory, we would have to go through the entire array, free the memory for each name, and then free the array.


/ 450