#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "eeze_udev_private.h" #include "eeze_net_private.h" static Eina_Hash *eeze_nets = NULL; Eina_Bool eeze_net_init(void) { eeze_nets = eina_hash_string_superfast_new(NULL); return !!eeze_nets; } void eeze_net_shutdown(void) { eina_hash_free(eeze_nets); eeze_nets = NULL; } /** * @addtogroup Eeze_Net Net * @ingroup Eeze * @{ */ /** * @brief Create a new net object * @param name The name of the underlying device (eth0, br1, etc) * @return A newly allocated net object, or NULL on failure * * This function creates a new net object based on @p name. * Only the most minimal lookups are performed at creation in order * to save memory. */ Eeze_Net * eeze_net_new(const char *name) { const char *syspath = NULL; const char *idx; _udev_enumerate *en; _udev_list_entry *devs, *cur; _udev_device *device = NULL; Eeze_Net *net; net = eina_hash_find(eeze_nets, name); if (net) { EINA_REFCOUNT_REF(net); return net; } en = udev_enumerate_new(udev); udev_enumerate_add_match_sysname(en, name); udev_enumerate_add_match_subsystem(en, "net"); udev_enumerate_scan_devices(en); devs = udev_enumerate_get_list_entry(en); udev_list_entry_foreach(cur, devs) { const char *devname, *test; devname = udev_list_entry_get_name(cur); test = strrchr(devname, '/'); if (!test) break; if (strcmp(++test, name)) continue; device = _new_device(devname); syspath = eina_stringshare_add(name); break; } if (!device) { udev_enumerate_unref(en); return NULL; } net = calloc(1, sizeof(Eeze_Net)); if (!net) { udev_enumerate_unref(en); udev_device_unref(device); return NULL; } EINA_REFCOUNT_INIT(net); net->device = device; net->syspath = syspath; net->name = eina_stringshare_add(name); idx = udev_device_get_sysattr_value(net->device, "ifindex"); if (!idx) { udev_enumerate_unref(en); udev_device_unref(net->device); eina_stringshare_del(net->syspath); eina_stringshare_del(net->name); free(net); return NULL; } net->index = atoi(idx); eina_hash_add(eeze_nets, name, net); udev_enumerate_unref(en); return net; } /** * @brief Free a net object * @param net The object to free * * Use this function to free a net object. * @see eeze_net_new() * @see eeze_net_list() */ void eeze_net_free(Eeze_Net *net) { EINA_SAFETY_ON_NULL_RETURN(net); EINA_REFCOUNT_UNREF(net) { eina_hash_del_by_key(eeze_nets, net->name); udev_device_unref(net->device); eina_stringshare_del(net->syspath); eina_stringshare_del(net->name); eina_stringshare_del(net->ip); eina_stringshare_del(net->broadip); eina_stringshare_del(net->netmask); #ifdef HAVE_IPV6 eina_stringshare_del(net->ip6); eina_stringshare_del(net->broadip6); eina_stringshare_del(net->netmask6); #endif free(net); } } /** * @brief Get the MAC address of a net object * @param net The net object * @return The MAC address, NULL on failure * Use this function to retrieve the non-stringshared MAC address of @p net. */ const char * eeze_net_mac_get(Eeze_Net *net) { EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL); return udev_device_get_sysattr_value(net->device, "address"); } /** * @brief Get the index of a net object * @param net The net object * @return The ifindex of the object, -1 on failure * Use this function to get the hardware index of @p net */ int eeze_net_idx_get(Eeze_Net *net) { EINA_SAFETY_ON_NULL_RETURN_VAL(net, -1); return net->index; } /** * @brief Scan an interface to cache its network addresses * @param net The net object to scan * @return EINA_TRUE on success, EINA_FALSE on failure * Use this function to scan and cache the ip address, netmask, and broadcast * address for an interface. This function will perform a full scan every time * it is called, and IPv6 addresses will be cached if Eeze was compiled with IPv6 * support was enabled at compile time. * @see eeze_net_addr_get() */ Eina_Bool eeze_net_scan(Eeze_Net *net) { char ip[INET_ADDRSTRLEN]; #ifdef HAVE_IPV6 char ip6[INET6_ADDRSTRLEN]; struct sockaddr_in6 *sa6; #endif int sock; int ioctls[3] = {SIOCGIFADDR, SIOCGIFBRDADDR, SIOCGIFNETMASK}, *i = ioctls; struct ifreq ifr; struct sockaddr_in *sa; EINA_SAFETY_ON_NULL_RETURN_VAL(net, EINA_FALSE); /* ensure that we have the right name, mostly for hahas */ if_indextoname((unsigned int)net->index, ifr.ifr_name); ifr.ifr_addr.sa_family = AF_INET; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) return EINA_FALSE; if (ioctl(sock, *i++, &ifr) < 0) goto error; sa = (struct sockaddr_in*) & (ifr.ifr_addr); inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN); eina_stringshare_replace_length(&net->ip, ip, INET_ADDRSTRLEN); if (ioctl(sock, *i++, &ifr) < 0) goto error; sa = (struct sockaddr_in*) & (ifr.ifr_broadaddr); inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN); eina_stringshare_replace_length(&net->broadip, ip, INET_ADDRSTRLEN); if (ioctl(sock, *i++, &ifr) < 0) goto error; sa = (struct sockaddr_in*) & (ifr.ifr_addr); inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN); eina_stringshare_replace_length(&net->netmask, ip, INET_ADDRSTRLEN); close(sock); #ifdef HAVE_IPV6 i = ioctls; ifr.ifr_addr.sa_family = AF_INET6; sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) return EINA_FALSE; if (ioctl(sock, *i++, &ifr) < 0) goto error; sa6 = (struct sockaddr_in6*) & (ifr.ifr_addr); inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN); eina_stringshare_replace_length(&net->ip6, ip6, INET6_ADDRSTRLEN); if (ioctl(sock, *i++, &ifr) < 0) goto error; sa6 = (struct sockaddr_in6*) & (ifr.ifr_broadaddr); inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN); eina_stringshare_replace_length(&net->broadip6, ip6, INET6_ADDRSTRLEN); if (ioctl(sock, *i++, &ifr) < 0) goto error; sa6 = (struct sockaddr_in6*) & (ifr.ifr_addr); inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN); eina_stringshare_replace_length(&net->netmask6, ip6, INET6_ADDRSTRLEN); close(sock); #endif return EINA_TRUE; error: close(sock); return EINA_FALSE; } /** * @brief Get the address of a net object * @param net The net object * @param type The type of address to retrieve * @return The stringshared address for @p net corresponding to @p type, NULL on failure * This function returns a value previously cached. * @see eeze_net_scan() */ const char * eeze_net_addr_get(Eeze_Net *net, Eeze_Net_Addr_Type type) { EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL); switch (type) { case EEZE_NET_ADDR_TYPE_IP6: #ifdef HAVE_IPV6 return net->ip6; #else return NULL; #endif case EEZE_NET_ADDR_TYPE_BROADCAST: return net->broadip; case EEZE_NET_ADDR_TYPE_BROADCAST6: #ifdef HAVE_IPV6 return net->broadip6; #else return NULL; #endif case EEZE_NET_ADDR_TYPE_NETMASK: return net->netmask; case EEZE_NET_ADDR_TYPE_NETMASK6: #ifdef HAVE_IPV6 return net->netmask6; #else return NULL; #endif default: break; } return net->ip; } /** * @brief Get a system attribute of a net object * @param net The net object * @param attr The attribute to retrieve * @return The non-stringshared value of the attribute, NULL on failure * Use this function to perform a udev sysattr lookup on the underlying device of @p net */ const char * eeze_net_attribute_get(Eeze_Net *net, const char *attr) { EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL); EINA_SAFETY_ON_TRUE_RETURN_VAL(!attr[0], NULL); return udev_device_get_sysattr_value(net->device, attr); } /** * @brief Get the /sys/ path of a net object * @param net The net object * @return The stringshared /sys/ path of the interface, NULL on failure */ const char * eeze_net_syspath_get(Eeze_Net *net) { EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL); return net->syspath; } /** * @brief Get a list of all the network interfaces available * @return A list of Eeze_Net objects * Use this function to get all network interfaces available to the application. * This list must be freed by the user. */ Eina_List * eeze_net_list(void) { struct if_nameindex *ifs, *i; Eina_List *ret = NULL; Eeze_Net *net; ifs = if_nameindex(); for (i = ifs; i && i->if_name && i->if_name[0]; i++) { net = eeze_net_new(i->if_name); if (net) ret = eina_list_append(ret, net); } if_freenameindex(ifs); return ret; } /** @} */