Fix an additional multiple-write case noted by John, where sendauth
authorKen Raeburn <raeburn@mit.edu>
Thu, 15 Jan 2009 19:15:22 +0000 (19:15 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 15 Jan 2009 19:15:22 +0000 (19:15 +0000)
calls write_message twice in a row.

Add new function krb5int_write_messages, calls krb5_net_writev with
multiple messages (currently only two at a time).  Use it from
krb5_write_message and krb5_sendauth.

ticket: 6339

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21752 dc483132-0cff-0310-8789-dd5450dbe970

src/include/k5-int.h
src/lib/krb5/krb/sendauth.c
src/lib/krb5/os/write_msg.c

index 072a4d397aff27fbdc4330121ce1e3700a85884a..78b271065bb02befcaf085f2b97cc2481e56f7cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1989,1990,1991,1992,1993,1994,1995,2000,2001, 2003,2006,2007,2008 by the Massachusetts Institute of Technology,
+ * Copyright (C) 1989,1990,1991,1992,1993,1994,1995,2000,2001, 2003,2006,2007,2008,2009 by the Massachusetts Institute of Technology,
  * Cambridge, MA, USA.  All Rights Reserved.
  * 
  * This software is being provided to you, the LICENSEE, by the 
@@ -2594,6 +2594,7 @@ krb5int_server_decrypt_ticket_keyblock
 
 krb5_error_code krb5_read_message (krb5_context, krb5_pointer, krb5_data *);
 krb5_error_code krb5_write_message (krb5_context, krb5_pointer, krb5_data *);
+krb5_error_code krb5int_write_messages (krb5_context, krb5_pointer, krb5_data *, int);
 int krb5_net_read (krb5_context, int , char *, int);
 int krb5_net_write (krb5_context, int , const char *, int);
 
index 5b563430756da1a98d3149760c0b33f00f533a14..35684bebbe355a9fe43b06fd6c27805709474732 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lib/krb5/krb/sendauth.c
  *
- * Copyright 1991 by the Massachusetts Institute of Technology.
+ * Copyright 1991, 2009 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
 static const char sendauth_version[] = "KRB5_SENDAUTH_V1.0";
 
 krb5_error_code KRB5_CALLCONV
-krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds)
+krb5_sendauth(krb5_context context, krb5_auth_context *auth_context,
+             krb5_pointer fd, char *appl_version, krb5_principal client,
+             krb5_principal server, krb5_flags ap_req_options,
+             krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache,
+             krb5_error **error, krb5_ap_rep_enc_part **rep_result,
+             krb5_creds **out_creds)
 {
        krb5_octet              result;
        krb5_creds              creds;
        krb5_creds               * credsp = NULL;
        krb5_creds               * credspout = NULL;
        krb5_error_code         retval = 0;
-       krb5_data               inbuf, outbuf;
+       krb5_data               inbuf, outbuf[2];
        int                     len;
        krb5_ccache             use_ccache = 0;
 
@@ -58,13 +63,11 @@ krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointe
         * over the length of the application version strings followed
         * by the string itself.  
         */
-       outbuf.length = strlen(sendauth_version) + 1;
-       outbuf.data = (char *) sendauth_version;
-       if ((retval = krb5_write_message(context, fd, &outbuf)))
-               return(retval);
-       outbuf.length = strlen(appl_version) + 1;
-       outbuf.data = appl_version;
-       if ((retval = krb5_write_message(context, fd, &outbuf)))
+       outbuf[0].length = strlen(sendauth_version) + 1;
+       outbuf[0].data = (char *) sendauth_version;
+       outbuf[1].length = strlen(appl_version) + 1;
+       outbuf[1].data = appl_version;
+       if ((retval = krb5int_write_messages(context, fd, outbuf, 2)))
                return(retval);
        /*
         * Now, read back a byte: 0 means no error, 1 means bad sendauth
@@ -154,15 +157,15 @@ krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointe
 
        if ((retval = krb5_mk_req_extended(context, auth_context,
                                           ap_req_options, in_data, credsp,
-                                          &outbuf)))
+                                          &outbuf[0])))
            goto error_return;
 
        /*
         * First write the length of the AP_REQ message, then write
         * the message itself.
         */
-       retval = krb5_write_message(context, fd, &outbuf);
-       free(outbuf.data);
+       retval = krb5_write_message(context, fd, &outbuf[0]);
+       free(outbuf[0].data);
        if (retval)
            goto error_return;
 
index 86b9275d7450f84227635dc2d43900335130761d..7586c9b8696a11183246a343eb34f4f7ff266b94 100644 (file)
 #include <errno.h>
 #include "os-proto.h"
 
+/* Try to write a series of messages with as few write(v) system calls
+   as possible, to avoid Nagle/DelayedAck problems.  Cheating here a
+   little -- I know the only cases we have at the moment will send one
+   or two messages in a call.  Sending more will work, but not as
+   efficiently.  */
 krb5_error_code
-krb5_write_message(krb5_context context, krb5_pointer fdp, krb5_data *outbuf)
+krb5int_write_messages(krb5_context context, krb5_pointer fdp, krb5_data *outbuf, int nbufs)
 {
-       krb5_int32      len;
-       int             fd = *( (int *) fdp);
-       sg_buf          sg[2];
+    int fd = *( (int *) fdp);
+
+    while (nbufs) {
+       int nbufs1;
+       sg_buf sg[4];
+       krb5_int32 len[2];
 
-       len = htonl(outbuf->length);
-       SG_SET(&sg[0], &len, 4);
-       SG_SET(&sg[1], outbuf->data, outbuf->length);
-       if (krb5int_net_writev(context, fd, sg, 2) < 0) {
+       if (nbufs > 1)
+           nbufs1 = 2;
+       else
+           nbufs1 = 1;
+       len[0] = htonl(outbuf[0].length);
+       SG_SET(&sg[0], &len[0], 4);
+       SG_SET(&sg[1], outbuf[0].data, outbuf[0].length);
+       if (nbufs1 == 2) {
+           len[1] = htonl(outbuf[1].length);
+           SG_SET(&sg[2], &len[1], 4);
+           SG_SET(&sg[3], outbuf[1].data, outbuf[1].length);
+       }
+       if (krb5int_net_writev(context, fd, sg, nbufs1 * 2) < 0) {
            return errno;
        }
-       return(0);
+       outbuf += nbufs1;
+       nbufs -= nbufs1;
+    }
+    return(0);
+}
+
+krb5_error_code
+krb5_write_message(krb5_context context, krb5_pointer fdp, krb5_data *outbuf)
+{
+    return krb5int_write_messages(context, fdp, outbuf, 1);
 }