dns_recurring.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2015, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief DNS Recurring Query Support
00022  *
00023  * \author Joshua Colp <jcolp@digium.com>
00024  */
00025 
00026 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433370 $")
00033 
00034 #include "asterisk/astobj2.h"
00035 #include "asterisk/linkedlists.h"
00036 #include "asterisk/sched.h"
00037 #include "asterisk/strings.h"
00038 #include "asterisk/dns_core.h"
00039 #include "asterisk/dns_recurring.h"
00040 #include "asterisk/dns_internal.h"
00041 
00042 #include <arpa/nameser.h>
00043 
00044 /*! \brief Destructor for a DNS query */
00045 static void dns_query_recurring_destroy(void *data)
00046 {
00047    struct ast_dns_query_recurring *recurring = data;
00048 
00049    ao2_cleanup(recurring->user_data);
00050 }
00051 
00052 static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query);
00053 
00054 /*! \brief Scheduled recurring query callback */
00055 static int dns_query_recurring_scheduled_callback(const void *data)
00056 {
00057    struct ast_dns_query_recurring *recurring = (struct ast_dns_query_recurring *)data;
00058 
00059    ao2_lock(recurring);
00060    recurring->timer = -1;
00061    if (!recurring->cancelled) {
00062       recurring->active = ast_dns_resolve_async(recurring->name, recurring->rr_type, recurring->rr_class, dns_query_recurring_resolution_callback,
00063          recurring);
00064    }
00065    ao2_unlock(recurring);
00066 
00067    ao2_ref(recurring, -1);
00068 
00069    return 0;
00070 }
00071 
00072 /*! \brief Query resolution callback */
00073 static void dns_query_recurring_resolution_callback(const struct ast_dns_query *query)
00074 {
00075    struct ast_dns_query_recurring *recurring = ast_dns_query_get_data(query);
00076 
00077    /* Replace the user data so the actual callback sees what it provided */
00078    ((struct ast_dns_query*)query)->user_data = ao2_bump(recurring->user_data);
00079    recurring->callback(query);
00080 
00081    ao2_lock(recurring);
00082    /* So.. if something has not externally cancelled this we can reschedule based on the TTL */
00083    if (!recurring->cancelled) {
00084       const struct ast_dns_result *result = ast_dns_query_get_result(query);
00085       int ttl = MIN(ast_dns_result_get_lowest_ttl(result), INT_MAX / 1000);
00086 
00087       if (ttl) {
00088          recurring->timer = ast_sched_add(ast_dns_get_sched(), ttl * 1000, dns_query_recurring_scheduled_callback, ao2_bump(recurring));
00089          if (recurring->timer < 0) {
00090             /* It is impossible for this to be the last reference as this callback function holds a reference itself */
00091             ao2_ref(recurring, -1);
00092          }
00093       }
00094    }
00095 
00096    ao2_replace(recurring->active, NULL);
00097    ao2_unlock(recurring);
00098 
00099    /* Since we stole the reference from the query we need to drop it ourselves */
00100    ao2_ref(recurring, -1);
00101 }
00102 
00103 struct ast_dns_query_recurring *ast_dns_resolve_recurring(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
00104 {
00105    struct ast_dns_query_recurring *recurring;
00106 
00107    if (ast_strlen_zero(name) || !callback || !ast_dns_get_sched()) {
00108       return NULL;
00109    }
00110 
00111    recurring = ao2_alloc(sizeof(*recurring) + strlen(name) + 1, dns_query_recurring_destroy);
00112    if (!recurring) {
00113       return NULL;
00114    }
00115 
00116    recurring->callback = callback;
00117    recurring->user_data = ao2_bump(data);
00118    recurring->timer = -1;
00119    recurring->rr_type = rr_type;
00120    recurring->rr_class = rr_class;
00121    strcpy(recurring->name, name); /* SAFE */
00122 
00123    recurring->active = ast_dns_resolve_async(name, rr_type, rr_class, dns_query_recurring_resolution_callback, recurring);
00124    if (!recurring->active) {
00125       ao2_ref(recurring, -1);
00126       return NULL;
00127    }
00128 
00129    return recurring;
00130 }
00131 
00132 int ast_dns_resolve_recurring_cancel(struct ast_dns_query_recurring *recurring)
00133 {
00134    int res = 0;
00135 
00136    ao2_lock(recurring);
00137 
00138    recurring->cancelled = 1;
00139    AST_SCHED_DEL_UNREF(ast_dns_get_sched(), recurring->timer, ao2_ref(recurring, -1));
00140 
00141    if (recurring->active) {
00142       res = ast_dns_resolve_cancel(recurring->active);
00143       ao2_replace(recurring->active, NULL);
00144    }
00145 
00146    ao2_unlock(recurring);
00147 
00148    return res;
00149 }

Generated on Thu Apr 16 06:27:33 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6