network_information.c [plain text]
#include <pthread.h>
#include <notify.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include "network_information.h"
#include "network_information_priv.h"
static nwi_state_t G_nwi_state = NULL;
static pthread_mutex_t nwi_store_lock = PTHREAD_MUTEX_INITIALIZER;
static boolean_t nwi_store_token_valid = FALSE;
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static int nwi_store_token;
static
void
_nwi_state_initialize(void)
{
const char *nwi_key = nwi_state_get_notify_key();
uint32_t status = notify_register_check(nwi_key,
&nwi_store_token);
if (status != NOTIFY_STATUS_OK) {
fprintf(stderr, "nwi_state: registration failed (%u)\n", status);
}
else {
nwi_store_token_valid = TRUE;
}
}
static
void
nwi_set_alias(nwi_state* state, nwi_ifstate* ifstate)
{
nwi_ifstate* ifstate_alias;
int af = ifstate->af;
int af_alias;
af_alias = (af == AF_INET)?AF_INET6:AF_INET;
ifstate_alias =
nwi_state_get_ifstate_with_name(state, af_alias,
ifstate->ifname);
if (ifstate_alias != NULL) {
ifstate_alias->af_alias = ifstate;
}
ifstate->af_alias = ifstate_alias;
return;
}
static
void
_nwi_state_reset_alias(nwi_state_t state) {
int i;
for (i = 0; i < state->ipv4_count; i++) {
state->nwi_ifstates[i].af_alias = NULL;
}
for (i = state->ipv6_start;
i < state->ipv6_start + state->ipv6_count; i++) {
nwi_set_alias(state, &state->nwi_ifstates[i]);
}
}
const char *
nwi_state_get_notify_key()
{
return "com.apple.system.SystemConfiguration.nwi";
}
#define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++);
#define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n);
static void
nwi_state_retain(nwi_state_t state)
{
ATOMIC_INC(&state->ref);
return;
}
void
nwi_state_release(nwi_state_t state)
{
if (ATOMIC_DEC(&state->ref) == 0) {
free(state);
}
return;
}
nwi_state_t
nwi_state_copy(void)
{
nwi_state_t nwi_state = NULL;
nwi_state_t old_state = NULL;
pthread_once(&initialized, _nwi_state_initialize);
pthread_mutex_lock(&nwi_store_lock);
if (G_nwi_state != NULL) {
int check = 0;
uint32_t status;
if (nwi_store_token_valid == FALSE) {
check = 1;
}
else {
status = notify_check(nwi_store_token, &check);
if (status != NOTIFY_STATUS_OK) {
fprintf(stderr, "nwi notify_check: failed with %u\n",
status);
check = 1;
}
}
if (check != 0) {
old_state = G_nwi_state;
G_nwi_state = NULL;
}
}
if (G_nwi_state == NULL) {
G_nwi_state = _nwi_state_copy();
if (G_nwi_state != NULL) {
nwi_state_retain(G_nwi_state);
_nwi_state_reset_alias(G_nwi_state);
}
}
if (G_nwi_state != NULL) {
nwi_state_retain(G_nwi_state);
}
nwi_state = G_nwi_state;
pthread_mutex_unlock(&nwi_store_lock);
if (old_state != NULL) {
nwi_state_release(old_state);
}
return nwi_state;
}
void
_nwi_state_ack(nwi_state_t state, const char *bundle_id)
{
return;
}
uint64_t
nwi_state_get_generation(nwi_state_t state)
{
return (state->generation_count);
}
const char *
nwi_ifstate_get_ifname(nwi_ifstate_t ifstate)
{
return (ifstate != NULL?ifstate->ifname:NULL);
}
static uint64_t
flags_from_af(int af)
{
return ((af == AF_INET)
? NWI_IFSTATE_FLAGS_HAS_IPV4
: NWI_IFSTATE_FLAGS_HAS_IPV6);
}
nwi_ifstate_flags
nwi_ifstate_get_flags(nwi_ifstate_t ifstate)
{
nwi_ifstate_t alias = ifstate->af_alias;
nwi_ifstate_flags flags = 0ULL;
flags |= flags_from_af(ifstate->af);
if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) {
flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
}
if (alias != NULL) {
flags |= flags_from_af(alias->af);
if ((alias->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) {
flags |= NWI_IFSTATE_FLAGS_HAS_DNS;
}
}
return flags;
}
nwi_ifstate_t
nwi_state_get_first_ifstate(nwi_state_t state, int af)
{
nwi_ifstate_t ifstate;
if (state == NULL) {
return NULL;
}
ifstate =
nwi_state_get_ifstate_with_index(state, af, 0);
if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST)
!= 0) {
ifstate = NULL;
}
return ifstate;
}
nwi_ifstate_t
nwi_state_get_ifstate(nwi_state_t state, const char * ifname)
{
nwi_ifstate_t ifstate = nwi_state_get_ifstate_with_name(state, AF_INET, ifname);
if (ifstate == NULL) {
ifstate = nwi_state_get_ifstate_with_name(state, AF_INET6, ifname);
}
return ifstate;
}
nwi_ifstate_t
nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af)
{
nwi_ifstate_t alias, next;
alias =
(af == ifstate->af)?ifstate:ifstate->af_alias;
if (alias == NULL) {
return NULL;
}
if ((alias->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) {
return NULL;
}
next = ++alias;
if ((next->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) == 0) {
return next;
}
return NULL;
}
int
nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2)
{
return RankCompare(ifstate1->rank, ifstate2->rank);
}