[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
RE: ldapsearch problems (ITS#2490)
> A fix has been committed to CVS HEAD. Please try the attached patch to
libraries/liblber/io.c and let us know your results.
It doesn't :-(
Below you find my solution for ber_get_next(), which works but is not
optimized yet to read multiple bytes at once during reading the tag and
length instead reading one after one.
As you'll see, the big difference is, that if I do not process it as a
failure if ber_int_sb_read() returns with zero. And my solution doesn't
have any problems to leave and being recalled if no data was currently
available.
Please try my solution and give me some feedpack - only positiv ones are
welcome :-))
Patrick
================================================================
ber_tag_t
ber_get_next(
Sockbuf *sb,
ber_len_t *len,
BerElement *ber )
{
ber_slen_t sblen;
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
/*
* 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) tag and len at most 32 bits wide
* 2) definite lengths
* 3) primitive encodings used whenever possible
*
* The code also handles multi-byte tags. 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_tag, ber_len, and ber_usertag fields
of the
* berelement until tag/len parsing is complete. After this parsing,
any
* leftover bytes and the rest of the message are copied into the
ber_buf.
*/
// 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_usertag = 0;
ber->ber_rwptr = (char*)&ber->ber_tag;
}
// reading tag as long as ber_rwptr points inside ber_tag
if ((char*)&ber->ber_tag <= ber->ber_rwptr
&& ber->ber_rwptr < (char*)&ber->ber_len) {
// first byte
if (ber->ber_usertag == 0) {
sblen = ber_int_sb_read(sb, ber->ber_rwptr, 1);
if (sblen <= 0) {
if (sblen == 0) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
}
return LBER_DEFAULT;
}
// is only one byte long
if ((*ber->ber_rwptr & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK) {
ber->ber_tag = *ber->ber_rwptr;
ber->ber_usertag = 0;
ber->ber_rwptr = (char*)&ber->ber_len;
}
// otherwise multi byte
else
ber->ber_usertag = *ber->ber_rwptr++;
} // first byte
// more bytes
if (ber->ber_usertag != 0) {
do {
// tag too big
if (ber->ber_rwptr == (char*)&ber->ber_len) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
return LBER_DEFAULT;
}
sblen = ber_int_sb_read(sb, ber->ber_rwptr, 1);
if (sblen <= 0) {
if (sblen == 0) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
}
return LBER_DEFAULT;
}
ber->ber_usertag <<= 8;
ber->ber_usertag |= *ber->ber_rwptr;
} while((*ber->ber_rwptr++ & LBER_MORE_TAG_MASK) ==
LBER_MORE_TAG_MASK);
ber->ber_tag = ber->ber_usertag;
ber->ber_usertag = 0;
ber->ber_rwptr = (char*)&ber->ber_len;
}
} // reading tag
// reading length as long as ber_rwptr points inside ber_len
if ((char*)ber->ber_len <= ber->ber_rwptr
&& ber->ber_rwptr < (char*)&ber->ber_usertag) {
// first byte
if (ber->ber_usertag == 0) {
sblen = ber_int_sb_read(sb, ber->ber_rwptr, 1);
if (sblen <= 0) {
if (sblen == 0) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
}
return LBER_DEFAULT;
}
// is only one byte long
if ((*ber->ber_rwptr & 0x80) == 0) {
ber->ber_len = *ber->ber_rwptr;
ber->ber_usertag = 0;
}
// otherwise multi byte
else {
ber->ber_usertag = *ber->ber_rwptr++ & 0x7f;
// length too big
if (ber->ber_usertag > sizeof(ber->ber_len)) {
errno = ERANGE;
return LBER_DEFAULT;
}
}
} // first byte
// more bytes
for (; ber->ber_usertag > 0; --ber->ber_usertag, ++ber->ber_rwptr) {
char buf;
sblen = ber_int_sb_read(sb, &buf, 1);
if (sblen <= 0) {
if (sblen == 0) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
}
return LBER_DEFAULT;
}
ber->ber_len <<= 8;
ber->ber_len |= buf;
} // more bytes
// 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;
}
ber->ber_rwptr = (char*)&ber->ber_usertag;
} // reading length
// allocate buffer
if (ber->ber_buf == NULL) {
ber->ber_buf = LBER_MALLOC(ber->ber_len+1);
if (ber->ber_buf == NULL)
return LBER_DEFAULT;
ber->ber_ptr = ber->ber_buf;
ber->ber_end = ber->ber_buf + ber->ber_len;
ber->ber_rwptr = ber->ber_buf;
}
// reading data
if (ber->ber_buf <= ber->ber_rwptr && ber->ber_rwptr < ber->ber_end) {
sblen = ber_int_sb_read(sb, ber->ber_rwptr, ber->ber_end -
ber->ber_rwptr);
if (sblen <= 0) {
if (sblen == 0) {
#if defined(EWOULDBLOCK)
errno = EWOULDBLOCK;
#elif defined(EAGAIN)
errno = EAGAIN;
#endif
}
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;
}
// whole element is read
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