krb5 commit: Use k5_transport(_strategy) enums for k5_sendto

Greg Hudson ghudson at MIT.EDU
Mon Jun 2 18:53:27 EDT 2014


https://github.com/krb5/krb5/commit/9c6be00daca0b80aed94ec9680724f95e6be92e1
commit 9c6be00daca0b80aed94ec9680724f95e6be92e1
Author: Robbie Harwood (frozencemetery) <rharwood at club.cc.cmu.edu>
Date:   Thu Aug 15 15:55:52 2013 -0400

    Use k5_transport(_strategy) enums for k5_sendto
    
    In k5_sendto and k5_locate_server, replace "socktype" parameters with
    a new enumerator k5_transport, so that we can add new transports which
    are not in the socket type namespace.  Control the order in which we
    make connections of different types using a new k5_transport_strategy
    enumerator, to simplify the logic for adding new transports later.
    Control the result of k5_locate_server with a no_udp boolean rather
    than a socket type.
    
    [ghudson at mit.edu: renamed type to k5_transport; k5_locate_server
     no_udp change; clarified commit message; fix for Solaris getaddrinfo]
    [kaduk at mit.edu: name variables of type k5_transport 'transport']
    [nalin at redhat.com: use transport rather than sock_type in more places,
     add and use k5_transport_strategy, update the test program]
    
    ticket: 7929

 src/lib/krb5/os/changepw.c         |   31 +++++-----
 src/lib/krb5/os/hostrealm_domain.c |    2 +-
 src/lib/krb5/os/locate_kdc.c       |   75 +++++++++++++---------
 src/lib/krb5/os/os-proto.h         |   27 ++++++--
 src/lib/krb5/os/sendto_kdc.c       |  123 ++++++++++++++++++++++-------------
 src/lib/krb5/os/t_locate_kdc.c     |   24 ++++----
 src/lib/krb5/os/t_std_conf.c       |    2 +-
 src/lib/krb5/os/t_trace.c          |    6 +-
 src/lib/krb5/os/t_trace.ref        |    4 +-
 src/lib/krb5/os/trace.c            |    6 +-
 10 files changed, 178 insertions(+), 122 deletions(-)

diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index 4d8abd9..a1c9885 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -59,25 +59,25 @@ struct sendto_callback_context {
 
 static krb5_error_code
 locate_kpasswd(krb5_context context, const krb5_data *realm,
-               struct serverlist *serverlist, int socktype)
+               struct serverlist *serverlist, krb5_boolean no_udp)
 {
     krb5_error_code code;
 
     code = k5_locate_server(context, realm, serverlist, locate_service_kpasswd,
-                            socktype);
+                            no_udp);
 
     if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
         code = k5_locate_server(context, realm, serverlist,
-                                locate_service_kadmin, SOCK_STREAM);
+                                locate_service_kadmin, TRUE);
         if (!code) {
-            /* Success with admin_server but now we need to change the
-               port number to use DEFAULT_KPASSWD_PORT and the socktype.  */
+            /* Success with admin_server but now we need to change the port
+             * number to use DEFAULT_KPASSWD_PORT and the transport. */
             size_t i;
             for (i = 0; i < serverlist->nservers; i++) {
                 struct server_entry *s = &serverlist->servers[i];
                 krb5_ui_2 kpasswd_port = htons(DEFAULT_KPASSWD_PORT);
-                if (socktype != SOCK_STREAM)
-                    s->socktype = socktype;
+                if (!no_udp && s->transport == TCP)
+                    s->transport = TCP_OR_UDP;
                 if (s->hostname != NULL)
                     s->port = kpasswd_port;
                 else if (s->family == AF_INET)
@@ -214,7 +214,7 @@ change_set_password(krb5_context context,
                     krb5_data *result_string)
 {
     krb5_data                   chpw_rep;
-    krb5_boolean                use_tcp = 0;
+    krb5_boolean                no_udp = FALSE;
     GETSOCKNAME_ARG3_TYPE       addrlen;
     krb5_error_code             code = 0;
     char                        *code_string;
@@ -247,9 +247,10 @@ change_set_password(krb5_context context,
     callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;
 
     do {
-        int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM);
+        k5_transport_strategy strategy = no_udp ? NO_UDP : UDP_FIRST;
+
         code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl,
-                              socktype);
+                              no_udp);
         if (code)
             break;
 
@@ -260,7 +261,7 @@ change_set_password(krb5_context context,
         callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
         krb5_free_data_contents(callback_ctx.context, &chpw_rep);
 
-        code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0,
+        code = k5_sendto(callback_ctx.context, NULL, &sl, strategy,
                          &callback_info, &chpw_rep, ss2sa(&remote_addr),
                          &addrlen, NULL, NULL, NULL);
         if (code) {
@@ -277,9 +278,9 @@ change_set_password(krb5_context context,
                                    result_string);
 
         if (code) {
-            if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
+            if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
                 k5_free_serverlist(&sl);
-                use_tcp = 1;
+                no_udp = 1;
                 continue;
             }
 
@@ -305,9 +306,9 @@ change_set_password(krb5_context context,
             strncpy(result_code_string->data, code_string, result_code_string->length);
         }
 
-        if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
+        if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
             k5_free_serverlist(&sl);
-            use_tcp = 1;
+            no_udp = 1;
         } else {
             break;
         }
diff --git a/src/lib/krb5/os/hostrealm_domain.c b/src/lib/krb5/os/hostrealm_domain.c
index dc9cc59..2228df0 100644
--- a/src/lib/krb5/os/hostrealm_domain.c
+++ b/src/lib/krb5/os/hostrealm_domain.c
@@ -85,7 +85,7 @@ domain_fallback_realm(krb5_context context, krb5_hostrealm_moddata data,
     suffix = uhost;
     while (limit-- >= 0 && (dot = strchr(suffix, '.')) != NULL) {
         drealm = string2data((char *)suffix);
-        if (k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM) == 0) {
+        if (k5_locate_kdc(context, &drealm, &slist, FALSE, FALSE) == 0) {
             k5_free_serverlist(&slist);
             ret = k5_make_realmlist(suffix, realms_out);
             goto cleanup;
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index 4479465..4c8aead 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -129,7 +129,7 @@ new_server_entry(struct serverlist *list)
 
 /* Add an address entry to list. */
 static int
-add_addr_to_list(struct serverlist *list, int socktype, int family,
+add_addr_to_list(struct serverlist *list, k5_transport transport, int family,
                  size_t addrlen, struct sockaddr *addr)
 {
     struct server_entry *entry;
@@ -137,7 +137,7 @@ add_addr_to_list(struct serverlist *list, int socktype, int family,
     entry = new_server_entry(list);
     if (entry == NULL)
         return ENOMEM;
-    entry->socktype = socktype;
+    entry->transport = transport;
     entry->family = family;
     entry->hostname = NULL;
     entry->addrlen = addrlen;
@@ -149,14 +149,14 @@ add_addr_to_list(struct serverlist *list, int socktype, int family,
 /* Add a hostname entry to list. */
 static int
 add_host_to_list(struct serverlist *list, const char *hostname, int port,
-                 int socktype, int family)
+                 k5_transport transport, int family)
 {
     struct server_entry *entry;
 
     entry = new_server_entry(list);
     if (entry == NULL)
         return ENOMEM;
-    entry->socktype = socktype;
+    entry->transport = transport;
     entry->family = family;
     entry->hostname = strdup(hostname);
     if (entry->hostname == NULL)
@@ -187,7 +187,7 @@ server_list_contains(struct serverlist *list, struct server_entry *server)
 static krb5_error_code
 locate_srv_conf_1(krb5_context context, const krb5_data *realm,
                   const char * name, struct serverlist *serverlist,
-                  int socktype, int udpport, int sec_udpport)
+                  k5_transport transport, int udpport, int sec_udpport)
 {
     const char  *realm_srv_names[4];
     char **hostlist, *host, *port, *cp;
@@ -255,12 +255,12 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm,
             *cp = '\0';
         }
 
-        code = add_host_to_list(serverlist, host, p1, socktype, AF_UNSPEC);
+        code = add_host_to_list(serverlist, host, p1, transport, AF_UNSPEC);
         /* Second port is for IPv4 UDP only, and should possibly go away as
          * it was originally a krb4 compatibility measure. */
         if (code == 0 && p2 != 0 &&
-            (socktype == 0 || socktype == SOCK_DGRAM))
-            code = add_host_to_list(serverlist, host, p2, SOCK_DGRAM, AF_INET);
+            (transport == TCP_OR_UDP || transport == UDP))
+            code = add_host_to_list(serverlist, host, p2, UDP, AF_INET);
         if (code)
             goto cleanup;
     }
@@ -278,7 +278,8 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm,
 {
     krb5_error_code ret;
 
-    ret = locate_srv_conf_1(context, realm, name, al, 0, udpport, sec_udpport);
+    ret = locate_srv_conf_1(context, realm, name, al, TCP_OR_UDP, udpport,
+                            sec_udpport);
     if (ret)
         return ret;
     if (al->nservers == 0)        /* Couldn't resolve any KDC names */
@@ -294,7 +295,7 @@ locate_srv_dns_1(const krb5_data *realm, const char *service,
 {
     struct srv_dns_entry *head = NULL, *entry = NULL;
     krb5_error_code code = 0;
-    int socktype;
+    k5_transport transport;
 
     code = krb5int_make_srv_query_realm(realm, service, protocol, &head);
     if (code)
@@ -310,9 +311,9 @@ locate_srv_dns_1(const krb5_data *realm, const char *service,
     }
 
     for (entry = head; entry != NULL; entry = entry->next) {
-        socktype = (strcmp(protocol, "_tcp") == 0) ? SOCK_STREAM : SOCK_DGRAM;
+        transport = (strcmp(protocol, "_tcp") == 0) ? TCP : UDP;
         code = add_host_to_list(serverlist, entry->host, htons(entry->port),
-                                socktype, AF_UNSPEC);
+                                transport, AF_UNSPEC);
         if (code)
             goto cleanup;
     }
@@ -341,6 +342,7 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
 {
     struct module_callback_data *d = cbdata;
     size_t addrlen;
+    k5_transport transport;
 
     if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
         return 0;
@@ -350,7 +352,8 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
         addrlen = sizeof(struct sockaddr_in6);
     else
         return 0;
-    if (add_addr_to_list(d->list, socktype, sa->sa_family, addrlen,
+    transport = (socktype == SOCK_STREAM) ? TCP : UDP;
+    if (add_addr_to_list(d->list, transport, sa->sa_family, addrlen,
                          sa) != 0) {
         /* Assumes only error is ENOMEM.  */
         d->out_of_mem = 1;
@@ -362,14 +365,14 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
 static krb5_error_code
 module_locate_server(krb5_context ctx, const krb5_data *realm,
                      struct serverlist *serverlist,
-                     enum locate_service_type svc, int socktype)
+                     enum locate_service_type svc, k5_transport transport)
 {
     struct krb5plugin_service_locate_result *res = NULL;
     krb5_error_code code;
     struct krb5plugin_service_locate_ftable *vtbl = NULL;
     void **ptrs;
     char *realmz;               /* NUL-terminated realm */
-    int i;
+    int socktype, i;
     struct module_callback_data cbdata = { 0, };
     const char *msg;
 
@@ -413,11 +416,11 @@ module_locate_server(krb5_context ctx, const krb5_data *realm,
         if (code)
             continue;
 
-        code = vtbl->lookup(blob, svc, realmz,
-                            (socktype != 0) ? socktype : SOCK_DGRAM, AF_UNSPEC,
+        socktype = (transport == TCP) ? SOCK_STREAM : SOCK_DGRAM;
+        code = vtbl->lookup(blob, svc, realmz, socktype, AF_UNSPEC,
                             module_callback, &cbdata);
         /* Also ask for TCP addresses if we got UDP addresses and want both. */
-        if (code == 0 && socktype == 0) {
+        if (code == 0 && transport == TCP_OR_UDP) {
             code = vtbl->lookup(blob, svc, realmz, SOCK_STREAM, AF_UNSPEC,
                                 module_callback, &cbdata);
             if (code == KRB5_PLUGIN_NO_HANDLE)
@@ -459,7 +462,7 @@ module_locate_server(krb5_context ctx, const krb5_data *realm,
 static krb5_error_code
 prof_locate_server(krb5_context context, const krb5_data *realm,
                    struct serverlist *serverlist, enum locate_service_type svc,
-                   int socktype)
+                   k5_transport transport)
 {
     const char *profname;
     int dflport1, dflport2 = 0;
@@ -495,7 +498,7 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
         return EBUSY;           /* XXX */
     }
 
-    return locate_srv_conf_1(context, realm, profname, serverlist, socktype,
+    return locate_srv_conf_1(context, realm, profname, serverlist, transport,
                              dflport1, dflport2);
 }
 
@@ -503,7 +506,7 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
 static krb5_error_code
 dns_locate_server(krb5_context context, const krb5_data *realm,
                   struct serverlist *serverlist, enum locate_service_type svc,
-                  int socktype)
+                  k5_transport transport)
 {
     const char *dnsname;
     int use_dns = _krb5_use_dns_kdc(context);
@@ -533,12 +536,12 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
     }
 
     code = 0;
-    if (socktype == SOCK_DGRAM || socktype == 0) {
+    if (transport == UDP || transport == TCP_OR_UDP) {
         code = locate_srv_dns_1(realm, dnsname, "_udp", serverlist);
         if (code)
             Tprintf("dns udp lookup returned error %d\n", code);
     }
-    if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
+    if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) {
         code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist);
         if (code)
             Tprintf("dns tcp lookup returned error %d\n", code);
@@ -547,10 +550,16 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
 }
 #endif /* KRB5_DNS_LOOKUP */
 
+/*
+ * Try all of the server location methods in sequence.  transport must be
+ * TCP_OR_UDP, TCP, or UDP.  It is applied to hostname entries in the profile
+ * and affects whether we query modules or DNS for UDP or TCP or both, but does
+ * not restrict a method from returning entries of other transports.
+ */
 static krb5_error_code
 locate_server(krb5_context context, const krb5_data *realm,
               struct serverlist *serverlist, enum locate_service_type svc,
-              int socktype)
+              k5_transport transport)
 {
     krb5_error_code ret;
     struct serverlist list = SERVERLIST_INIT;
@@ -559,18 +568,18 @@ locate_server(krb5_context context, const krb5_data *realm,
 
     /* Try modules.  If a module returns 0 but leaves the list empty, return an
      * empty list. */
-    ret = module_locate_server(context, realm, &list, svc, socktype);
+    ret = module_locate_server(context, realm, &list, svc, transport);
     if (ret != KRB5_PLUGIN_NO_HANDLE)
         goto done;
 
     /* Try the profile.  Fall back to DNS if it returns an empty list. */
-    ret = prof_locate_server(context, realm, &list, svc, socktype);
+    ret = prof_locate_server(context, realm, &list, svc, transport);
     if (ret)
         goto done;
 
 #ifdef KRB5_DNS_LOOKUP
     if (list.nservers == 0)
-        ret = dns_locate_server(context, realm, &list, svc, socktype);
+        ret = dns_locate_server(context, realm, &list, svc, transport);
 #endif
 
 done:
@@ -589,9 +598,10 @@ done:
 krb5_error_code
 k5_locate_server(krb5_context context, const krb5_data *realm,
                  struct serverlist *serverlist, enum locate_service_type svc,
-                 int socktype)
+                 krb5_boolean no_udp)
 {
     krb5_error_code ret;
+    k5_transport transport = no_udp ? TCP : TCP_OR_UDP;
 
     memset(serverlist, 0, sizeof(*serverlist));
     if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
@@ -600,7 +610,7 @@ k5_locate_server(krb5_context context, const krb5_data *realm,
         return KRB5_REALM_CANT_RESOLVE;
     }
 
-    ret = locate_server(context, realm, serverlist, svc, socktype);
+    ret = locate_server(context, realm, serverlist, svc, transport);
     if (ret)
         return ret;
 
@@ -616,12 +626,13 @@ k5_locate_server(krb5_context context, const krb5_data *realm,
 
 krb5_error_code
 k5_locate_kdc(krb5_context context, const krb5_data *realm,
-              struct serverlist *serverlist, int get_masters, int socktype)
+              struct serverlist *serverlist, krb5_boolean get_masters,
+              krb5_boolean no_udp)
 {
     enum locate_service_type stype;
 
     stype = get_masters ? locate_service_master_kdc : locate_service_kdc;
-    return k5_locate_server(context, realm, serverlist, stype, socktype);
+    return k5_locate_server(context, realm, serverlist, stype, no_udp);
 }
 
 krb5_boolean
@@ -632,7 +643,7 @@ k5_kdc_is_master(krb5_context context, const krb5_data *realm,
     krb5_boolean found;
 
     if (locate_server(context, realm, &list, locate_service_master_kdc,
-                      server->socktype) != 0)
+                      server->transport) != 0)
         return FALSE;
     found = server_list_contains(&list, server);
     k5_free_serverlist(&list);
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index 9125ba0..3196bca 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -38,11 +38,23 @@
 
 #include <krb5/locate_plugin.h>
 
+typedef enum {
+    TCP_OR_UDP = 0,
+    TCP,
+    UDP,
+} k5_transport;
+
+typedef enum {
+    UDP_FIRST = 0,
+    UDP_LAST,
+    NO_UDP,
+} k5_transport_strategy;
+
 /* A single server hostname or address. */
 struct server_entry {
     char *hostname;             /* NULL -> use addrlen/addr instead */
     int port;                   /* Used only if hostname set */
-    int socktype;               /* May be 0 for UDP/TCP if hostname set */
+    k5_transport transport;     /* May be 0 for UDP/TCP if hostname set */
     int family;                 /* May be 0 (aka AF_UNSPEC) if hostname set */
     size_t addrlen;
     struct sockaddr_storage addr;
@@ -56,8 +68,8 @@ struct serverlist {
 #define SERVERLIST_INIT { NULL, 0 }
 
 struct remote_address {
+    k5_transport transport;
     int family;
-    int type;
     socklen_t len;
     struct sockaddr_storage saddr;
 };
@@ -69,12 +81,13 @@ struct sendto_callback_info {
 };
 
 krb5_error_code k5_locate_server(krb5_context, const krb5_data *realm,
-                                 struct serverlist *,
-                                 enum locate_service_type svc, int socktype);
+                                 struct serverlist *serverlist,
+                                 enum locate_service_type svc,
+                                 krb5_boolean no_udp);
 
 krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm,
-                              struct serverlist *serverlist, int get_masters,
-                              int socktype);
+                              struct serverlist *serverlist,
+                              krb5_boolean get_masters, krb5_boolean no_udp);
 
 krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm,
                               struct server_entry *server);
@@ -103,7 +116,7 @@ int _krb5_conf_boolean (const char *);
 
 krb5_error_code k5_sendto(krb5_context context, const krb5_data *message,
                           const struct serverlist *addrs,
-                          int socktype1, int socktype2,
+                          k5_transport_strategy strategy,
                           struct sendto_callback_info *callback_info,
                           krb5_data *reply, struct sockaddr *remoteaddr,
                           socklen_t *remoteaddrlen, int *server_used,
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index e3855a3..3f99ce8 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -104,6 +104,7 @@ struct conn_state {
     size_t server_index;
     struct conn_state *next;
     time_ms endtime;
+    krb5_boolean defer;
 };
 
 /* Get current time in milliseconds. */
@@ -293,6 +294,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
 }
 
 static int
+socktype_for_transport(k5_transport transport)
+{
+    switch (transport) {
+    case UDP:
+        return SOCK_DGRAM;
+    case TCP:
+        return SOCK_STREAM;
+    default:
+        return 0;
+    }
+}
+
+static int
 check_for_svc_unavailable (krb5_context context,
                            const krb5_data *reply,
                            void *msg_handler_data)
@@ -330,11 +344,12 @@ check_for_svc_unavailable (krb5_context context,
 krb5_error_code
 krb5_sendto_kdc(krb5_context context, const krb5_data *message,
                 const krb5_data *realm, krb5_data *reply, int *use_master,
-                int tcp_only)
+                int no_udp)
 {
     krb5_error_code retval, err;
     struct serverlist servers;
-    int socktype1 = 0, socktype2 = 0, server_used;
+    int server_used;
+    k5_transport_strategy strategy;
 
     /*
      * find KDC location(s) for realm
@@ -349,9 +364,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
      * should probably be returned as well.
      */
 
-    TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only);
+    TRACE_SENDTO_KDC(context, message->length, realm, *use_master, no_udp);
 
-    if (!tcp_only && context->udp_pref_limit < 0) {
+    if (!no_udp && context->udp_pref_limit < 0) {
         int tmp;
         retval = profile_get_integer(context->profile,
                                      KRB5_CONF_LIBDEFAULTS, KRB5_CONF_UDP_PREFERENCE_LIMIT, 0,
@@ -368,22 +383,21 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
         context->udp_pref_limit = tmp;
     }
 
-    if (tcp_only)
-        socktype1 = SOCK_STREAM, socktype2 = 0;
+    if (no_udp)
+        strategy = NO_UDP;
     else if (message->length <= (unsigned int) context->udp_pref_limit)
-        socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
+        strategy = UDP_FIRST;
     else
-        socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
+        strategy = UDP_LAST;
 
-    retval = k5_locate_kdc(context, realm, &servers, *use_master,
-                           tcp_only ? SOCK_STREAM : 0);
+    retval = k5_locate_kdc(context, realm, &servers, *use_master, no_udp);
     if (retval)
         return retval;
 
     err = 0;
-    retval = k5_sendto(context, message, &servers, socktype1, socktype2,
-                       NULL, reply, NULL, NULL, &server_used,
-                       check_for_svc_unavailable, &err);
+    retval = k5_sendto(context, message, &servers, strategy, NULL, reply,
+                       NULL, NULL, &server_used, check_for_svc_unavailable,
+                       &err);
     if (retval == KRB5_KDC_UNREACH) {
         if (err == KDC_ERR_SVC_UNAVAILABLE) {
             retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
@@ -444,7 +458,7 @@ set_transport_message(struct conn_state *state, const krb5_data *message)
     if (message == NULL || message->length == 0)
         return;
 
-    if (state->addr.type == SOCK_STREAM) {
+    if (state->addr.transport == TCP) {
         store_32_be(message->length, out->msg_len_buf);
         SG_SET(&out->sgbuf[0], out->msg_len_buf, 4);
         SG_SET(&out->sgbuf[1], message->data, message->length);
@@ -457,8 +471,9 @@ set_transport_message(struct conn_state *state, const krb5_data *message)
 }
 
 static krb5_error_code
-add_connection(struct conn_state **conns, struct addrinfo *ai,
-               size_t server_index, char **udpbufp)
+add_connection(struct conn_state **conns, k5_transport transport,
+               krb5_boolean defer, struct addrinfo *ai, size_t server_index,
+               char **udpbufp)
 {
     struct conn_state *state, **tailptr;
 
@@ -467,14 +482,15 @@ add_connection(struct conn_state **conns, struct addrinfo *ai,
         return ENOMEM;
     state->state = INITIALIZING;
     state->out.sgp = state->out.sgbuf;
-    state->addr.type = ai->ai_socktype;
+    state->addr.transport = transport;
     state->addr.family = ai->ai_family;
     state->addr.len = ai->ai_addrlen;
     memcpy(&state->addr.saddr, ai->ai_addr, ai->ai_addrlen);
+    state->defer = defer;
     state->fd = INVALID_SOCKET;
     state->server_index = server_index;
     SG_SET(&state->out.sgbuf[1], NULL, 0);
-    if (ai->ai_socktype == SOCK_STREAM) {
+    if (transport == TCP) {
         state->service = service_tcp_fd;
     } else {
         state->service = service_udp_fd;
@@ -549,32 +565,41 @@ translate_ai_error (int err)
  */
 static krb5_error_code
 resolve_server(krb5_context context, const struct serverlist *servers,
-               size_t ind, int socktype1, int socktype2,
+               size_t ind, k5_transport_strategy strategy,
                const krb5_data *message, char **udpbufp,
                struct conn_state **conns)
 {
     krb5_error_code retval;
     struct server_entry *entry = &servers->servers[ind];
+    k5_transport transport;
     struct addrinfo *addrs, *a, hint, ai;
+    krb5_boolean defer;
     int err, result;
     char portbuf[64];
 
-    /* Skip any stray entries of socktypes we don't want. */
-    if (entry->socktype != 0 && entry->socktype != socktype1 &&
-        entry->socktype != socktype2)
+    /* Skip UDP entries if we don't want UDP. */
+    if (strategy == NO_UDP && entry->transport == UDP)
         return 0;
 
+    transport = (strategy == UDP_FIRST) ? UDP : TCP;
     if (entry->hostname == NULL) {
-        ai.ai_socktype = entry->socktype;
+        /* Added by a module, so transport is either TCP or UDP. */
+        ai.ai_socktype = socktype_for_transport(entry->transport);
         ai.ai_family = entry->family;
         ai.ai_addrlen = entry->addrlen;
         ai.ai_addr = (struct sockaddr *)&entry->addr;
-        return add_connection(conns, &ai, ind, udpbufp);
+        defer = (entry->transport != transport);
+        return add_connection(conns, entry->transport, defer, &ai, ind,
+                              udpbufp);
     }
 
+    /* If the entry has a specified transport, use it. */
+    if (entry->transport != TCP_OR_UDP)
+        transport = entry->transport;
+
     memset(&hint, 0, sizeof(hint));
     hint.ai_family = entry->family;
-    hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1;
+    hint.ai_socktype = socktype_for_transport(transport);
     hint.ai_flags = AI_ADDRCONFIG;
 #ifdef AI_NUMERICSERV
     hint.ai_flags |= AI_NUMERICSERV;
@@ -586,15 +611,19 @@ resolve_server(krb5_context context, const struct serverlist *servers,
     err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs);
     if (err)
         return translate_ai_error(err);
-    /* Add each address with the preferred socktype. */
+
+    /* Add each address with the specified or preferred transport. */
     retval = 0;
     for (a = addrs; a != 0 && retval == 0; a = a->ai_next)
-        retval = add_connection(conns, a, ind, udpbufp);
-    if (retval == 0 && entry->socktype == 0 && socktype2 != 0) {
-        /* Add each address again with the non-preferred socktype. */
+        retval = add_connection(conns, transport, FALSE, a, ind, udpbufp);
+
+    /* For TCP_OR_UDP entries, add each address again with the non-preferred
+     * transport, unless we are avoiding UDP.  Flag these as deferred. */
+    if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) {
+        transport = (strategy == UDP_FIRST) ? TCP : UDP;
         for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
-            a->ai_socktype = socktype2;
-            retval = add_connection(conns, a, ind, udpbufp);
+            a->ai_socktype = socktype_for_transport(transport);
+            retval = add_connection(conns, transport, TRUE, a, ind, udpbufp);
         }
     }
     freeaddrinfo(addrs);
@@ -606,17 +635,18 @@ start_connection(krb5_context context, struct conn_state *state,
                  const krb5_data *message, struct select_state *selstate,
                  struct sendto_callback_info *callback_info)
 {
-    int fd, e;
+    int fd, e, type;
     static const int one = 1;
     static const struct linger lopt = { 0, 0 };
 
-    fd = socket(state->addr.family, state->addr.type, 0);
+    type = socktype_for_transport(state->addr.transport);
+    fd = socket(state->addr.family, type, 0);
     if (fd == INVALID_SOCKET)
         return -1;              /* try other hosts */
     set_cloexec_fd(fd);
     /* Make it non-blocking.  */
     ioctlsocket(fd, FIONBIO, (const void *) &one);
-    if (state->addr.type == SOCK_STREAM) {
+    if (state->addr.transport == TCP) {
         setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt));
         TRACE_SENDTO_KDC_TCP_CONNECT(context, &state->addr);
     }
@@ -665,7 +695,7 @@ start_connection(krb5_context context, struct conn_state *state,
     }
     set_transport_message(state, message);
 
-    if (state->addr.type == SOCK_DGRAM) {
+    if (state->addr.transport == UDP) {
         /* Send it now.  */
         ssize_t ret;
         sg_buf *sg = &state->out.sgbuf[0];
@@ -720,7 +750,7 @@ maybe_send(krb5_context context, struct conn_state *conn,
         return -1;
     }
 
-    if (conn->addr.type == SOCK_STREAM) {
+    if (conn->addr.transport != UDP) {
         /* The select callback will handle flushing any data we
            haven't written yet, and we only write it once.  */
         return -1;
@@ -910,7 +940,7 @@ get_endtime(time_ms endtime, struct conn_state *conns)
     struct conn_state *state;
 
     for (state = conns; state != NULL; state = state->next) {
-        if (state->addr.type == SOCK_STREAM &&
+        if (state->addr.transport == TCP &&
             (state->state == READING || state->state == WRITING) &&
             state->endtime > endtime)
             endtime = state->endtime;
@@ -1008,7 +1038,7 @@ service_fds(krb5_context context, struct select_state *selstate,
 
 krb5_error_code
 k5_sendto(krb5_context context, const krb5_data *message,
-          const struct serverlist *servers, int socktype1, int socktype2,
+          const struct serverlist *servers, k5_transport_strategy strategy,
           struct sendto_callback_info* callback_info, krb5_data *reply,
           struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
           int *server_used,
@@ -1038,17 +1068,18 @@ k5_sendto(krb5_context context, const krb5_data *message,
     cm_init_selstate(sel_state);
 
     /* First pass: resolve server hosts, communicate with resulting addresses
-     * of the preferred socktype, and wait 1s for an answer from each. */
+     * of the preferred transport, and wait 1s for an answer from each. */
     for (s = 0; s < servers->nservers && !done; s++) {
         /* Find the current tail pointer. */
         for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
-        retval = resolve_server(context, servers, s, socktype1, socktype2,
-                                message, &udpbuf, &conns);
+        retval = resolve_server(context, servers, s, strategy, message,
+                                &udpbuf, &conns);
         if (retval)
             goto cleanup;
         for (state = *tailptr; state != NULL && !done; state = state->next) {
-            /* Contact each new connection whose socktype matches socktype1. */
-            if (state->addr.type != socktype1)
+            /* Contact each new connection, deferring those which use the
+             * non-preferred RFC 4120 transport. */
+            if (state->defer)
                 continue;
             if (maybe_send(context, state, message, sel_state, callback_info))
                 continue;
@@ -1057,10 +1088,10 @@ k5_sendto(krb5_context context, const krb5_data *message,
         }
     }
 
-    /* Complete the first pass by contacting servers of the non-preferred
-     * socktype (if given), waiting 1s for an answer from each. */
+    /* Complete the first pass by contacting servers of the non-preferred RFC
+     * 4120 transport (if given), waiting 1s for an answer from each. */
     for (state = conns; state != NULL && !done; state = state->next) {
-        if (state->addr.type != socktype2)
+        if (!state->defer)
             continue;
         if (maybe_send(context, state, message, sel_state, callback_info))
             continue;
diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c
index 5453a4c..300aa71 100644
--- a/src/lib/krb5/os/t_locate_kdc.c
+++ b/src/lib/krb5/os/t_locate_kdc.c
@@ -29,18 +29,18 @@ kfatal (krb5_error_code err)
 }
 
 static const char *
-stypename (int stype)
+ttypename (k5_transport ttype)
 {
     static char buf[20];
-    switch (stype) {
-    case SOCK_STREAM:
-        return "stream";
-    case SOCK_DGRAM:
-        return "dgram";
-    case SOCK_RAW:
-        return "raw";
+    switch (ttype) {
+    case TCP_OR_UDP:
+        return "tcp or udp";
+    case TCP:
+        return "tcp";
+    case UDP:
+        return "udp";
     default:
-        snprintf(buf, sizeof(buf), "?%d", stype);
+        snprintf(buf, sizeof(buf), "?%d", ttype);
         return buf;
     }
 }
@@ -58,7 +58,7 @@ print_addrs (void)
 
         if (entry->hostname != NULL) {
             printf("%2d: host %s\t%s\tport %d\n", (int)i, entry->hostname,
-                   stypename(entry->socktype), ntohs(entry->port));
+                   ttypename(entry->transport), ntohs(entry->port));
             continue;
         }
         err = getnameinfo((struct sockaddr *)&entry->addr, entry->addrlen,
@@ -69,7 +69,7 @@ print_addrs (void)
                    gai_strerror(err));
         } else {
             printf("%2d: address %s\t%s\tport %s\n", (int)i, hostbuf,
-                   stypename(entry->socktype), srvbuf);
+                   ttypename(entry->transport), srvbuf);
         }
     }
 }
@@ -129,7 +129,7 @@ main (int argc, char *argv[])
         break;
 
     case LOOKUP_WHATEVER:
-        err = k5_locate_kdc(ctx, &realm, &sl, master, 0);
+        err = k5_locate_kdc(ctx, &realm, &sl, master, FALSE);
         break;
     }
     if (err) kfatal (err);
diff --git a/src/lib/krb5/os/t_std_conf.c b/src/lib/krb5/os/t_std_conf.c
index e2ff572..6ee54d5 100644
--- a/src/lib/krb5/os/t_std_conf.c
+++ b/src/lib/krb5/os/t_std_conf.c
@@ -82,7 +82,7 @@ test_locate_kdc(krb5_context ctx, char *realm)
 
     rlm.data = realm;
     rlm.length = strlen(realm);
-    retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, 0);
+    retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, FALSE);
     if (retval) {
         com_err("krb5_locate_kdc", retval, 0);
         return;
diff --git a/src/lib/krb5/os/t_trace.c b/src/lib/krb5/os/t_trace.c
index 36044f5..4cb2bd0 100644
--- a/src/lib/krb5/os/t_trace.c
+++ b/src/lib/krb5/os/t_trace.c
@@ -112,7 +112,7 @@ main (int argc, char *argv[])
     TRACE(ctx, "size_t and const char *, as four-character hex hash: "
           "{hashlenstr}", 1, NULL);
 
-    ra.type = SOCK_STREAM;
+    ra.transport = TCP;
     addr_in = (struct sockaddr_in *)&ra.saddr;
     addr_in->sin_family = AF_INET;
     addr_in->sin_addr.s_addr = INADDR_ANY;
@@ -121,10 +121,10 @@ main (int argc, char *argv[])
     ra.family = AF_INET;
     TRACE(ctx, "struct remote_address *, show socket type, address, port: "
           "{raddr}", &ra);
-    ra.type = SOCK_DGRAM;
+    ra.transport = UDP;
     TRACE(ctx, "struct remote_address *, show socket type, address, port: "
           "{raddr}", &ra);
-    ra.type = 1234;
+    ra.transport = 1234;
     addr_in->sin_family = AF_UNSPEC;
     ra.family = AF_UNSPEC;
     TRACE(ctx, "struct remote_address *, show socket type, address, port: "
diff --git a/src/lib/krb5/os/t_trace.ref b/src/lib/krb5/os/t_trace.ref
index 749d9c9..ca5818a 100644
--- a/src/lib/krb5/os/t_trace.ref
+++ b/src/lib/krb5/os/t_trace.ref
@@ -10,8 +10,8 @@ size_t and const char *, as four-character hex hash: 7B9A
 size_t and const char *, as four-character hex hash: (null)
 struct remote_address *, show socket type, address, port: stream 0.0.0.0:88
 struct remote_address *, show socket type, address, port: dgram 0.0.0.0:88
-struct remote_address *, show socket type, address, port: socktype1234 AF_UNSPEC
-struct remote_address *, show socket type, address, port: socktype1234 af5678
+struct remote_address *, show socket type, address, port: transport1234 AF_UNSPEC
+struct remote_address *, show socket type, address, port: transport1234 af5678
 krb5_data *, display as counted string: example.data
 krb5_data *, display as counted string: (null)
 krb5_data *, display as hex bytes: 6578616D706C652E64617461
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 525742c..8319a86 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -197,12 +197,12 @@ trace_format(krb5_context context, const char *fmt, va_list ap)
             }
         } else if (strcmp(tmpbuf, "raddr") == 0) {
             ra = va_arg(ap, struct remote_address *);
-            if (ra->type == SOCK_DGRAM)
+            if (ra->transport == UDP)
                 k5_buf_add(&buf, "dgram");
-            else if (ra->type == SOCK_STREAM)
+            else if (ra->transport == TCP)
                 k5_buf_add(&buf, "stream");
             else
-                k5_buf_add_fmt(&buf, "socktype%d", ra->type);
+                k5_buf_add_fmt(&buf, "transport%d", ra->transport);
 
             if (getnameinfo((struct sockaddr *)&ra->saddr, ra->len,
                             addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf),


More information about the cvs-krb5 mailing list