about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstd/net_tcp.rs112
1 files changed, 77 insertions, 35 deletions
diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs
index dc310a32a52..b75ddebac8f 100644
--- a/src/libstd/net_tcp.rs
+++ b/src/libstd/net_tcp.rs
@@ -72,7 +72,7 @@ pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket {
  */
 pub struct TcpSocketBuf {
     data: @TcpBufferedSocketData,
-    mut end_of_stream: bool,
+    mut end_of_stream: bool
 }
 
 pub fn TcpSocketBuf(data: @TcpBufferedSocketData) -> TcpSocketBuf {
@@ -809,7 +809,7 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint,
  * A buffered wrapper that you can cast as an `io::reader` or `io::writer`
  */
 pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf {
-    TcpSocketBuf(@TcpBufferedSocketData { sock: sock, buf: ~[] })
+    TcpSocketBuf(@TcpBufferedSocketData { sock: move sock, mut buf: ~[], buf_off: 0 })
 }
 
 /// Convenience methods extending `net::tcp::tcp_socket`
@@ -859,48 +859,89 @@ impl TcpSocket {
 /// Implementation of `io::reader` trait for a buffered `net::tcp::tcp_socket`
 impl TcpSocketBuf: io::Reader {
     fn read(&self, buf: &[mut u8], len: uint) -> uint {
-        // Loop until our buffer has enough data in it for us to read from.
-        while self.data.buf.len() < len {
-            let read_result = read(&self.data.sock, 0u);
-            if read_result.is_err() {
-                let err_data = read_result.get_err();
+        if len == 0 { return 0 }
+        let mut count: uint = 0;
 
-                if err_data.err_name == ~"EOF" {
-                    self.end_of_stream = true;
-                    break;
-                } else {
-                    debug!("ERROR sock_buf as io::reader.read err %? %?",
-                           err_data.err_name, err_data.err_msg);
+        loop {
+          assert count < len;
 
-                    return 0;
+          // If possible, copy up to `len` bytes from the internal 
+          // `data.buf` into `buf`
+          let nbuffered = self.data.buf.len() - self.data.buf_off;
+          let needed = len - count;
+            if nbuffered > 0 {
+                unsafe {
+                    let ncopy = uint::min(nbuffered, needed); 
+                    let dst = ptr::mut_offset(
+                        vec::raw::to_mut_ptr(buf), count);
+                    let src = ptr::const_offset(
+                        vec::raw::to_const_ptr(self.data.buf),
+                        self.data.buf_off);
+                    ptr::copy_memory(dst, src, ncopy); 
+                    self.data.buf_off += ncopy;
+                    count += ncopy;
                 }
-            }
-            else {
-                self.data.buf.push_all(result::unwrap(read_result));
-            }
-        }
-
-        let count = uint::min(len, self.data.buf.len());
-
-        let mut data = ~[];
-        self.data.buf <-> data;
+          }
 
-        vec::bytes::copy_memory(buf, vec::view(data, 0, data.len()), count);
+          assert count <= len;
+          if count == len {
+              break;
+          }
 
-        self.data.buf.push_all(vec::view(data, count, data.len()));
+          // We copied all the bytes we had in the internal buffer into
+          // the result buffer, but the caller wants more bytes, so we
+          // need to read in data from the socket. Note that the internal
+          // buffer is of no use anymore as we read all bytes from it,
+          // so we can throw it away.
+          let read_result = read(&self.data.sock, 0u);
+          if read_result.is_err() {
+              let err_data = read_result.get_err();
+
+              if err_data.err_name == ~"EOF" {
+                  self.end_of_stream = true;
+                  break;
+              } else {
+                  debug!("ERROR sock_buf as io::reader.read err %? %?",
+                         err_data.err_name, err_data.err_msg);
+                  // As we have already copied data into result buffer,
+                  // we cannot simply return 0 here. Instead the error
+                  // should show up in a later call to read(). 
+                  break;
+              }
+          }
+          else {
+              self.data.buf = result::unwrap(read_result);
+              self.data.buf_off = 0;
+          }
+        }
 
         count
     }
     fn read_byte(&self) -> int {
-        let mut bytes = ~[0];
-        if self.read(bytes, 1u) == 0 {
-            if self.end_of_stream {
-                -1
-            } else {
-                fail
-            }
-        } else {
-            bytes[0] as int
+        loop {
+          if self.data.buf.len() > self.data.buf_off {
+            let c = self.data.buf[self.data.buf_off];
+            self.data.buf_off += 1;
+            return c as int
+          }
+
+          let read_result = read(&self.data.sock, 0u);
+          if read_result.is_err() {
+              let err_data = read_result.get_err();
+
+              if err_data.err_name == ~"EOF" {
+                  self.end_of_stream = true;
+                  return -1
+              } else {
+                  debug!("ERROR sock_buf as io::reader.read err %? %?",
+                         err_data.err_name, err_data.err_msg);
+                  fail
+              }
+          }
+          else {
+              self.data.buf = result::unwrap(read_result);
+              self.data.buf_off = 0;
+          }
         }
     }
     fn eof(&self) -> bool {
@@ -1375,6 +1416,7 @@ struct TcpSocketData {
 struct TcpBufferedSocketData {
     sock: TcpSocket,
     mut buf: ~[u8],
+    mut buf_off: uint
 }
 
 //#[cfg(test)]