diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-01-30 07:22:16 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:09:23 -0500 |
commit | a0ab1f7afda62964d480af9dc26e60a38d1350e0 (patch) | |
tree | c078770b99b8a2972ff71cd090acb2ebfe0d7a60 /source4/libcli/ldap | |
parent | 003fbe7f6472ed433bc5495b422f3e6d5278da17 (diff) | |
download | samba-a0ab1f7afda62964d480af9dc26e60a38d1350e0.tar.gz samba-a0ab1f7afda62964d480af9dc26e60a38d1350e0.tar.bz2 samba-a0ab1f7afda62964d480af9dc26e60a38d1350e0.zip |
r5107: moved the horrible ldap socket code, and the even worse
asn1-tied-to-blocking-sockets code into the ldap client and torture
suite, and out of the generic libs, so nobody else is tempted to use
it for any new code.
(This used to be commit 39d1ced21baeca40d1fca62ba65243ca8f15757e)
Diffstat (limited to 'source4/libcli/ldap')
-rw-r--r-- | source4/libcli/ldap/ldap_client.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index c9e81ac28f..73099ec1be 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -29,6 +29,246 @@ #include "asn_1.h" #include "dlinklist.h" + + +/**************************************************************************** + Check the timeout. +****************************************************************************/ +static BOOL timeout_until(struct timeval *timeout, + const struct timeval *endtime) +{ + struct timeval now; + + GetTimeOfDay(&now); + + if ((now.tv_sec > endtime->tv_sec) || + ((now.tv_sec == endtime->tv_sec) && + (now.tv_usec > endtime->tv_usec))) + return False; + + timeout->tv_sec = endtime->tv_sec - now.tv_sec; + timeout->tv_usec = endtime->tv_usec - now.tv_usec; + return True; +} + + +/**************************************************************************** + Read data from the client, reading exactly N bytes, with timeout. +****************************************************************************/ +static ssize_t read_data_until(int fd,char *buffer,size_t N, + const struct timeval *endtime) +{ + ssize_t ret; + size_t total=0; + + while (total < N) { + + if (endtime != NULL) { + fd_set r_fds; + struct timeval timeout; + int res; + + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + + if (!timeout_until(&timeout, endtime)) + return -1; + + res = sys_select(fd+1, &r_fds, NULL, NULL, &timeout); + if (res <= 0) + return -1; + } + + ret = sys_read(fd,buffer + total,N - total); + + if (ret == 0) { + DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) )); + return 0; + } + + if (ret == -1) { + DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) )); + return -1; + } + total += ret; + } + return (ssize_t)total; +} + + +/**************************************************************************** + Write data to a fd with timeout. +****************************************************************************/ +static ssize_t write_data_until(int fd,char *buffer,size_t N, + const struct timeval *endtime) +{ + size_t total=0; + ssize_t ret; + + while (total < N) { + + if (endtime != NULL) { + fd_set w_fds; + struct timeval timeout; + int res; + + FD_ZERO(&w_fds); + FD_SET(fd, &w_fds); + + if (!timeout_until(&timeout, endtime)) + return -1; + + res = sys_select(fd+1, NULL, &w_fds, NULL, &timeout); + if (res <= 0) + return -1; + } + + ret = sys_write(fd,buffer + total,N - total); + + if (ret == -1) { + DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) )); + return -1; + } + if (ret == 0) + return total; + + total += ret; + } + return (ssize_t)total; +} + + + +static BOOL read_one_uint8(int sock, uint8_t *result, struct asn1_data *data, + const struct timeval *endtime) +{ + if (read_data_until(sock, result, 1, endtime) != 1) + return False; + + return asn1_write(data, result, 1); +} + +/* Read a complete ASN sequence (ie LDAP result) from a socket */ +static BOOL asn1_read_sequence_until(int sock, struct asn1_data *data, + const struct timeval *endtime) +{ + uint8_t b; + size_t len; + char *buf; + + ZERO_STRUCTP(data); + + if (!read_one_uint8(sock, &b, data, endtime)) + return False; + + if (b != 0x30) { + data->has_error = True; + return False; + } + + if (!read_one_uint8(sock, &b, data, endtime)) + return False; + + if (b & 0x80) { + int n = b & 0x7f; + if (!read_one_uint8(sock, &b, data, endtime)) + return False; + len = b; + while (n > 1) { + if (!read_one_uint8(sock, &b, data, endtime)) + return False; + len = (len<<8) | b; + n--; + } + } else { + len = b; + } + + buf = talloc_size(NULL, len); + if (buf == NULL) + return False; + + if (read_data_until(sock, buf, len, endtime) != len) + return False; + + if (!asn1_write(data, buf, len)) + return False; + + talloc_free(buf); + + data->ofs = 0; + + return True; +} + + + +/**************************************************************************** + create an outgoing socket. timeout is in milliseconds. + **************************************************************************/ +static int open_socket_out(int type, struct ipv4_addr *addr, int port, int timeout) +{ + struct sockaddr_in sock_out; + int res,ret; + int connect_loop = 250; /* 250 milliseconds */ + int loops = (timeout) / connect_loop; + + /* create a socket to write to */ + res = socket(PF_INET, type, 0); + if (res == -1) + { DEBUG(0,("socket error\n")); return -1; } + + if (type != SOCK_STREAM) return(res); + + memset((char *)&sock_out,'\0',sizeof(sock_out)); + putip((char *)&sock_out.sin_addr,(char *)addr); + + sock_out.sin_port = htons( port ); + sock_out.sin_family = PF_INET; + + /* set it non-blocking */ + set_blocking(res,False); + + DEBUG(3,("Connecting to %s at port %d\n", sys_inet_ntoa(*addr),port)); + + /* and connect it to the destination */ +connect_again: + ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out)); + + /* Some systems return EAGAIN when they mean EINPROGRESS */ + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN) && loops--) { + msleep(connect_loop); + goto connect_again; + } + + if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || + errno == EAGAIN)) { + DEBUG(1,("timeout connecting to %s:%d\n", sys_inet_ntoa(*addr),port)); + close(res); + return -1; + } + +#ifdef EISCONN + if (ret < 0 && errno == EISCONN) { + errno = 0; + ret = 0; + } +#endif + + if (ret < 0) { + DEBUG(2,("error connecting to %s:%d (%s)\n", + sys_inet_ntoa(*addr),port,strerror(errno))); + close(res); + return -1; + } + + /* set it blocking again */ + set_blocking(res,True); + + return res; +} + #if 0 static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn, const char *base, |