Let ExtensionState resolve dynamic hints.
[asterisk/asterisk.git] / main / srv.c
index 898195d..c650650 100644 (file)
@@ -33,7 +33,6 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-#include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #ifdef __APPLE__
@@ -42,15 +41,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #endif
 #endif
 #include <resolv.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
 
 #include "asterisk/channel.h"
-#include "asterisk/logger.h"
 #include "asterisk/srv.h"
 #include "asterisk/dns.h"
-#include "asterisk/options.h"
 #include "asterisk/utils.h"
 #include "asterisk/linkedlists.h"
 
@@ -70,6 +64,8 @@ struct srv_entry {
 
 struct srv_context {
        unsigned int have_weights:1;
+       struct srv_entry *prev;
+       unsigned int num_records;
        AST_LIST_HEAD_NOLOCK(srv_entries, srv_entry) entries;
 };
 
@@ -79,7 +75,7 @@ static int parse_srv(unsigned char *answer, int len, unsigned char *msg, struct
                unsigned short priority;
                unsigned short weight;
                unsigned short port;
-       } __attribute__ ((__packed__)) *srv = (struct srv *) answer;
+       } __attribute__((__packed__)) *srv = (struct srv *) answer;
 
        int res = 0;
        char repl[256] = "";
@@ -132,7 +128,7 @@ static int srv_callback(void *context, unsigned char *answer, int len, unsigned
                if (current->priority <= entry->priority)
                        continue;
 
-               AST_LIST_INSERT_BEFORE_CURRENT(&c->entries, entry, list);
+               AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
                entry = NULL;
                break;
        }
@@ -167,8 +163,7 @@ static void process_weights(struct srv_context *context)
                        if (current->priority != cur_priority)
                                break;
 
-                       AST_LIST_REMOVE_CURRENT(&context->entries, list);
-                       AST_LIST_INSERT_TAIL(&temp_list, current, list);
+                       AST_LIST_MOVE_CURRENT(&temp_list, list);
                }
                AST_LIST_TRAVERSE_SAFE_END;
 
@@ -190,8 +185,8 @@ static void process_weights(struct srv_context *context)
                                if (current->weight < random_weight)
                                        continue;
 
-                               AST_LIST_REMOVE_CURRENT(&temp_list, list);
-                               AST_LIST_INSERT_TAIL(&newlist, current, list);
+                               AST_LIST_MOVE_CURRENT(&newlist, list);
+                               break;
                        }
                        AST_LIST_TRAVERSE_SAFE_END;
                }
@@ -204,6 +199,58 @@ static void process_weights(struct srv_context *context)
        AST_LIST_APPEND_LIST(&context->entries, &newlist, list);
 }
 
+int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
+{
+       struct srv_entry *cur;
+
+       if (*context == NULL) {
+               if (!(*context = ast_calloc(1, sizeof(struct srv_context)))) {
+                       return -1;
+               }
+               AST_LIST_HEAD_INIT_NOLOCK(&(*context)->entries);
+
+               if ((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 0) {
+                       ast_free(*context);
+                       *context = NULL;
+                       return -1;
+               }
+
+               if ((*context)->have_weights) {
+                       process_weights(*context);
+               }
+
+               (*context)->prev = AST_LIST_FIRST(&(*context)->entries);
+               *host = (*context)->prev->host;
+               *port = (*context)->prev->port;
+               AST_LIST_TRAVERSE(&(*context)->entries, cur, list) {
+                       ++((*context)->num_records);
+               }
+               return 0;
+       }
+
+       if (((*context)->prev = AST_LIST_NEXT((*context)->prev, list))) {
+               /* Retrieve next item in result */
+               *host = (*context)->prev->host;
+               *port = (*context)->prev->port;
+               return 0;
+       } else {
+               /* No more results */
+               while ((cur = AST_LIST_REMOVE_HEAD(&(*context)->entries, list))) {
+                       ast_free(cur);
+               }
+               ast_free(*context);
+               *context = NULL;
+               return 1;
+       }
+}
+
+void ast_srv_cleanup(struct srv_context **context)
+{
+       const char *host;
+       unsigned short port;
+       while (!(ast_srv_lookup(context, NULL, &host, &port)));
+}
+
 int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
 {
        struct srv_context context = { .entries = AST_LIST_HEAD_NOLOCK_INIT_VALUE };
@@ -231,10 +278,8 @@ int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, co
                ast_copy_string(host, current->host, hostlen);
                *port = current->port;
                ast_free(current);
-               if (option_verbose > 3) {
-                       ast_verbose(VERBOSE_PREFIX_3 "ast_get_srv: SRV lookup for '%s' mapped to host %s, port %d\n",
+               ast_verb(4, "ast_get_srv: SRV lookup for '%s' mapped to host %s, port %d\n",
                                    service, host, *port);
-               }
        } else {
                host[0] = '\0';
                *port = -1;
@@ -245,3 +290,34 @@ int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, co
 
        return ret;
 }
+
+unsigned int ast_srv_get_record_count(struct srv_context *context)
+{
+       return context->num_records;
+}
+
+int ast_srv_get_nth_record(struct srv_context *context, int record_num, const char **host,
+               unsigned short *port, unsigned short *priority, unsigned short *weight)
+{
+       int i = 1;
+       int res = -1;
+       struct srv_entry *entry;
+
+       if (record_num < 1 || record_num > context->num_records) {
+               return res;
+       }
+
+       AST_LIST_TRAVERSE(&context->entries, entry, list) {
+               if (i == record_num) {
+                       *host = entry->host;
+                       *port = entry->port;
+                       *priority = entry->priority;
+                       *weight = entry->weight;
+                       res = 0;
+                       break;
+               }
+               ++i;
+       }
+
+       return res;
+}