BufWriter hangs after writing to stream

Hi all,

Once again, I'm quite stumped about how TcpStreams work in Rust.
Similiar to the post I've made saturday, my bufreader hangs. But this time after writing to a stream.

A nice person has provided me with an elegant solution of reading from a stream:

 fn read_message<R: Read>(mut reader:R)->Result<String, Box<dyn std::error::Error>> {
        let mut buf:Vec<u8> = vec![];
        let mut packet: Vec<u8> = vec![];
        loop {
            let mut header_bytes = [0u8;2];
            reader.read_exact(&mut header_bytes)?;
            let header = u16::from_le_bytes(header_bytes);
            packet.resize((header >> 1) as usize, 0);
            reader.read_exact(packet.as_mut_slice())?;
            buf.append(&mut packet);
            if header & 1 == 1 {
                return Ok(String::from_utf8(buf)?);
            }
        }
    }

and this works well when initially connecting to a TcpStream. But when I write to a stream and then try to read I get a blinking cursor. First the code that does work.

 pub fn new(address: &str) -> Result<MapiSocket, String>{

        let addr: SocketAddr = match address.parse() {
            Ok(f)=> f,
            Err(_) => return Err(format!("Unable to parse address"))
        };

        let socket = match TcpStream::connect(addr) {
            Ok(s) => s,
            Err(_) => return Err(format!("Unable to connect to server"))
        };

        let mut reader = BufReader::new(&socket);

        let data_str = MapiSocket::read_message(reader).unwrap();

        let settings = MapiSocket::parse_challenge_prompt(data_str.to_string());

        return Ok(MapiSocket {socket: socket.try_clone().unwrap(), settings, addr});
    }

The code that does not work:

 pub fn connect(&self, username: String, password: String) -> Result<(), AuthError> {

        let socket = TcpStream::connect(&self.addr).unwrap();
        let mut stream = BufWriter::new(socket);
        let hash = MapiSocket::calculate_hash(self.settings.salt.clone(), password);
        let conn_string = format!("LIT:{}:{{SHA1}}{}:sql:demo:\n", username, hash);

        MapiSocket::write_message(stream, conn_string);

        let reader = BufReader::new(&self.socket);
        let data_str = MapiSocket::read_message(reader);

        Ok(())
    }

and my write function:

    fn write_message<W: Write>(mut writer: W, conn_string: String) {
        writer.write(conn_string.as_bytes()).unwrap();
        writer.flush().unwrap();
    }

Do I need to reuse my BufReader of the previous function to read new messages, or do I need to create a new BufReader when I try to read new messages?

You should never throw the BufReader away unless you are done using the socket. There may be data left in the internal buffer of the BufReader that would be lost if you throw it away. Generally, you would not put a reference to the socket into a BufReader.

Thanks for the feedback!

I've added the reader to my socket struct:

struct MapiSocket {
    socket: TcpStream,
    reader: BufReader<TcpStream>,
    settings: MapiSettings,
    addr: SocketAddr,
}

But now when I use that reader, read_message panics that it cannot fill the whole buffer....

I don't know what MapiSocket is. Why does it panic?

MapiSocket is my own struct.

When I try to unwrap what is returned from read_message, it panics because:
failed to fill whole buffer

fn read_message<R: Read>(mut reader:R)->Result<String, Box<dyn std::error::Error>> {
        let mut buf:Vec<u8> = vec![];
        let mut packet: Vec<u8> = vec![];
        loop {
            let mut header_bytes = [0u8;2];
            reader.read_exact(&mut header_bytes)?;
            let header = u16::from_le_bytes(header_bytes);
            packet.resize((header >> 1) as usize, 0);
            reader.read_exact(packet.as_mut_slice())?;
            buf.append(&mut packet);
            if header & 1 == 1 {
                return Ok(String::from_utf8(buf)?);
            }
        }
    }

How are you calling it?

First I write a message to it

MapiSocket::write_message(&self.socket, "hello_world".as_bytes().unwrap());
(it does not really matter what kind of string is being sent, it should return something).

then I try to read the message that is being sent back:

let data_str = MapiSocket::read_message(self.reader.by_ref());

EDIT: after the message is sent I flush the buffer.

Honestly, I don't see the issue. I would probably insert some prints of the length to ensure it has the value you expect. Also, is the sender supposed to close the stream after writing the message? Because you shouldn't get that error unless the stream is closed.

I don't explicitly close the stream, so I don't think the stream is closed? Do I call any functions that close the stream?

It's not your code that is closing the stream. It looks like the stream is closed by the server at the other end of the connection, while your code is still expecting to receive more bytes.

Oh, that's weird. I'm gonna look into that.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.