[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
Re: FW: ldapsearch problems (ITS#2490)
Like Howard noted in a previous post, I am bit concerned by the
"rewrite" approach here. The question I guess is whether or
not a simple patch could fix the problem or not. I haven't
yet thought about, if a rewrite was needed, whether or not
this would be most appropriate rewrite. If we're going to
rewrite things, there may be other problems we should consider.
Anyways, I haven't yet examined the patch yet. I first need
to understand the underlying problem which let to the creation
of the patch. I'll try to find some time tomorrow to do that.
Kurt
At 05:35 PM 5/20/2003, you wrote:
>I'm a bit pressed for time, can someone else look this over/comment?
>
> -- Howard Chu
> Chief Architect, Symas Corp. Director, Highland Sun
> http://www.symas.com http://highlandsun.com/hyc
> Symas: Premier OpenSource Development and Support
>
>-----Original Message-----
>From: Patrick Dreyer, SY-UCP [mailto:Patrick.Dreyer@swisscom-ucp.com]
>Sent: Tuesday, May 20, 2003 1:32 AM
>To: Howard Chu; openldap-its@OpenLDAP.org
>Subject: RE: ldapsearch problems (ITS#2490)
>
>
>Hi
>
>> Thanks for this, but it has some obvious problems. Setting errno when
>read() returns 0 is incorrect behavior. This will
>> cause ber_get_next() to treat an EOF/close as a retry.
>
>Yes, you're right. I corrected that in my second solution below.
>
>> Also, even if your patch were valid, you have used C++ style comments in
>it, which is not acceptable.
>
>Sorry for this. It seams the MS compiler is too dump to tell me that, beside
>I should have known it.
>
>As I told you, I want to optimize my first solution and below it is, hopping
>my comments are kind of help...
>Give me your feedpack one more time please and tell me if I should have
>forgotten to take out any C++ code.
>
>Patrick
>
>
>====================================================
>
>/*
> * A rewrite of ber_get_next that can safely be called multiple times for the
> * same packet and will simply continue where it stopped last time until a
>full
> * packet is read.
> *
> * Any ber element looks like this: tag length contents.
> * Assuming everything's ok, we return the tag byte (we can assume a single
> * byte), return the length in len, and the rest of the undecoded element in
> * buf.
> *
> * Assumptions:
> * 1) multi-byte tag and len at most 32 bits wide
> * 2) definite lengths
> * 3) primitive encodings used whenever possible
> *
> * The first few bytes of the message are read to check for multi-byte tags
>and
> * lengths. These bytes are temporarily stored in the ber_usertag and ber_buf
> * fields, called temp buffer, of the berelement until tag/length parsing is
> * complete.
> * ber_ptr is used to indicate if we are parsing the tag or the length and if
> * they are multi-byte to know which byte we are reading.
> * ber_rwptr points to the next byte in the temp buffer and ber_end points to
> * the byte one after the last in the temp buffer.
> *
> * The diagram below shows you how it looks like if we could fill the whole
> * temp buffer before we begin parsing the tag:
> *
> * +-------------+-------------+-------------+-------------+-------------+---
> * | ber_tag | ber_len | ber_usertag | ber_buf | ber_ptr | ..
> * +-------------+-------------+-------------+-------------+-------------+--
> * ^ ^ ^
> * ber_ptr ber_rwptr ber_end
> *
> *
> * The following diagram shows you how it could look like if we parsed the
>tag
> * and the length is a multi-byte two bytes long:
> *
> * +-------------+-------------+-------------+-------------+-------------+---
> * | ber_tag | ber_len | ber_usertag | ber_buf | ber_ptr | ..
> * +-------------+-------------+-------------+-------------+-------------+--
> * ^ ^ ^
> * ber_ptr ber_rwptr ber_end
> *
> *
> * After tag/length parsing, any leftover bytes and the rest of the message
>is
> * copied into ber_buf.
> */
>ber_tag_t
>ber_get_next(
> Sockbuf *sb,
> ber_len_t *len,
> BerElement *ber )
>{
> assert( sb != NULL );
> assert( len != NULL );
> assert( ber != NULL );
>
> assert( SOCKBUF_VALID( sb ) );
> assert( LBER_VALID( ber ) );
>
> #ifdef NEW_LOGGING
> LDAP_LOG( BER, ENTRY, "ber_get_next: enter\n", 0, 0, 0 );
> #else
> ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, "ber_get_next\n" );
> #endif
>
> /* we start reading the next element */
> if (ber->ber_rwptr == NULL) {
> #if 0
> /* XXYYZ - dtest does like this assert. */
> assert( ber->ber_buf == NULL );
> #endif
> ber->ber_tag = 0;
> ber->ber_len = 0;
> ber->ber_ptr = (char*)&ber->ber_tag;
> ber->ber_end = (char*)&ber->ber_usertag;
> ber->ber_rwptr = (char*)&ber->ber_usertag;
> }
>
> /* parse the tag and length */
> if ((char*)&ber->ber_tag <= ber->ber_ptr
> && ber->ber_ptr < (char*)&ber->ber_usertag) {
> /* read more data if we have free space in the temp buffer */
> {
> ber_len_t sblen = (char*)&ber->ber_ptr - ber->ber_end;
>
> /* jump to the beginning of the temp buffer if it is empty and we
> reached the end */
> if (sblen == 0 && ber->ber_rwptr == ber->ber_end) {
> ber->ber_end = (char*)&ber->ber_usertag;
> sblen = (char*)&ber->ber_ptr - ber->ber_end;
> }
>
> /* read as much bytes as we have space left in the temp buffer */
> if (sblen > 0) {
> sblen = ber_int_sb_read(sb, ber->ber_end, sblen);
> if (sblen <= 0)
> return LBER_DEFAULT;
>
> ber->ber_end += sblen;
>
> /* be sure we have at least one available byte in the temp buffer */
> if (ber->ber_rwptr == ber->ber_end) {
> #if defined(EWOULDBLOCK)
> errno = EWOULDBLOCK;
> #elif defined(EAGAIN)
> errno = EAGAIN;
> #endif
> return LBER_DEFAULT;
> }
> }
> } /* read more data */
>
> /* parse the first tag byte */
> if (ber->ber_ptr == (char*)&ber->ber_tag) {
> ber->ber_tag = *ber->ber_rwptr;
>
> /* tag is only one byte long */
> if ((*ber->ber_rwptr++ & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK)
> ber->ber_ptr = (char*)&ber->ber_len;
> else
> ++ber->ber_ptr;
> }
>
> /* parse more tag bytes */
> if (ber->ber_ptr < (char*)&ber->ber_len) {
> do {
> /* be sure the temp buffer is not empty */
> if (ber->ber_rwptr == ber->ber_end) {
> #if defined(EWOULDBLOCK)
> errno = EWOULDBLOCK;
> #elif defined(EAGAIN)
> errno = EAGAIN;
> #endif
> return LBER_DEFAULT;
> }
>
> /* be sure the tag is not too big */
> if (ber->ber_ptr++ == (char*)&ber->ber_len) {
> errno = ERANGE;
> return LBER_DEFAULT;
> }
>
> ber->ber_tag <<= 8;
> ber->ber_tag |= *ber->ber_rwptr;
> } while ((*ber->ber_rwptr++ & LBER_MORE_TAG_MASK) ==
>LBER_MORE_TAG_MASK);
>
> ber->ber_ptr = (char*)&ber->ber_len;
> } /* parse more tag bytes */
>
> /* parse the first length byte */
> if (ber->ber_ptr == (char*)&ber->ber_len) {
> /* be sure the temp buffer is not empty */
> if (ber->ber_rwptr == ber->ber_end) {
> #if defined(EWOULDBLOCK)
> errno = EWOULDBLOCK;
> #elif defined(EAGAIN)
> errno = EAGAIN;
> #endif
> return LBER_DEFAULT;
> }
>
> /* length is only one byte long */
> if ((*ber->ber_rwptr & 0x80) == 0) {
> ber->ber_len = *ber->ber_rwptr++;
> ber->ber_ptr = (char*)&ber->ber_usertag;
> }
> else {
> ber->ber_len = *ber->ber_rwptr++ & 0x7f;
>
> /* be sure the length is not too big */
> if (ber->ber_len > sizeof(ber->ber_len)) {
> errno = ERANGE;
> return LBER_DEFAULT;
> }
>
> ber->ber_ptr += sizeof(ber->ber_len) - ber->ber_len;
> }
> } /* parse the first length byte */
>
> /* parse more length bytes */
> for (; ber->ber_ptr < (char*)&ber->ber_usertag; ++ber->ber_ptr) {
> /* be sure the temp buffer is not empty */
> if (ber->ber_rwptr == ber->ber_end) {
> #if defined(EWOULDBLOCK)
> errno = EWOULDBLOCK;
> #elif defined(EAGAIN)
> errno = EAGAIN;
> #endif
> return LBER_DEFAULT;
> }
>
> ber->ber_len <<= 8;
> ber->ber_len |= *ber->ber_rwptr++;
> }
>
> /* be sure we have to read at least one byte of data */
> if (ber->ber_len == 0) {
> errno = ERANGE;
> return LBER_DEFAULT;
> }
>
> /* be sure sockbuf_max_incoming didn't exceed */
> if (sb->sb_max_incoming > 0 && ber->ber_len > sb->sb_max_incoming) {
> #ifdef NEW_LOGGING
> LDAP_LOG( BER, ERR,
> "ber_get_next: sockbuf_max_incoming exceeded "
> "(%d > %d)\n", ber->ber_len, sb->sb_max_incoming, 0 );
> #else
> ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
> "ber_get_next: sockbuf_max_incoming exceeded "
> "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
> #endif
> errno = ERANGE;
> return LBER_DEFAULT;
> }
>
> /* allocate data buffer */
> {
> char* buffer;
> ber_len_t left_over;
>
> buffer = LBER_MALLOC(ber->ber_len + 1);
> if (buffer == NULL)
> return LBER_DEFAULT;
>
> /* copy left over bytes from temp to data buffer */
> left_over = ber->ber_end - ber->ber_rwptr;
> if (left_over > 0)
> AC_MEMCPY(buffer, ber->ber_rwptr, left_over);
>
> ber->ber_buf = buffer;
> ber->ber_ptr = buffer;
> ber->ber_end = buffer + ber->ber_len;
> ber->ber_rwptr = buffer + left_over;
> }
> } /* parse the tag and length */
>
> /* read the data */
> if (ber->ber_buf <= ber->ber_rwptr && ber->ber_rwptr < ber->ber_end) {
> ber_len_t sblen = ber_int_sb_read(sb, ber->ber_rwptr,
> ber->ber_end - ber->ber_rwptr);
> if (sblen <= 0)
> return LBER_DEFAULT;
>
> ber->ber_rwptr += sblen;
>
> /* more data */
> if (ber->ber_rwptr < ber->ber_end) {
> #if defined(EWOULDBLOCK)
> errno = EWOULDBLOCK;
> #elif defined(EAGAIN)
> errno = EAGAIN;
> #endif
> return LBER_DEFAULT;
> }
>
> /* the whole element is read if we reach this point */
> ber->ber_rwptr = NULL;
> *len = ber->ber_len;
>
> /* dump if debugging is switched on */
> if (ber->ber_debug) {
> #ifdef NEW_LOGGING
> LDAP_LOG( BER, DETAIL1,
> "ber_get_next: tag 0x%lx len %ld\n",
> ber->ber_tag, ber->ber_len, 0 );
> if (LDAP_LOGS_TEST(BER, DETAIL2))
> BER_DUMP(( "liblber", LDAP_LEVEL_DETAIL2, ber, 1 ));
> #else
> ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
> "ber_get_next: tag 0x%lx len %ld contents:\n",
> ber->ber_tag, ber->ber_len );
> ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
> #endif
> }
>
> return ber->ber_tag;
> }
>
> /* the ber structure is messed up if we reach this point */
> assert( 0 );
> return LBER_DEFAULT;
>} /* ber_get_next */