<commit_before>/* nsapi_dns.cpp
 * Original work Copyright (c) 2013 <NAME> (henry[dot]leinen [at] online [dot] de)
 * Modified work Copyright (c) 2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* Declare __STDC_LIMIT_MACROS so stdint.h defines INT32_MAX when using C++ */
#define __STDC_LIMIT_MACROS

#include "nsapi_dns.h"
#include "netsocket/UDPSocket.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mbed_shared_queues.h"
#include "events/EventQueue.h"
#include "OnboardNetworkStack.h"
#include "Kernel.h"
#include "PlatformMutex.h"
#include "SingletonPtr.h"

#define CLASS_IN 1

#define RR_A 1
#define RR_AAAA 28

// DNS options
#define DNS_BUFFER_SIZE 512
#define DNS_SERVERS_SIZE 5
#define DNS_RESPONSE_MIN_SIZE 12
#define DNS_STACK_SERVERS_NUM 5
#define DNS_QUERY_QUEUE_SIZE 5
#define DNS_HOST_NAME_MAX_LEN 255
#define DNS_TIMER_TIMEOUT 100

struct DNS_CACHE {
    nsapi_addr_t address;
    char *host;
    uint64_t expires;      /*!< time to live in milliseconds */
    uint64_t accessed;     /*!< last accessed */
};

struct SOCKET_CB_DATA {
    call_in_callback_cb_t call_in_cb;
    NetworkStack *stack;
};

enum dns_state {
    DNS_CREATED,           /*!< created, not yet making query to network */
    DNS_INITIATED,         /*!< making query to network */
    DNS_CANCELLED          /*!< cancelled, callback will not be called */
};

struct DNS_QUERY {
    int unique_id;
    nsapi_error_t status;
    NetworkStack *stack;
    char *host;
    const char *interface_name;
    NetworkStack::hostbyname_cb_t callback;
    call_in_callback_cb_t call_in_cb;
    nsapi_size_t addr_count;
    nsapi_version_t version;
    UDPSocket *socket;
    SOCKET_CB_DATA *socket_cb_data;
    nsapi_addr_t *addrs;
    uint32_t ttl;
    uint32_t total_timeout;
    uint32_t socket_timeout;
    uint16_t dns_message_id;
    uint8_t dns_server;
    uint8_t retries;
    uint8_t total_attempts;
    uint8_t send_success;
    uint8_t count;
    dns_state state;
};

static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);

static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr, const char *interface_name);

static void nsapi_dns_query_async_create(void *ptr);
static nsapi_error_t nsapi_dns_query_async_delete(int unique_id);
static void nsapi_dns_query_async_send(void *ptr);
static void nsapi_dns_query_async_timeout(void);
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address);
static void nsapi_dns_query_async_socket_callback(void *ptr);
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack);
static void nsapi_dns_query_async_response(void *ptr);
static void nsapi_dns_query_async_initiate_next(void);

// *INDENT-OFF*
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
    {NSAPI_IPv4, {8, 8, 8, 8}},                             // Google
    {NSAPI_IPv6, {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0,     // Google
                  0,0, 0,0, 0,0, 0x88,0x88}},
    {NSAPI_IPv4, {209, 244, 0, 3}},                         // Level 3
    {NSAPI_IPv4, {84, 200, 69, 80}},                        // DNS.WATCH
    {NSAPI_IPv6, {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25,     // DNS.WATCH
                  0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}},
};
// *INDENT-ON*

#if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE];
// Protects cache shared between blocking and asynchronous calls
static SingletonPtr<PlatformMutex> dns_cache_mutex;
#endif

static uint16_t dns_message_id = 1;
static int dns_unique_id = 1;
static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE];
// Protects from several threads running asynchronous DNS
static SingletonPtr<PlatformMutex> dns_mutex;
static SingletonPtr<call_in_callback_cb_t> dns_call_in;
static bool dns_timer_running = false;

// DNS server configuration
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name)
{
    memmove(&dns_servers[1], &dns_servers[0],
            (DNS_SERVERS_SIZE - 1)*sizeof(nsapi_addr_t));

    dns_servers[0] = addr;
    return NSAPI_ERROR_OK;
}


// DNS packet parsing
static void dns_append_byte(uint8_t **p, uint8_t byte)
{
    *(*p)++ = byte;
}

static void dns_append_word(uint8_t **p, uint16_t word)
{

    dns_append_byte(p, 0xff & (word >> 8));
    dns_append_byte(p, 0xff & (word >> 0));
}

static void dns_append_name(uint8_t **p, const char *name, uint8_t len)
{
    dns_append_byte(p, len);
    memcpy(*p, name, len);
    *p += len;
}<commit_msg>Fix nsapi_dns_add_server to add a server just once<commit_after>/* nsapi_dns.cpp
 * Original work Copyright (c) 2013 <NAME> (henry[dot]leinen [at] online [dot] de)
 * Modified work Copyright (c) 2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* Declare __STDC_LIMIT_MACROS so stdint.h defines INT32_MAX when using C++ */
#define __STDC_LIMIT_MACROS

#include "nsapi_dns.h"
#include "netsocket/UDPSocket.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mbed_shared_queues.h"
#include "events/EventQueue.h"
#include "OnboardNetworkStack.h"
#include "Kernel.h"
#include "PlatformMutex.h"
#include "SingletonPtr.h"

#define CLASS_IN 1

#define RR_A 1
#define RR_AAAA 28

// DNS options
#define DNS_BUFFER_SIZE 512
#define DNS_SERVERS_SIZE 5
#define DNS_RESPONSE_MIN_SIZE 12
#define DNS_STACK_SERVERS_NUM 5
#define DNS_QUERY_QUEUE_SIZE 5
#define DNS_HOST_NAME_MAX_LEN 255
#define DNS_TIMER_TIMEOUT 100

struct DNS_CACHE {
    nsapi_addr_t address;
    char *host;
    uint64_t expires;      /*!< time to live in milliseconds */
    uint64_t accessed;     /*!< last accessed */
};

struct SOCKET_CB_DATA {
    call_in_callback_cb_t call_in_cb;
    NetworkStack *stack;
};

enum dns_state {
    DNS_CREATED,           /*!< created, not yet making query to network */
    DNS_INITIATED,         /*!< making query to network */
    DNS_CANCELLED          /*!< cancelled, callback will not be called */
};

struct DNS_QUERY {
    int unique_id;
    nsapi_error_t status;
    NetworkStack *stack;
    char *host;
    const char *interface_name;
    NetworkStack::hostbyname_cb_t callback;
    call_in_callback_cb_t call_in_cb;
    nsapi_size_t addr_count;
    nsapi_version_t version;
    UDPSocket *socket;
    SOCKET_CB_DATA *socket_cb_data;
    nsapi_addr_t *addrs;
    uint32_t ttl;
    uint32_t total_timeout;
    uint32_t socket_timeout;
    uint16_t dns_message_id;
    uint8_t dns_server;
    uint8_t retries;
    uint8_t total_attempts;
    uint8_t send_success;
    uint8_t count;
    dns_state state;
};

static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);

static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr, const char *interface_name);

static void nsapi_dns_query_async_create(void *ptr);
static nsapi_error_t nsapi_dns_query_async_delete(int unique_id);
static void nsapi_dns_query_async_send(void *ptr);
static void nsapi_dns_query_async_timeout(void);
static void nsapi_dns_query_async_resp(DNS_QUERY *query, nsapi_error_t status, SocketAddress *address);
static void nsapi_dns_query_async_socket_callback(void *ptr);
static void nsapi_dns_query_async_socket_callback_handle(NetworkStack *stack);
static void nsapi_dns_query_async_response(void *ptr);
static void nsapi_dns_query_async_initiate_next(void);

// *INDENT-OFF*
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
    {NSAPI_IPv4, {8, 8, 8, 8}},                             // Google
    {NSAPI_IPv6, {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0,     // Google
                  0,0, 0,0, 0,0, 0x88,0x88}},
    {NSAPI_IPv4, {209, 244, 0, 3}},                         // Level 3
    {NSAPI_IPv4, {84, 200, 69, 80}},                        // DNS.WATCH
    {NSAPI_IPv6, {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25,     // DNS.WATCH
                  0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}},
};
// *INDENT-ON*

#if (MBED_CONF_NSAPI_DNS_CACHE_SIZE > 0)
static DNS_CACHE *dns_cache[MBED_CONF_NSAPI_DNS_CACHE_SIZE];
// Protects cache shared between blocking and asynchronous calls
static SingletonPtr<PlatformMutex> dns_cache_mutex;
#endif

static uint16_t dns_message_id = 1;
static int dns_unique_id = 1;
static DNS_QUERY *dns_query_queue[DNS_QUERY_QUEUE_SIZE];
// Protects from several threads running asynchronous DNS
static SingletonPtr<PlatformMutex> dns_mutex;
static SingletonPtr<call_in_callback_cb_t> dns_call_in;
static bool dns_timer_running = false;

// DNS server configuration
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name)
{
    // check if addr was already added
    for (int i = 0; i < DNS_SERVERS_SIZE; i++) {
        if (memcmp(&addr, &dns_servers[i], sizeof(nsapi_addr_t)) == 0) {
            return NSAPI_ERROR_OK;
        }
    }

    memmove(&dns_servers[1], &dns_servers[0],
            (DNS_SERVERS_SIZE - 1)*sizeof(nsapi_addr_t));

    dns_servers[0] = addr;
    return NSAPI_ERROR_OK;
}


// DNS packet parsing
static void dns_append_byte(uint8_t **p, uint8_t byte)
{
    *(*p)++ = byte;
}

static void dns_append_word(uint8_t **p, uint16_t word)
{

    dns_append_byte(p, 0xff & (word >> 8));
    dns_append_byte(p, 0xff & (word >> 0));
}

static void dns_append_name(uint8_t **p, const char *name, uint8_t len)
{
    dns_append_byte(p, len);
    memcpy(*p, name, len);
    *p += len;
}
{'fraction_non_alphanumeric': 0.0953660797034291, 'fraction_numerical': 0.030954587581093606, 'mean_word_length': 4.175539568345323, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1188466', 'n_tokens_mistral': 4204, 'n_tokens_neox': 3951, 'n_words': 979}