From 81fd49642a14a83aa6755c5f0243f7770bd4b522 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 29 Dec 2020 17:51:10 +0200 Subject: [PATCH] net: restore back the blocking TcpConn.read_line() method for simplicity --- vlib/net/tcp.v | 6 ++++- vlib/net/tcp_read_line.v | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 vlib/net/tcp_read_line.v diff --git a/vlib/net/tcp.v b/vlib/net/tcp.v index 9f9736d84a..9745a9c318 100644 --- a/vlib/net/tcp.v +++ b/vlib/net/tcp.v @@ -35,7 +35,8 @@ pub fn (c TcpConn) close() ? { // write_ptr blocks and attempts to write all data pub fn (c TcpConn) write_ptr(b byteptr, len int) ? { $if trace_tcp ? { - eprintln('>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len') + eprintln('>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' + + unsafe { b.vstring_with_len(len) }) } unsafe { mut ptr_base := byteptr(b) @@ -85,6 +86,9 @@ pub fn (c TcpConn) read_ptr(buf_ptr byteptr, len int) ?int { error_ewouldblock { c.wait_for_read() ? res = wrap_read_result(C.recv(c.sock.handle, buf_ptr, len, 0)) ? + $if trace_tcp ? { + eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res') + } return socket_error(res) } else { diff --git a/vlib/net/tcp_read_line.v b/vlib/net/tcp_read_line.v new file mode 100644 index 0000000000..07024c58b0 --- /dev/null +++ b/vlib/net/tcp_read_line.v @@ -0,0 +1,56 @@ +module net + +const ( + crlf = '\r\n' + msg_peek = 0x02 + max_read = 400 +) + +// read_line is a *simple*, *non customizable*, blocking line reader. +// It will *always* return a line, ending with CRLF, or just '', on EOF. +// NB: if you want more control over the buffer, please use a buffered IO +// reader instead: `io.new_buffered_reader({reader: io.make_reader(con)})` +pub fn (con TcpConn) read_line() string { + mut buf := [max_read]byte{} // where C.recv will store the network data + mut res := '' // The final result, including the ending \n. + for { + mut line := '' // The current line. Can be a partial without \n in it. + n := C.recv(con.sock.handle, buf, max_read - 1, msg_peek | msg_nosignal) + if n == -1 { + return res + } + if n == 0 { + return res + } + buf[n] = `\0` + mut eol_idx := -1 + for i in 0 .. n { + if int(buf[i]) == `\n` { + eol_idx = i + // Ensure that tos_clone(buf) later, + // will return *only* the first line (including \n), + // and ignore the rest + buf[i + 1] = `\0` + break + } + } + bufbp := byteptr(buf) + line = tos_clone(bufbp) + if eol_idx > 0 { + // At this point, we are sure that recv returned valid data, + // that contains *at least* one line. + // Ensure that the block till the first \n (including it) + // is removed from the socket's receive queue, so that it does + // not get read again. + C.recv(con.sock.handle, buf, eol_idx + 1, msg_nosignal) + res += line + break + } + // recv returned a buffer without \n in it . + C.recv(con.sock.handle, buf, n, msg_nosignal) + res += line + res += crlf + break + } + return res +}