[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
RE: ldapsearch problems (ITS#2490)
- To: <openldap-devel@OpenLDAP.org>
- Subject: RE: ldapsearch problems (ITS#2490)
- From: "Patrick Dreyer, SY-UCP" <Patrick.Dreyer@swisscom-ucp.com>
- Date: Wed, 21 May 2003 09:11:06 +0200
- Content-class: urn:content-classes:message
- Thread-index: AcMfMzyLgpDIqT5lSf2TiUkab7XHuwAM/Y5Q
- Thread-topic: ldapsearch problems (ITS#2490)
Hi
Because I was growing up with C++ I didn't write plain C code. Howard
already gave me some feedback and I made some corrections. You'll find
the corrected version below.
Any feedback is welcome.
Patrick
> -----Original Message-----
> From: Howard Chu [mailto:hyc@highlandsun.com]
> Sent: Mittwoch, 21. Mai 2003 02:35
> To: openldap-devel@OpenLDAP.org
> Subject: FW: ldapsearch problems (ITS#2490)
>
>
> I'm a bit pressed for time, can someone else look this over/comment?
>
> -----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 = *(unsigned char*)ber->ber_rwptr;
/* tag is only one byte long */
if ((*(unsigned char*)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 |= *(unsigned char*)ber->ber_rwptr;
} while ((*(unsigned char*)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 ((*(unsigned char*)ber->ber_rwptr & 0x80) == 0) {
ber->ber_len = *(unsigned char*)ber->ber_rwptr++;
ber->ber_ptr = (char*)&ber->ber_usertag;
}
else {
ber->ber_len = *(unsigned char*)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 |= *(unsigned char*)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 (ber->ber_rwptr == ber->ber_end) {
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 */