[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#4603) non-blocking socket breaks `ber_flush'



Full_Name: David Lukacs
Version: 2.3.24
OS: Linux
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (194.237.142.21)


In case a backend uses sockets in non-blocking mode, and a ber message which
size is bigger than the socket buffer is to be written, `ber_flush' in
`libraries/liblber/io.c' mostly fails.
The following is a diff against `libraries/liblber/io.c' CVS version 1.111.2.2
I hope this helps someone.


--- libraries/liblber/io.c	2006-06-30 10:45:41.000000000 +0200
+++ libraries/liblber/io.c	2006-06-30 10:54:22.000000000 +0200
@@ -240,8 +240,39 @@
 		rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite );
 #endif
 		if ( rc <= 0 ) {
-			if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
-			return -1;
+			if (errno == EAGAIN) {
+				fd_set sdes;
+				FD_ZERO(&sdes);
+				FD_SET(sb->sb_fd, &sdes);
+				struct timeval tv;
+				tv.tv_sec = 1;
+				tv.tv_usec = 0;
+				int retval;
+				for (;;) {
+					retval = select(FD_SETSIZE, NULL, &sdes, NULL, &tv);
+					if (retval == -1) {
+						if (errno == EINTR) continue;
+						ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
+							"ber_flush: select error (errno==%d, sock_desc==%d)\n",
+							errno,
+							sb->sb_fd);
+						if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
+						return -1;
+					} else if (retval == 0) {
+						ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
+							"ber_flush: select timeout (%d sec)\n",
+							tv.tv_sec);
+						if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
+						return -1;
+					} else {
+						break;
+					}
+				}
+				continue;
+			} else {
+				if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
+				return -1;
+			}
 		}
 		towrite -= rc;
 		ber->ber_rwptr += rc;