diff --git a/source/lib/system.c b/source/lib/system.c index eabb6d6..48ecf90 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -142,6 +142,31 @@ ssize_t sys_write(int fd, const void *buf, size_t count) } /******************************************************************* +A writev wrapper that will deal with EINTR. +********************************************************************/ + +ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + +#if 0 + /* Try to confuse write_data_iov a bit */ + if ((random() % 5) == 0) { + return sys_write(fd, iov[0].iov_base, iov[0].iov_len); + } + if (iov[0].iov_len > 1) { + return sys_write(fd, iov[0].iov_base, + (random() % (iov[0].iov_len-1)) + 1); + } +#endif + + do { + ret = writev(fd, iov, iovcnt); + } while (ret == -1 && errno == EINTR); + return ret; +} + +/******************************************************************* A pread wrapper that will deal with EINTR and 64-bit file offsets. ********************************************************************/ diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c index e64b003..9c37e0c 100644 --- a/source/lib/util_sock.c +++ b/source/lib/util_sock.c @@ -1037,40 +1037,109 @@ NTSTATUS read_data(int fd, char *buffer, size_t N) } /**************************************************************************** - Write data to a fd. + Write all data from an iov array ****************************************************************************/ -ssize_t write_data(int fd, const char *buffer, size_t N) +ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) { - size_t total=0; - ssize_t ret; - char addr[INET6_ADDRSTRLEN]; + int i; + size_t to_send; + ssize_t thistime; + size_t sent; + struct iovec *iov_copy, *iov; - while (total < N) { - ret = sys_write(fd,buffer + total,N - total); + to_send = 0; + for (i=0; i 0) { + if (thistime < iov[0].iov_len) { + char *new_base = + (char *)iov[0].iov_base + thistime; + iov[0].iov_base = new_base; + iov[0].iov_len -= thistime; + break; } - return -1; + thistime -= iov[0].iov_len; + iov += 1; + iovcnt -= 1; } - if (ret == 0) { - return total; + thistime = sys_writev(fd, iov, iovcnt); + if (thistime <= 0) { + break; } + sent += thistime; + } + + TALLOC_FREE(iov_copy); + return sent; +} + +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +/**************************************************************************** + Write data to a fd. +****************************************************************************/ + +ssize_t write_data(int fd, const char *buffer, size_t N) +{ + ssize_t ret; + struct iovec iov; + + iov.iov_base = CONST_DISCARD(char *, buffer); + iov.iov_len = N; + + ret = write_data_iov(fd, &iov, 1); + if (ret >= 0) { + return ret; + } - total += ret; + if (fd == get_client_fd()) { + char addr[INET6_ADDRSTRLEN]; + /* + * Try and give an error message saying what client failed. + */ + DEBUG(0, ("write_data: write failure in writing to client %s. " + "Error %s\n", get_peer_addr(fd,addr,sizeof(addr)), + strerror(errno))); + } else { + DEBUG(0,("write_data: write failure. Error = %s\n", + strerror(errno) )); } - return (ssize_t)total; + + return -1; } /**************************************************************************** diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c index d6d26e4..a8c3fad 100644 --- a/source/libsmb/clientgen.c +++ b/source/libsmb/clientgen.c @@ -316,6 +316,7 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, size_t len = SVAL(cli->outbuf,smb_vwv11) + 4; size_t nwritten=0; ssize_t ret; + struct iovec iov[2]; /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ if (cli->fd == -1) { @@ -327,33 +328,19 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, return false; } - while (nwritten < len) { - ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", - (int)len,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; - } + iov[0].iov_base = cli->outbuf; + iov[0].iov_len = len; + iov[1].iov_base = CONST_DISCARD(char *, p); + iov[1].iov_len = extradata; - /* Now write the extra data. */ - nwritten=0; - while (nwritten < extradata) { - ret = write_socket(cli->fd,p+nwritten,extradata - nwritten); - if (ret <= 0) { - close(cli->fd); - cli->fd = -1; - cli->smb_rw_error = SMB_WRITE_ERROR; - DEBUG(0,("Error writing %d extradata " - "bytes to client. %d (%s)\n", - (int)extradata,(int)ret, strerror(errno) )); - return false; - } - nwritten += ret; + nwritten = write_data_iov(cli->fd, iov, 2); + if (nwritten < (len + extradata)) { + close(cli->fd); + cli->fd = -1; + cli->smb_rw_error = SMB_WRITE_ERROR; + DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", + (int)(len+extradata), (int)ret, strerror(errno))); + return false; } /* Increment the mid so we can tell between responses. */