Hi Folks,
As discussed earlier i have added the optional %iface parameter
to slp to allow specifying particular interface. I have made it backward
compatible to allow older method of specifying the interface as well.
Iam attaching the patch with this mail. Let me know if its ok. As of now its
only linux port. I have code ready for win32 aswell which i will be submitting
later. If its ok we can push this upstream.
Regards,
Varun
Index: common/slp_socket.h
===================================================================
--- common/slp_socket.h (revision 1632)
+++ common/slp_socket.h (working copy)
@@ -97,6 +97,7 @@
# include <net/if.h>
# include <net/if_arp.h>
# include <netdb.h>
+# include <ifaddrs.h>
/** Portability definitions
* @todo Move to slp_types.h
Index: common/slp_iface.c
===================================================================
--- common/slp_iface.c (revision 1632)
+++ common/slp_iface.c (working copy)
@@ -52,7 +52,43 @@
/** The max index for v6 address to test for valid scope ids. */
#define MAX_INTERFACE_TEST_INDEX 255
+/** The max interface name lenght is 20 */
+#define MAX_IFACE_LEN 20
+/** Custom designed wrapper for inet_pton to allow <ip>%<iface> format
+ *
+ *
+ * @param[in] af - A integer representing address family
+ * @param[in] src - A pointer to source address
+ * @param[out] dst - A pointer to structure in_addr6
+ *
+ * @return As per the lib call inet_pton()
+ * @internal
+ */
+static int SLP_inet_pton(int af, char *src, void *dst)
+{
+ char *src_ptr = src;
+ char tmp_addr[40];
+ int i = 0;
+
+ memset(&tmp_addr, 0, sizeof(tmp_addr));
+
+ if(af == AF_INET6) {
+ while(i != strlen(src)) {
+ if(*src_ptr != '%')
+ tmp_addr[i] = *src_ptr;
+ else
+ break;
+ i++;
+ src_ptr++;
+ }
+ return inet_pton(af, (char *)&tmp_addr, dst);
+ } else {
+
+ return inet_pton(af, src, dst);
+ }
+}
+
/** Checks a string-list for the occurence of a string
*
* @param[in] list - A pointer to the string-list to be checked.
@@ -72,7 +108,7 @@
char * itembegin = (char *) list;
char * itemend = itembegin;
struct sockaddr_storage addr;
- char buffer[INET6_ADDRSTRLEN]; /* must be at least 40 characters */
+ char buffer[INET6_ADDRSTRLEN + MAX_IFACE_LEN]; /* must be at least 40 characters for address string and 20 for inetrface name */
int buffer_len;
while (itemend < listend)
@@ -93,13 +129,13 @@
buffer_len = sizeof(buffer);
strncpy(buffer, itembegin, buffer_len);
buffer[itemend - itembegin] = '\0';
- if (SLPNetIsIPV6() && inet_pton(AF_INET6, buffer, &addr) == 1)
+ if (SLPNetIsIPV6() && SLP_inet_pton(AF_INET6, buffer, &addr) == 1)
{
inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
if (SLPCompareString(strlen(buffer), buffer, stringlen, string) == 0)
return 1;
}
- else if (SLPNetIsIPV4() && inet_pton(AF_INET, buffer, &addr) == 1)
+ else if (SLPNetIsIPV4() && SLP_inet_pton(AF_INET, buffer, &addr) == 1)
{
inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));
if (SLPCompareString(strlen(buffer), buffer, stringlen, string) == 0)
@@ -125,15 +161,52 @@
{
sockfd_t fd;
int result = -1;
+#if defined(LINUX)
+ struct ifaddrs *ifa, *ifaddr;
+ struct sockaddr_in6 *paddr;
+
+ if (getifaddrs(&ifa)) {
+ return result;
+ }
+ ifaddr = ifa;
+
+ if(!iface) {
+ for (; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ paddr = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if(!memcmp(&paddr->sin6_addr, &addr->sin6_addr, sizeof(struct in6_addr))) {
+ addr->sin6_scope_id = ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id;
+ result = 0;
+ break;
+ }
+ }
+ freeifaddrs(ifaddr);
+ return result;
+ }
+
+ for (; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ paddr = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if((!strncmp(iface, ifa->ifa_name, strlen(iface))) && (!memcmp(&paddr->sin6_addr, &addr->sin6_addr, sizeof(struct in6_addr)))) {
+ addr->sin6_scope_id = ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id;
+ result = 0;
+ break;
+ }
+ }
+ freeifaddrs(ifaddr);
+#else
+ /*Windows code need to be rewritten here*/
/* try and bind to verify the address is okay */
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (fd != SLP_INVALID_SOCKET)
{
- /* This loop attempts to find the proper scope value
- in case the tested address is an ipv6 link-local
+ /* This loop attempts to find the proper scope value
+ in case the tested address is an ipv6 link-local
address. In case of a global address a scope value
- of zero will bind immediately so the loop causes
+ of zero will bind immediately so the loop causes
no harm for global addresses. */
int i;
@@ -145,18 +218,12 @@
}
closesocket(fd);
}
-
+#endif
return result;
}
#if defined(LINUX)
-/* While Linux supports SIOCGIFCONF for getting IPv4 addresses, it does not support
- * that ioctl for getting IPv6 addresses. RTNetLink could be used to get this info
- * for both IPv4 and IPv6, and we may move to that later. Linux also has the IPv6
- * interface info readable from /proc/if_inet6, and this solution uses that route
- */
-
-/** Parses /proc/if_inet6 to get the IPv6 address information of a linux host
+/** Fetches the interface IPv6 address information of a linux host
*
* @param[in,out] ifaceinfo - The address of a buffer in which to return
* information about the requested interfaces. Note that the address
@@ -173,42 +240,36 @@
*/
static int SLPIfaceParseProc(SLPIfaceInfo * ifaceinfo)
{
- FILE* f;
- char buf[256];
- char ifstr[40];
- struct sockaddr_in6* paddr;
-
- if((f = fopen("/proc/net/if_inet6", "r")) == 0)
- return -1;
-
- while(fgets(buf, 256, f))
+ struct sockaddr_in6* paddr, *ifaddr;
+ struct ifaddrs *ifa;
+
+ if (getifaddrs(&ifa)) {
+ return -1;
+ }
+
+
+ for (; ifa; ifa = ifa->ifa_next)
{
+ if(ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ if(strstr("lo", ifa->ifa_name) != 0)
+ continue;
+
paddr = (struct sockaddr_in6*)&ifaceinfo->iface_addr[ifaceinfo->iface_count];
memset(paddr, 0, sizeof(struct sockaddr_in6));
-
- if(18 != sscanf(buf, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x %d %*d %*d %*d %s",
- (unsigned *)&paddr->sin6_addr.s6_addr[0], (unsigned *)&paddr->sin6_addr.s6_addr[1],
- (unsigned *)&paddr->sin6_addr.s6_addr[2], (unsigned *)&paddr->sin6_addr.s6_addr[3],
- (unsigned *)&paddr->sin6_addr.s6_addr[4], (unsigned *)&paddr->sin6_addr.s6_addr[5],
- (unsigned *)&paddr->sin6_addr.s6_addr[6], (unsigned *)&paddr->sin6_addr.s6_addr[7],
- (unsigned *)&paddr->sin6_addr.s6_addr[8], (unsigned *)&paddr->sin6_addr.s6_addr[9],
- (unsigned *)&paddr->sin6_addr.s6_addr[10], (unsigned *)&paddr->sin6_addr.s6_addr[11],
- (unsigned *)&paddr->sin6_addr.s6_addr[12], (unsigned *)&paddr->sin6_addr.s6_addr[13],
- (unsigned *)&paddr->sin6_addr.s6_addr[14], (unsigned *)&paddr->sin6_addr.s6_addr[15],
- &paddr->sin6_scope_id, ifstr))
- continue;
-
- if(strstr("lo", ifstr) != 0)
- continue; //Ignore loopback
-
+ ifaddr = (struct sockaddr_in6 *)ifa->ifa_addr;
+
+ memcpy(&paddr->sin6_addr, &ifaddr->sin6_addr, sizeof(struct in6_addr));
+ paddr->sin6_scope_id = ifaddr->sin6_scope_id;
+
paddr->sin6_family = AF_INET6;
#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
paddr->sin6_len = sizeof(struct sockaddr_in6);
#endif
++ifaceinfo->iface_count;
}
-
- fclose(f);
+ freeifaddrs(ifa);
return 0;
}
@@ -304,7 +365,7 @@
memcpy(&ifrflags, ifr, sizeof(struct ifreq));
if (ioctl(fd, SIOCGIFFLAGS, &ifrflags) == 0
&& (ifrflags.ifr_flags & IFF_LOOPBACK) == 0
- && (GetV6Scope((struct sockaddr_in6*)sa) == 0))
+ && (GetV6Scope((struct sockaddr_in6*)sa, NULL) == 0))
memcpy(&ifaceinfo->iface_addr[ifaceinfo->iface_count++],
sa, sizeof(struct sockaddr_in6));
}
@@ -409,7 +470,7 @@
plist = (SOCKET_ADDRESS_LIST*)buffer;
for (i = 0; i < plist->iAddressCount; ++i)
if ((plist->Address[i].lpSockaddr->sa_family == AF_INET6) &&
- (0 == GetV6Scope((struct sockaddr_in6*)plist->Address[i].lpSockaddr)) &&
+ (0 == GetV6Scope((struct sockaddr_in6*)plist->Address[i].lpSockaddr, NULL)) &&
/*Ignore Teredo and loopback pseudo-interfaces*/
(2 < ((struct sockaddr_in6*)plist->Address[i].lpSockaddr)->sin6_scope_id))
memcpy(&ifaceinfo->iface_addr[ifaceinfo->iface_count++],
@@ -485,6 +546,37 @@
#endif
+/** Extract the interface name from ip for the format
+ * <ip address>%<inetface>
+ *
+ * @param[in] ip - Ip address with interface name format
+ * @param[in,out] iface - Pointer to store the extracted interface info
+ *
+ * @return Zero on success; -1 on failure
+ */
+static int SLPD_Get_Iface_From_Ip(char *ip, char *iface) {
+
+ char *ip_ptr = ip;
+ int i = 0, ret = -1;
+
+ if(iface == NULL)
+ return ret;
+
+ while(i != strlen(ip)) {
+ if(*ip_ptr != '%') {
+ ip_ptr++;
+ i++;
+ continue;
+ } else {
+ ip_ptr++;
+ memcpy(iface, ip_ptr, strlen(ip_ptr));
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
/** Get the network interface addresses for this host.
*
* Returns either a complete list or a subset of the list of network interface
@@ -542,15 +634,20 @@
slider2++;
*slider2 = 0;
+ memset(&interface, 0, sizeof(interface));
+ ret = SLPD_Get_Iface_From_Ip(slider1, (char *)&interface);
+
if (SLPIfaceContainsAddr(useifaceslen, useifaces,
strlen(slider1), slider1))
{
sockfd_t fd;
struct sockaddr_in v4addr;
struct sockaddr_in6 v6addr;
+ char interface[MAX_IFACE_LEN];
+ int ret = 0;
/* check if an ipv4 address was given */
- if (inet_pton(AF_INET, slider1, &v4addr.sin_addr) == 1)
+ if (SLP_inet_pton(AF_INET, slider1, &v4addr.sin_addr) == 1)
{
if (SLPNetIsIPV4() && ((family == AF_INET) || (family == AF_UNSPEC)))
{
@@ -567,16 +664,23 @@
}
}
}
- else if (inet_pton(AF_INET6, slider1, &v6addr.sin6_addr) == 1)
+ else if (SLP_inet_pton(AF_INET6, slider1, &v6addr.sin6_addr) == 1)
{
if (SLPNetIsIPV6() && ((family == AF_INET6) || (family == AF_UNSPEC)))
{
v6addr.sin6_family = AF_INET6;
v6addr.sin6_port = 0;
v6addr.sin6_flowinfo = 0;
- if((sts = GetV6Scope(&v6addr)) == 0)
- memcpy(&ifaceinfo->iface_addr[ifaceinfo->iface_count++],
- &v6addr, sizeof(v6addr));
+ if(!ret) {
+ if((sts = GetV6Scope(&v6addr, interface)) == 0)
+ memcpy(&ifaceinfo->iface_addr[ifaceinfo->iface_count++],
+ &v6addr, sizeof(v6addr));
+ } else {
+ if((sts = GetV6Scope(&v6addr, NULL)) == 0)
+ memcpy(&ifaceinfo->iface_addr[ifaceinfo->iface_count++],
+ &v6addr, sizeof(v6addr));
+ }
+
}
}
else
@@ -616,6 +720,42 @@
return sts;
}
+/** Extract Interface Name from scope id.
+ *
+ * @param[in] scope_id - The scope id of interface
+ * @param[in,out] iface - The interface name got from scope id
+ *
+ * @return Zero on success, -1 on error.
+ */
+static int SLPGetIfaceNameFromScopeId(int scope_id, char *iface)
+{
+#ifdef LINUX
+ struct ifaddrs *ifa, *ifaddr;
+
+ if(!scope_id)
+ return -1;
+
+ if (getifaddrs(&ifa)) {
+ return -1;
+ }
+ ifaddr = ifa;
+ for (; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if(((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == scope_id) {
+ memcpy(iface, ifa->ifa_name, strlen(ifa->ifa_name));
+ freeifaddrs(ifaddr);
+ return 0;
+ }
+ }
+ freeifaddrs(ifaddr);
+ return -1;
+#else
+ /*Windows/AIX code has to put here*/
+ return -1;
+#endif
+}
+
/** Convert an array of sockaddr_storage buffers to a comma-delimited list.
*
* Converts an array of sockaddr_storage buffers to a comma-delimited list of
@@ -634,15 +774,18 @@
int addrcount, char ** addrstr)
{
int i;
+ struct sockaddr *addr;
+ struct sockaddr_in6 *addr6;
SLP_ASSERT(addrs && addrcount && addrstr);
if (!addrs || !addrcount || !addrstr)
return (errno = EINVAL), -1;
/* 40 is the maximum size of a string representation of
- * an IPv6 address (including the comma for the list)
+ * an IPv6 address (including the comma for the list)
+ * 20 is MAX size of interface name
*/
- if ((*addrstr = xmalloc(addrcount * 40)) == 0)
+ if ((*addrstr = xmalloc(addrcount * (40 + MAX_IFACE_LEN))) == 0)
return (errno = ENOMEM), -1;
**addrstr = 0;
@@ -650,10 +793,22 @@
for (i = 0; i < addrcount; i++)
{
char buf[1024] = "";
+ char iface[16] = "";
SLPNetSockAddrStorageToString(&addrs[i], buf, sizeof(buf));
-
- strcat(*addrstr, buf);
+ addr = (struct sockaddr *)&addrs[i];
+ if (addr->sa_family == AF_INET6) {
+ addr6 = (struct sockaddr_in6 *)addr;
+ if (!SLPGetIfaceNameFromScopeId(addr6->sin6_scope_id, (char *)&iface)) {
+ strcat(*addrstr, buf);
+ strcat(*addrstr, "%");
+ strcat(*addrstr, iface);
+ } else {
+ strcat(*addrstr, buf);
+ }
+ } else {
+ strcat(*addrstr, buf);
+ }
if (i != addrcount - 1)
strcat(*addrstr, ",");
}
Index: etc/slp.conf
===================================================================
--- etc/slp.conf (revision 1632)
+++ etc/slp.conf (working copy)
@@ -152,6 +152,11 @@
# used must be specified. Both IPv4 and IPv6 addresses may be specified.
# Only link-local addresses can be used for IPv6 SLP multicast. Any
# site-local or global addresses will be used, but only for unicast SLP.
+# Option parameter "%" can be used to specify the interface when multiple
+# instance of the same link-local address are present in the same host. If
+# the interface option is not provided, the daemon will bind to the first
+# interface with specified ip. This option is only valid for IPv6 link-local
+# addresses. Eg: fe80::215:58ff:fe7e:c037%eth0
;net.slp.interfaces = 192.168.0.1
# This option is a string indicating the broadcast address to use when
------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://ad.doubleclick.net/clk;226879339;13503038;l?
http://clk.atdmt.com/CRS/go/247765532/direct/01/
_______________________________________________
Openslp-devel mailing list
Openslp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openslp-devel