From cf1cd14aa1efdb7930761fd544f66d9fc047ae5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alf-Andr=C3=A9=20Walla?= Date: Wed, 5 Dec 2018 15:26:00 +0100 Subject: [PATCH 01/12] examples: Add a TCP-to-TCP transfer example --- examples/transfer/CMakeLists.txt | 41 ++++++++++++ examples/transfer/config.json | 11 +++ examples/transfer/linux/CMakeLists.txt | 18 +++++ examples/transfer/send_file.sh | 2 + examples/transfer/server.py | 37 +++++++++++ examples/transfer/service.cpp | 92 ++++++++++++++++++++++++++ examples/transfer/vm.json | 3 + 7 files changed, 204 insertions(+) create mode 100644 examples/transfer/CMakeLists.txt create mode 100644 examples/transfer/config.json create mode 100644 examples/transfer/linux/CMakeLists.txt create mode 100755 examples/transfer/send_file.sh create mode 100755 examples/transfer/server.py create mode 100644 examples/transfer/service.cpp create mode 100644 examples/transfer/vm.json diff --git a/examples/transfer/CMakeLists.txt b/examples/transfer/CMakeLists.txt new file mode 100644 index 0000000000..1e3f8b72d4 --- /dev/null +++ b/examples/transfer/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 2.8.9) + +# IncludeOS install location +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) +project (tcp) + +# Human-readable name of your service +set(SERVICE_NAME "TCP Example Service") + +# Name of your service binary +set(BINARY "tcp_example") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# Adding memdisk (expects my.disk to exist in current dir): +# set(MEMDISK ${CMAKE_SOURCE_DIR}/my.disk) + +# DRIVERS / PLUGINS: + +set(DRIVERS + virtionet # Virtio networking + # ... Others from IncludeOS/src/drivers + ) + +set(PLUGINS + # syslogd # Syslog over UDP + # ...others + ) + + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) diff --git a/examples/transfer/config.json b/examples/transfer/config.json new file mode 100644 index 0000000000..26564e1325 --- /dev/null +++ b/examples/transfer/config.json @@ -0,0 +1,11 @@ +{ + "net" : [ + { + "iface": 0, + "config": "static", + "address": "10.0.0.42", + "netmask": "255.255.255.0", + "gateway": "10.0.0.1" + } + ] +} diff --git a/examples/transfer/linux/CMakeLists.txt b/examples/transfer/linux/CMakeLists.txt new file mode 100644 index 0000000000..5a6fca00dc --- /dev/null +++ b/examples/transfer/linux/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 2.8.9) +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +project (service C CXX) + +# Human-readable name of your service +set(SERVICE_NAME "TCP Transfer From Linux") + +# Name of your service binary +set(BINARY "tcp_linux") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + ../service.cpp + ) + +include($ENV{INCLUDEOS_PREFIX}/includeos/linux.service.cmake) diff --git a/examples/transfer/send_file.sh b/examples/transfer/send_file.sh new file mode 100755 index 0000000000..66fd069b9c --- /dev/null +++ b/examples/transfer/send_file.sh @@ -0,0 +1,2 @@ +#!/bin/bash +dd if=/dev/zero bs=1280 count=1048576 > /dev/tcp/10.0.0.42/81 diff --git a/examples/transfer/server.py b/examples/transfer/server.py new file mode 100755 index 0000000000..8bdc9400aa --- /dev/null +++ b/examples/transfer/server.py @@ -0,0 +1,37 @@ +import socket +import sys + +# Create a TCP/IP socket +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + +# Bind the socket to the port +server_address = ('10.0.0.1', 1337) +print 'starting up on %s port %s' % server_address +sock.bind(server_address) + +# Listen for incoming connections +sock.listen(5) + +while True: + # Wait for a connection + print 'waiting for a connection' + connection, client_address = sock.accept() + + try: + print 'connection from', client_address + bytes = 0 + + while True: + data = connection.recv(8192) + if data: + bytes += len(data) + #print 'received: %d' % len(data) + connection.sendall(data) + else: + print 'received %d bytes' % bytes + print 'closing', client_address + break + + finally: + # Clean up the connection + connection.close() diff --git a/examples/transfer/service.cpp b/examples/transfer/service.cpp new file mode 100644 index 0000000000..0da15c0011 --- /dev/null +++ b/examples/transfer/service.cpp @@ -0,0 +1,92 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +/** + * An example to show incoming and outgoing TCP Connections. + * In this example, IncludeOS is listening on port 80. + * + * Data received on port 80 will be redirected to a + * outgoing connection to a (in this case) python server (server.py) + * + * Data received from the python server connection + * will be redirected back to the client. + * + * To try it out, use netcat to connect to this IncludeOS instance. +**/ + +using Connection_ptr = net::tcp::Connection_ptr; +using Disconnect = net::tcp::Connection::Disconnect; + +// Address to our python server: 10.0.2.2:1337 +// @note: This may have to be modified depending on network and server settings. +net::Socket python_server{ {10,0,0,1} , 1337}; + +void Service::start() +{ +#ifdef USERSPACE_LINUX + extern void create_network_device(int N, const char* route, const char* ip); + create_network_device(0, "10.0.0.0/24", "10.0.0.1"); +#endif + auto& inet = net::Super_stack::get(0); + inet.network_config( + { 10, 0, 0, 42 }, // IP + { 255,255,255, 0 }, // Netmask + { 10, 0, 0, 1 }, // Gateway + { 10, 0, 0, 1 }); // DNS + + // Set up a TCP server on port 81 + auto& server = inet.tcp().listen(81); + printf("Server listening: %s \n", server.local().to_string().c_str()); + + // When someone connects to our server + server.on_connect( + [&inet] (Connection_ptr client) { + printf("Connected [Client]: %s\n", client->to_string().c_str()); + // Make an outgoing connection to our python server + auto outgoing = inet.tcp().connect(python_server); + // When outgoing connection to python sever is established + outgoing->on_connect( + [client] (Connection_ptr python) { + if (!python) { + printf("Connection failed!\n"); + return; + } + printf("Connected [Python]: %s\n", python->to_string().c_str()); + + // Setup handlers for when data is received on client and python connection + // When client reads data + client->on_read(1024, [python](auto buf) { + python->write(buf); + }); + + // When client is disconnecting + client->on_disconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); + python->close(); + }); + + // When python is disconnecting + python->on_disconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); + client->close(); + }); + }); // << onConnect (outgoing (python)) + }); // << onConnect (client) +} diff --git a/examples/transfer/vm.json b/examples/transfer/vm.json new file mode 100644 index 0000000000..7d0b112a2f --- /dev/null +++ b/examples/transfer/vm.json @@ -0,0 +1,3 @@ +{ + "mem" : 128 +} From d4f295f1d801713b4c968656df2989f96c307512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 21 Jan 2019 10:08:30 +0100 Subject: [PATCH 02/12] net: Remove namespace from call to ntohs for building unittest on mac --- src/net/checksum.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/checksum.cpp b/src/net/checksum.cpp index 065152fea5..db7e1035f6 100644 --- a/src/net/checksum.cpp +++ b/src/net/checksum.cpp @@ -133,7 +133,7 @@ uint16_t checksum(uint32_t tsum, const void* data, size_t length) noexcept vsum=(vsum & 0xFFFF)+(vsum>>16); } //allways right in this case as its allways little endian x86 - return ~net::ntohs((uint16_t)(vsum)); + return ~ntohs((uint16_t)(vsum)); #elif defined(__AVX2__) // VEX-align buffer while (((uintptr_t) buffer & 15) && length >= 4) { From 73e5f23a5eeb491891d4c7ecf0f4922ffecf95eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 21 Jan 2019 10:08:50 +0100 Subject: [PATCH 03/12] test: Update tcp read request test to reflect changes to API --- test/net/unit/tcp_read_request_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/net/unit/tcp_read_request_test.cpp b/test/net/unit/tcp_read_request_test.cpp index 4ff0e4f2a6..a157c024ad 100644 --- a/test/net/unit/tcp_read_request_test.cpp +++ b/test/net/unit/tcp_read_request_test.cpp @@ -34,7 +34,8 @@ CASE("Operating with out of order data") no_reads++; }; - auto req = std::make_unique(seq, BUFSZ, BUFSZ, read_cb); + auto req = std::make_unique(seq, BUFSZ, BUFSZ); + req->on_read_callback = read_cb; no_reads = 0; // Insert hole, first missing From 0081283991b95d9665ee194ccd54f16835411df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 21 Jan 2019 14:31:28 +0100 Subject: [PATCH 04/12] net: removed unicode char in stream buffer code --- api/net/stream_buffer.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/net/stream_buffer.hpp b/api/net/stream_buffer.hpp index 8aaf2a428f..42347f485f 100644 --- a/api/net/stream_buffer.hpp +++ b/api/net/stream_buffer.hpp @@ -205,7 +205,9 @@ namespace net { // Pop each time, in case callback leads to another call here. m_send_buffers.pop_front(); m_on_read(buf); - if (m_on_read == nullptr) { break; } //if calling m_on_read reset the callbacks exit + if (m_on_read == nullptr) { + break; + } //if calling m_on_read reset the callbacks exit } } } From 82b0219521e1ed250781d36a02294dc473e084a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 21 Jan 2019 16:07:58 +0100 Subject: [PATCH 05/12] pmr: return subcap if set --- api/util/detail/alloc_pmr.hpp | 5 +++-- test/util/unit/pmr_alloc_test.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/api/util/detail/alloc_pmr.hpp b/api/util/detail/alloc_pmr.hpp index 73f67fb5cf..6a7e317622 100644 --- a/api/util/detail/alloc_pmr.hpp +++ b/api/util/detail/alloc_pmr.hpp @@ -155,7 +155,8 @@ namespace os::mem::detail { std::size_t resource_capacity() { if (cap_suballoc_ == 0) { - return cap_total_ / (used_resources_ + os::mem::Pmr_pool::resource_division_offset); + auto div = cap_total_ / (used_resources_ + os::mem::Pmr_pool::resource_division_offset); + return std::min(div, allocatable()); } return cap_suballoc_; } @@ -249,7 +250,7 @@ namespace os::mem { // Pmr_resource::Pmr_resource(Pool_ptr p) : pool_{p} {} std::size_t Pmr_resource::capacity() { - return std::min(pool_->resource_capacity(), pool_->allocatable()); + return pool_->resource_capacity(); } std::size_t Pmr_resource::allocatable() { auto cap = capacity(); diff --git a/test/util/unit/pmr_alloc_test.cpp b/test/util/unit/pmr_alloc_test.cpp index 51cdc1b0ae..1f537bc0b3 100644 --- a/test/util/unit/pmr_alloc_test.cpp +++ b/test/util/unit/pmr_alloc_test.cpp @@ -166,10 +166,37 @@ CASE("pmr::resource usage") { // Drain all the resources for (auto& res : resources) { + auto exp_alloc = resource_cap; + EXPECT(not res->full()); + EXPECT(pool.allocatable() >= exp_alloc); + EXPECT(res->allocatable() == exp_alloc); + EXPECT(res->allocated() == 0); + auto* p1 = res->allocate(1_KiB); + exp_alloc -= 1_KiB; + EXPECT(res->allocated() == 1_KiB); + EXPECT(res->capacity() == resource_cap); + EXPECT(pool.allocatable() >= exp_alloc); + EXPECT(res->allocatable() == exp_alloc); + auto* p2 = res->allocate(1_KiB); + exp_alloc -= 1_KiB; + EXPECT(res->allocated() == 2_KiB); + EXPECT(pool.allocatable() >= exp_alloc); + EXPECT(res->allocatable() == exp_alloc); + auto* p3 = res->allocate(1_KiB); + exp_alloc -= 1_KiB; + EXPECT(res->allocated() == 3_KiB); + EXPECT(pool.allocatable() >= exp_alloc); + EXPECT(res->allocatable() == exp_alloc); + auto* p4 = res->allocate(1_KiB); + exp_alloc -= 1_KiB; + EXPECT(res->allocated() == 4_KiB); + EXPECT(pool.allocatable() >= exp_alloc); + EXPECT(res->allocatable() == exp_alloc); + EXPECT(p1 != nullptr); EXPECT(p2 != nullptr); EXPECT(p3 != nullptr); From 1db1523103c6557ae06b3249ce7e038dfa3051b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 22 Jan 2019 11:55:55 +0100 Subject: [PATCH 06/12] net: Flush data in stream buffer when handler is set --- api/net/stream_buffer.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/net/stream_buffer.hpp b/api/net/stream_buffer.hpp index 42347f485f..700b5694ab 100644 --- a/api/net/stream_buffer.hpp +++ b/api/net/stream_buffer.hpp @@ -22,9 +22,11 @@ namespace net { void on_read(size_t, ReadCallback cb) override { m_on_read = std::move(cb); + signal_data(); } void on_data(DataCallback cb) override { m_on_data = std::move(cb); + signal_data(); } size_t next_size() override; From afc904434640ad32cdbec0f75af3c76980aa381a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 22 Jan 2019 11:57:10 +0100 Subject: [PATCH 07/12] microlb: Replace lambda with member functions --- lib/microLB/micro_lb/balancer.cpp | 47 +++++++++++++++---------------- lib/microLB/micro_lb/balancer.hpp | 3 ++ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/lib/microLB/micro_lb/balancer.cpp b/lib/microLB/micro_lb/balancer.cpp index 9b0f124da6..9115313959 100644 --- a/lib/microLB/micro_lb/balancer.cpp +++ b/lib/microLB/micro_lb/balancer.cpp @@ -278,12 +278,8 @@ namespace microLB session.outgoing->reset_callbacks(); closed_sessions.push_back(session.self); - if (!cleanup_timer.is_running()) - { - cleanup_timer.start(std::chrono::milliseconds(10),[this](){ - this->destroy_sessions(); - }); - } + destroy_sessions(); + session_cnt--; LBOUT("Session %d closed (total = %d)\n", session.self, session_cnt); } @@ -322,7 +318,7 @@ namespace microLB this->restart_active_check(); } }); - } catch (std::exception& e) { + } catch (const std::exception&) { // do nothing, because might just be eph.ports used up } } @@ -440,34 +436,37 @@ namespace microLB : parent(n), self(idx), incoming(std::move(inc)), outgoing(std::move(out)) { - - incoming->on_data([this]() { - assert(this->is_alive()); - while((this->incoming->next_size() > 0) and this->outgoing->is_writable()) - { - this->outgoing->write(this->incoming->read_next()); - } - }); + incoming->on_data({this, &Session::flush_incoming}); incoming->on_close( [&nodes = n, idx] () { nodes.close_session(idx); }); - outgoing->on_data([this]() { - assert(this->is_alive()); - while((this->outgoing->next_size() > 0) and this->incoming->is_writable()) - { - this->incoming->write(this->outgoing->read_next()); - } - }); + outgoing->on_data({this, &Session::flush_outgoing}); outgoing->on_close( [&nodes = n, idx] () { nodes.close_session(idx); }); - - } bool Session::is_alive() const { return incoming != nullptr; } + + void Session::flush_incoming() + { + assert(this->is_alive()); + while((this->incoming->next_size() > 0) and this->outgoing->is_writable()) + { + this->outgoing->write(this->incoming->read_next()); + } + } + + void Session::flush_outgoing() + { + assert(this->is_alive()); + while((this->outgoing->next_size() > 0) and this->incoming->is_writable()) + { + this->incoming->write(this->outgoing->read_next()); + } + } } diff --git a/lib/microLB/micro_lb/balancer.hpp b/lib/microLB/micro_lb/balancer.hpp index f05ffd8027..473e76b475 100644 --- a/lib/microLB/micro_lb/balancer.hpp +++ b/lib/microLB/micro_lb/balancer.hpp @@ -28,6 +28,9 @@ namespace microLB const int self; net::Stream_ptr incoming; net::Stream_ptr outgoing; + + void flush_incoming(); + void flush_outgoing(); }; struct Node { From 9cfc81ec28e385988bfe37a8f9560c1d1e3349e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 22 Jan 2019 13:17:00 +0100 Subject: [PATCH 08/12] test: Increase memory for microLB test --- test/net/integration/microLB/vm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/net/integration/microLB/vm.json b/test/net/integration/microLB/vm.json index 85f68a14cf..8c0a4549e9 100644 --- a/test/net/integration/microLB/vm.json +++ b/test/net/integration/microLB/vm.json @@ -6,5 +6,5 @@ {"device" : "virtio"}, {"device" : "virtio"} ], - "mem" : 64 + "mem" : 256 } From a18127611e7d7a8df842fe334ed2033621bd72b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alf-Andr=C3=A9=20Walla?= Date: Tue, 22 Jan 2019 04:37:17 -0800 Subject: [PATCH 09/12] microlb: Add try/catch to avoid silently invalidating the client queue --- lib/microLB/micro_lb/balancer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/microLB/micro_lb/balancer.cpp b/lib/microLB/micro_lb/balancer.cpp index 770c5653ad..d335e032a7 100644 --- a/lib/microLB/micro_lb/balancer.cpp +++ b/lib/microLB/micro_lb/balancer.cpp @@ -74,16 +74,21 @@ namespace microLB auto& client = queue.front(); assert(client.conn != nullptr); if (client.conn->is_connected()) { - // NOTE: explicitly want to copy buffers - net::Stream_ptr rval = - nodes.assign(std::move(client.conn), client.readq); - if (rval == nullptr) { - // done with this queue item - queue.pop_front(); - } - else { - // put connection back in queue item - client.conn = std::move(rval); + try { + // NOTE: explicitly want to copy buffers + net::Stream_ptr rval = + nodes.assign(std::move(client.conn), client.readq); + if (rval == nullptr) { + // done with this queue item + queue.pop_front(); + } + else { + // put connection back in queue item + client.conn = std::move(rval); + } + } catch (...) { + queue.pop_front(); // we have no choice + throw; } } else { From dcfdbaa3355520ce9acd3ef40f423c74806da1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alf-Andr=C3=A9=20Walla?= Date: Tue, 22 Jan 2019 05:17:27 -0800 Subject: [PATCH 10/12] microlb: Remove reference to readq --- lib/microLB/micro_lb/balancer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/microLB/micro_lb/balancer.cpp b/lib/microLB/micro_lb/balancer.cpp index a1a9adedec..f7c69c38e8 100644 --- a/lib/microLB/micro_lb/balancer.cpp +++ b/lib/microLB/micro_lb/balancer.cpp @@ -74,7 +74,7 @@ namespace microLB try { // NOTE: explicitly want to copy buffers net::Stream_ptr rval = - nodes.assign(std::move(client.conn), client.readq); + nodes.assign(std::move(client.conn)); if (rval == nullptr) { // done with this queue item queue.pop_front(); From 6a5f8a56bbe234f03eb5f6ede5d3372501e6c66b Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Tue, 22 Jan 2019 14:19:28 +0100 Subject: [PATCH 11/12] Test: Set a timeout for microlb get connection --- test/net/integration/microLB/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/net/integration/microLB/test.py b/test/net/integration/microLB/test.py index 24777b3f30..3fe5734756 100755 --- a/test/net/integration/microLB/test.py +++ b/test/net/integration/microLB/test.py @@ -16,8 +16,7 @@ expected_string = "#" * 1024 * 1024 * 50 def validateRequest(addr): - response = requests.get('https://10.0.0.68:443', verify=False) - #print (response.content) + response = requests.get('https://10.0.0.68:443', verify=False, timeout=5) return (response.content) == str(addr) + expected_string # start nodeJS From 948f230d9accf654f0ad1a1d351da9072c06198b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 22 Jan 2019 16:19:42 +0100 Subject: [PATCH 12/12] posix: Fix TCP posix hanging when data and FIN is recv right after eachother resulting in os block not getting time Co-authored-by: Martin Nordsletten --- api/net/tcp/connection_states.hpp | 8 ++++++-- src/posix/tcp_fd.cpp | 6 ++++-- test/posix/integration/tcp/test.py | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/api/net/tcp/connection_states.hpp b/api/net/tcp/connection_states.hpp index 869ae69de5..ca95f9acb2 100644 --- a/api/net/tcp/connection_states.hpp +++ b/api/net/tcp/connection_states.hpp @@ -352,11 +352,15 @@ class Connection::LastAck : public State { */ virtual Result handle(Connection&, Packet_view& in) override; - inline virtual std::string to_string() const override { + std::string to_string() const override { return "LAST-ACK"; }; - inline virtual bool is_closing() const override { + bool is_closing() const override { + return true; + } + + bool is_closed() const override { return true; } diff --git a/src/posix/tcp_fd.cpp b/src/posix/tcp_fd.cpp index a2cf6115bb..ca0d3f2d6d 100644 --- a/src/posix/tcp_fd.cpp +++ b/src/posix/tcp_fd.cpp @@ -311,8 +311,10 @@ ssize_t TCP_FD_Conn::recv(void* dest, size_t len, int) bytes = buffer->size(); }); - // BLOCK HERE - while (!done || !conn->is_readable()) { + // BLOCK HERE: + // 1. if we havent read the data we asked for + // 2. or we aren't readable but not closed (not 100% sure here hehe..) + while (!done || (!conn->is_readable() and !conn->is_closed())) { OS::block(); } // restore diff --git a/test/posix/integration/tcp/test.py b/test/posix/integration/tcp/test.py index 7ce8aab968..0c5b27c547 100755 --- a/test/posix/integration/tcp/test.py +++ b/test/posix/integration/tcp/test.py @@ -50,6 +50,7 @@ def TCP_connect(): sock.connect((HOST, PORT)) MESSAGE = "POSIX is for hipsters" sock.send(MESSAGE) + sock.close() def TCP_recv(trigger_line): server.listen(1)