static NetworkAddress * getCachedAddress(NetworkAddress * matchAddress, const char * uri, int uriLength)
{
    NetworkAddress * result = NULL;
    int index;
    for (index = 0; index < MAX_NETWORK_ADDRESS_CACHE; index++)
    {
        NetworkAddress * address = networkAddressCache[index].address;
        if (address)
        {
            if (NetworkAddress_Compare(matchAddress, address) == 0)
            {
                if (uri && uriLength > 0 && networkAddressCache[index].uri == NULL)
                {
                    // Add info to cached address
                    address->Secure = matchAddress->Secure;
                    networkAddressCache[index].uri = (char *)malloc(uriLength + 1);
                    if (networkAddressCache[index].uri)
                    {
                        memcpy(networkAddressCache[index].uri, uri, uriLength);
                        networkAddressCache[index].uri[uriLength] = 0;
                        Lwm2m_Debug("Address add uri: %s\n", networkAddressCache[index].uri);
                    }
                }
                result = address;
                break;
            }
        }
    }
    return result;
}
void coap_handle_notification(NetworkAddress * sourceAddress, coap_packet_t * message)
{
    if (message->token_len == sizeof(int))
    {
        int token;
        memcpy(&token, message->token, sizeof(int));
        Observation * observation = NULL;
        int index;
        for (index = 0; index < MAX_COAP_OBSERVATIONS; index++)
        {
            if ((Observations[index].Token == token) && (NetworkAddress_Compare(Observations[index].Address, sourceAddress) == 0))
            {
                observation = &Observations[index];
                break;
            }
        }
        if (observation && observation->Callback)
        {
            AddressType address;
            int ContentType = 0;
            char * payload = NULL;

            NetworkAddress_SetAddressType(sourceAddress, &address);
            coap_get_header_content_format(message, &ContentType);
            int payloadLen = coap_get_payload(message, (const uint8_t **) &payload);

            observation->Callback(observation->Context, &address, observation->Path, COAP_OPTION_TO_RESPONSE_CODE(message->code),
                    ContentType, payload, payloadLen);
        }
    }

}
void NetworkAddress_Free(NetworkAddress ** address)
{
    // TODO - review when addresses are freed (e.g. after client bootstrap, or connection lost ?)
    if (address && *address)
    {
        (*address)->useCount--;
        if ((*address)->useCount == 0)
        {
            int index;
            for (index = 0; index < MAX_NETWORK_ADDRESS_CACHE; index++)
            {
                if (NetworkAddress_Compare(&networkAddressCache[index].Address, *address) == 0)
                {
                    if (networkAddressCache[index].Uri)
                    {
                        Lwm2m_Debug("Address free: %s\n", networkAddressCache[index].Uri);
                        networkAddressCache[index].Uri[0] = '\0';
                    }
                    else
                    {
                        Lwm2m_Debug("Address free\n");
                    }
                    networkAddressCache[index].InUse = false;
                    break;
                }
            }
        }
        *address = NULL;
    }
}
static DTLS_Session * GetSession(NetworkAddress * address)
{
    DTLS_Session * result = NULL;
    int index;
    for (index = 0;index < MAX_DTLS_SESSIONS; index++)
    {
        if (NetworkAddress_Compare(sessions[index].NetworkAddress,address) == 0)
        {
            result = &sessions[index];
            break;
        }
    }
    return result;
}
static int removeObserve(NetworkAddress * remoteAddress, char * path)
{
    int result = 0;
    int index;
    for (index = 0; index < MAX_COAP_OBSERVATIONS; index++)
    {
        if ((NetworkAddress_Compare(Observations[index].Address, sourceAddress) == 0) && (strcmp(Observations[index].Path,path) == 0))
        {
            result = Observations[index].Token;
            memset(&Observations[index],0, sizeof(Observation));
            break;
        }
    }
    return result;
}
static NetworkAddress * getCachedAddress(const uip_ipaddr_t * addr, uint16_t port)
{
    NetworkAddress * result = NULL;
    NetworkAddress matchAddress;
    int index;

    memcpy(&matchAddress.Address, addr, sizeof(uip_ipaddr_t));
    matchAddress.Port = port;

    for (index = 0; index < MAX_NETWORK_ADDRESS_CACHE; index++)
    {
        NetworkAddress * address = &networkAddressCache[index].Address;
        if (address)
        {
            if (NetworkAddress_Compare(&matchAddress, address) == 0)
            {
                result = address;
                break;
            }
        }
    }
    return result;
}