+static si_list_t *
+_gai_srv(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, uint32_t *err)
+{
+ int i;
+ char *qname;
+ si_srv_t *srv;
+ si_item_t *item;
+
+ si_list_t *list = NULL;
+ si_list_t *result = NULL;
+
+ /* Minimum SRV priority is zero. Start below that. */
+ int lastprio = -1;
+ int currprio;
+
+ if (node == NULL || serv == NULL) return NULL;
+
+ asprintf(&qname, "%s.%s", serv, node);
+ list = si_srv_byname(si, qname, err);
+ free(qname);
+
+ /* Iterate the SRV records starting at lowest priority and attempt to
+ * lookup the target host name. Returns the first successful lookup.
+ * It's an O(n^2) algorithm but data sets are small (less than 100) and
+ * sorting overhead is dwarfed by network I/O for each element.
+ */
+ while (list != NULL && result == NULL)
+ {
+ /* Find the next lowest priority level. */
+ /* Maximum SRV priority is UINT16_MAX. Start above that. */
+ currprio = INT_MAX;
+
+ for (i = 0; i < list->count; ++i)
+ {
+ item = list->entry[i];
+ srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ if (srv->priority > lastprio && srv->priority < currprio)
+ {
+ currprio = srv->priority;
+ }
+ }
+
+ if (currprio == INT_MAX)
+ {
+ /* All priorities have been evaluated. Done. */
+ break;
+ }
+ else
+ {
+ lastprio = currprio;
+ }
+
+ /* Lookup hosts at the current priority level. Return first match. */
+ for (i = 0; i < list->count; ++i)
+ {
+ item = list->entry[i];
+ srv = (si_srv_t *)((uintptr_t)item + sizeof(si_item_t));
+
+ if (srv->priority == currprio)
+ {
+ /* So that _gai_simple expects an integer service. */
+ flags |= AI_NUMERICSERV;
+
+ result = _gai_simple(si, srv->target, &srv->port, family, socktype, proto, flags, err);
+ if (result)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ if (list != NULL)
+ {
+ si_list_release(list);
+ }
+
+ return result;
+}
+