Let ExtensionState resolve dynamic hints.
[asterisk/asterisk.git] / main / srv.c
index 0819942..c650650 100644 (file)
@@ -64,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;
 };
 
@@ -197,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 };
@@ -236,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;
+}