]> git.sur5r.net Git - openldap/commitdiff
Rewrote ber_get_next, fixed byte-order dependency on ber_tag and optimized
authorHoward Chu <hyc@openldap.org>
Sun, 13 Jan 2002 03:00:45 +0000 (03:00 +0000)
committerHoward Chu <hyc@openldap.org>
Sun, 13 Jan 2002 03:00:45 +0000 (03:00 +0000)
libraries/liblber/io.c
libraries/liblber/lber-int.h

index 6cc1505c5a4bcb9958a3862273ee86aa71ff40cd..23fd80cbf41e6d44d105947764964d6eec16ed58 100644 (file)
 
 #include "lber-int.h"
 
-static ber_slen_t
-BerRead(
-       Sockbuf *sb,
-       unsigned char *buf,
-       ber_len_t len )
-{
-       ber_slen_t      c;
-       ber_slen_t      nread = 0;
-
-       assert( sb != NULL );
-       assert( buf != NULL );
-
-       assert( SOCKBUF_VALID( sb ) );
-
-       while ( len > 0 ) {
-               if ( (c = ber_int_sb_read( sb, buf, len )) <= 0 ) {
-                       if ( nread > 0 )
-                               break;
-                       return( c );
-               }
-               buf+=c;
-               nread+=c;
-               len-=c;
-       }
-
-       return( nread );
-}
-
 ber_slen_t
 ber_read(
        BerElement *ber,
@@ -476,131 +448,126 @@ ber_get_next(
         *      2) definite lengths
         *      3) primitive encodings used whenever possible
         */
-       
+
        if (ber->ber_rwptr == NULL) {
                /* XXYYZ
                 * dtest does like this assert.
                 */
                /* assert( ber->ber_buf == NULL ); */
-               ber->ber_rwptr = (char *) &ber->ber_tag;
+               ber->ber_rwptr = (char *) &ber->ber_len-1;
+               ber->ber_ptr = ber->ber_rwptr;
                ber->ber_tag = 0;
        }
 
-#undef PTR_IN_VAR
-#define PTR_IN_VAR( ptr, var ) \
-       (((ptr)>=(char *) &(var)) && ((ptr)< (char *) &(var)+sizeof(var)))
-       
-       if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) {
-               if (ber->ber_rwptr == (char *) &ber->ber_tag) {
-                       if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0)
-                               return LBER_DEFAULT;
+       while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr <
+               (char *)(&ber->ber_usertag + 1)) {
+               int i;
+               char buf[sizeof(ber->ber_len)-1];
+               ber_len_t tlen = 0;
 
-                       if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK)
-                               != LBER_BIG_TAG_MASK)
-                       {
-                               ber->ber_tag = ber->ber_rwptr[0];
-                               ber->ber_rwptr = (char *) &ber->ber_usertag;
-                               goto get_lenbyte;
-                       }
-                       ber->ber_rwptr++;
+               if ((i=ber_int_sb_read( sb, ber->ber_rwptr,
+                       (char *)(&ber->ber_usertag+1)-ber->ber_rwptr))<=0) {
+                       return LBER_DEFAULT;
                }
-               do {
-                       /* reading the tag... */
-                       if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0) {
-                               return LBER_DEFAULT;
-                       }
 
-                       if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) {
-                               ber->ber_tag>>=sizeof(ber->ber_tag) -
-                                 ((char *) &ber->ber_tag - ber->ber_rwptr);
-                               ber->ber_rwptr = (char *) &ber->ber_usertag;
-                               goto get_lenbyte;
+               ber->ber_rwptr += i;
+
+               /* We got at least one byte, try to parse the tag. */
+               if (ber->ber_ptr == (char *)&ber->ber_len-1) {
+                       ber_tag_t tag;
+                       unsigned char *p = (unsigned char *)ber->ber_ptr;
+                       tag = *p++;
+                       if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) {
+                               for (i=1; (char *)p<ber->ber_rwptr; i++,p++) {
+                                       tag <<= 8;
+                                       tag |= *p;
+                                       if (!(*p & LBER_MORE_TAG_MASK))
+                                               break;
+                                       /* Is the tag too big? */
+                                       if (i == sizeof(ber_tag_t)-1) {
+                                               errno = ERANGE;
+                                               return LBER_DEFAULT;
+                                       }
+                               }
+                               /* Did we run out of bytes? */
+                               if ((char *)p == ber->ber_rwptr) {
+                                       return LBER_DEFAULT;
+                               }
+                               p++;
                        }
-               } while( PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag ));
-
-               errno = ERANGE; /* this is a serious error. */
-               return LBER_DEFAULT;
-       }
-
-get_lenbyte:
-       if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
-               unsigned char c;
-               if (ber_int_sb_read( sb, (char *) &c, 1)<=0) {
-                       return LBER_DEFAULT;
+                       ber->ber_tag = tag;
+                       ber->ber_ptr = (char *)p;
                }
 
-               if (c & 0x80U) {
-                       int len = c & 0x7fU;
-                       if ( (len==0) || ( len>sizeof( ber->ber_len ) ) ) {
+               /* Now look for the length */
+               if (*ber->ber_ptr & 0x80) {     /* multi-byte */
+                       int llen = *(unsigned char *)ber->ber_ptr++ & 0x7f;
+                       if (llen > sizeof(ber_len_t)) {
                                errno = ERANGE;
                                return LBER_DEFAULT;
                        }
-
-                       ber->ber_rwptr = (char *) &ber->ber_len +
-                               sizeof(ber->ber_len) - len;
-                       ber->ber_len = 0;
-
+                       /* Not enough bytes? */
+                       if (ber->ber_rwptr - ber->ber_ptr < llen) {
+                               return LBER_DEFAULT;
+                       }
+                       for (i=0; i<llen && ber->ber_ptr<ber->ber_rwptr; i++,ber->ber_ptr++) {
+                               tlen <<=8;
+                               tlen |= *(unsigned char *)ber->ber_ptr;
+                       }
                } else {
-                       ber->ber_len = c;
-                       goto fill_buffer;
+                       tlen = *(unsigned char *)ber->ber_ptr++;
                }
-       }
-
-       if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) {
-               unsigned char netlen[sizeof(ber_len_t)];
-
-               ber_slen_t res;
-               ber_slen_t to_go;
-               to_go = (char *) &ber->ber_len + sizeof( ber->ber_len ) -
-                       ber->ber_rwptr;
-               assert( to_go > 0 );
-
-               res = BerRead( sb, netlen, to_go );
-               if (res <= 0) {
-                       return LBER_DEFAULT;
+               /* Are there leftover data bytes inside ber->ber_len? */
+               if (ber->ber_ptr < (char *)&ber->ber_usertag) {
+                       i = (char *)&ber->ber_usertag - ber->ber_ptr;
+                       AC_MEMCPY(buf, ber->ber_ptr, i);
+                       ber->ber_ptr += i;
+               } else {
+                       i = 0;
                }
-               ber->ber_rwptr += res;
+               ber->ber_len = tlen;
 
-               /* convert length. */
-               for( to_go = 0; to_go < res ; to_go++ ) {
-                       ber->ber_len <<= 8;
-                       ber->ber_len |= netlen[to_go];
-               }
+               /* now fill the buffer. */
 
-               if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) {
+               /* make sure length is reasonable */
+               if ( ber->ber_len == 0 ) {
+                       errno = ERANGE;
                        return LBER_DEFAULT;
-               }
-       }
-
-fill_buffer:   
-       /* now fill the buffer. */
-
-       /* make sure length is reasonable */
-       if ( ber->ber_len == 0 ) {
-               errno = ERANGE;
-               return LBER_DEFAULT;
-       } else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
+               } else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
 #ifdef NEW_LOGGING
-               LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, 
-                       "ber_get_next: sockbuf_max_incoming limit hit "
-                       "(%d > %d)\n", ber->ber_len, sb->sb_max_incoming ));
+                       LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, 
+                               "ber_get_next: sockbuf_max_incoming limit hit "
+                               "(%d > %d)\n", ber->ber_len, sb->sb_max_incoming ));
 #else
-               ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
-                       "ber_get_next: sockbuf_max_incoming limit hit "
-                       "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
+                       ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
+                               "ber_get_next: sockbuf_max_incoming limit hit "
+                               "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
 #endif
-               errno = ERANGE;
-               return LBER_DEFAULT;
-       }
+                       errno = ERANGE;
+                       return LBER_DEFAULT;
+               }
 
-       if (ber->ber_buf==NULL) {
-               ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len + 1 );
                if (ber->ber_buf==NULL) {
-                       return LBER_DEFAULT;
+                       ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len + 1 );
+                       if (ber->ber_buf==NULL) {
+                               return LBER_DEFAULT;
+                       }
+                       ber->ber_end = ber->ber_buf + ber->ber_len;
+                       if (i) {
+                               AC_MEMCPY(ber->ber_buf, buf, i);
+                       }
+                       if (ber->ber_ptr < ber->ber_rwptr) {
+                               AC_MEMCPY(ber->ber_buf + i, ber->ber_ptr, ber->ber_rwptr-
+                                       ber->ber_ptr);
+                               i += ber->ber_rwptr - ber->ber_ptr;
+                       }
+                       ber->ber_ptr = ber->ber_buf;
+                       ber->ber_usertag = 0;
+                       if (i == ber->ber_len) {
+                               goto done;
+                       }
+                       ber->ber_rwptr = ber->ber_buf + i;
                }
-               ber->ber_rwptr = ber->ber_buf;
-               ber->ber_ptr = ber->ber_buf;
-               ber->ber_end = ber->ber_buf + ber->ber_len;
        }
 
        if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
@@ -623,7 +590,7 @@ fill_buffer:
 #endif                 
                        return LBER_DEFAULT;
                }
-               
+done:
                ber->ber_rwptr = NULL;
                *len = ber->ber_len;
                if ( ber->ber_debug ) {
index 800f7444f54c5399278fb4e4bddf82affdf25032..14f02ca555a9d7df24f8ddef18ef103c24d1652d 100644 (file)
@@ -69,10 +69,10 @@ struct berelement {
 #define ber_options            ber_opts.lbo_options
 #define ber_debug              ber_opts.lbo_debug
 
-       ber_tag_t       ber_usertag;
-
+       /* Do not change the order of these 3 fields! see ber_get_next */
        ber_tag_t       ber_tag;
        ber_len_t       ber_len;
+       ber_tag_t       ber_usertag;
 
        char            *ber_buf;
        char            *ber_ptr;