Compare commits

..

No commits in common. "010c2c934b9e5bf3e4475543cdff5bb0be6e59c8" and "cb07142832481aa7aea9424a8b768073e3cc3df7" have entirely different histories.

24 changed files with 150 additions and 236 deletions

View File

@ -45,23 +45,9 @@ namespace BAN
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); } inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); } inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); } inline bool compare_exchange(T expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); }; inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_add_fetch (&m_value, val, mem_order); }
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_sub_fetch (&m_value, val, mem_order); }
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_and_fetch (&m_value, val, mem_order); }
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_xor_fetch (&m_value, val, mem_order); }
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_or_fetch (&m_value, val, mem_order); }
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nand_fetch(&m_value, val, mem_order); }
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
private: private:
T m_value; T m_value;
}; };

View File

@ -32,7 +32,7 @@ namespace BAN
new (m_storage) CallableMemberConst<Own>(function, owner); new (m_storage) CallableMemberConst<Own>(function, owner);
} }
template<typename Lambda> template<typename Lambda>
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; } Function(Lambda lambda) requires requires(Lambda lamda, Args... args) { { lambda(args...) } -> BAN::same_as<Ret>; }
{ {
static_assert(sizeof(CallableLambda<Lambda>) <= m_size); static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
new (m_storage) CallableLambda<Lambda>(lambda); new (m_storage) CallableLambda<Lambda>(lambda);

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <BAN/Atomic.h>
#include <BAN/Errors.h> #include <BAN/Errors.h>
#include <BAN/Move.h> #include <BAN/Move.h>
#include <BAN/NoCopyMove.h> #include <BAN/NoCopyMove.h>
@ -23,27 +22,15 @@ namespace BAN
void ref() const void ref() const
{ {
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed); ASSERT(m_ref_count > 0);
ASSERT(old > 0); m_ref_count++;
}
bool try_ref() const
{
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
for (;;)
{
if (expected == 0)
return false;
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
return true;
}
} }
void unref() const void unref() const
{ {
uint32_t old = m_ref_count.fetch_sub(1); ASSERT(m_ref_count > 0);
ASSERT(old > 0); m_ref_count--;
if (old == 1) if (m_ref_count == 0)
delete (const T*)this; delete (const T*)this;
} }
@ -52,7 +39,7 @@ namespace BAN
virtual ~RefCounted() { ASSERT(m_ref_count == 0); } virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
private: private:
mutable Atomic<uint32_t> m_ref_count = 1; mutable uint32_t m_ref_count = 1;
}; };
template<typename T> template<typename T>

View File

@ -2,10 +2,6 @@
#include <BAN/RefPtr.h> #include <BAN/RefPtr.h>
#if __is_kernel
#include <kernel/Lock/SpinLock.h>
#endif
namespace BAN namespace BAN
{ {
@ -15,37 +11,22 @@ namespace BAN
template<typename T> template<typename T>
class WeakPtr; class WeakPtr;
// FIXME: Write this without using locks...
template<typename T> template<typename T>
class WeakLink : public RefCounted<WeakLink<T>> class WeakLink : public RefCounted<WeakLink<T>>
{ {
public: public:
RefPtr<T> try_lock() RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
{ T* raw_ptr() { return m_ptr; }
#if __is_kernel
Kernel::SpinLockGuard _(m_weak_lock);
#endif
if (m_ptr && m_ptr->try_ref())
return RefPtr<T>::adopt(m_ptr);
return nullptr;
}
bool valid() const { return m_ptr; } bool valid() const { return m_ptr; }
void invalidate() void invalidate() { m_ptr = nullptr; }
{
#if __is_kernel
Kernel::SpinLockGuard _(m_weak_lock);
#endif
m_ptr = nullptr;
}
private: private:
WeakLink(T* ptr) : m_ptr(ptr) {} WeakLink(T* ptr) : m_ptr(ptr) {}
private: private:
T* m_ptr; T* m_ptr;
#if __is_kernel
Kernel::SpinLock m_weak_lock;
#endif
friend class RefPtr<WeakLink<T>>; friend class RefPtr<WeakLink<T>>;
}; };
@ -101,8 +82,8 @@ namespace BAN
RefPtr<T> lock() RefPtr<T> lock()
{ {
if (m_link) if (valid())
return m_link->try_lock(); return m_link->lock();
return nullptr; return nullptr;
} }

View File

@ -1,59 +1,20 @@
#pragma once #pragma once
#include <kernel/FS/Inode.h>
namespace Kernel namespace Kernel
{ {
class Socket : public Inode enum class SocketDomain
{
public:
enum class Domain
{ {
INET, INET,
INET6, INET6,
UNIX, UNIX,
}; };
enum class Type enum class SocketType
{ {
STREAM, STREAM,
DGRAM, DGRAM,
SEQPACKET, SEQPACKET,
}; };
struct Info
{
mode_t mode;
uid_t uid;
gid_t gid;
};
public:
ino_t ino() const final override { ASSERT_NOT_REACHED(); }
Mode mode() const final override { return Mode(m_info.mode); }
nlink_t nlink() const final override { ASSERT_NOT_REACHED(); }
uid_t uid() const final override { return m_info.uid; }
gid_t gid() const final override { return m_info.gid; }
off_t size() const final override { ASSERT_NOT_REACHED(); }
timespec atime() const final override { ASSERT_NOT_REACHED(); }
timespec mtime() const final override { ASSERT_NOT_REACHED(); }
timespec ctime() const final override { ASSERT_NOT_REACHED(); }
blksize_t blksize() const final override { ASSERT_NOT_REACHED(); }
blkcnt_t blocks() const final override { ASSERT_NOT_REACHED(); }
dev_t dev() const final override { ASSERT_NOT_REACHED(); }
dev_t rdev() const final override { ASSERT_NOT_REACHED(); }
protected:
Socket(const Info& info)
: m_info(info)
{}
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan buffer) override { return recvfrom_impl(buffer, nullptr, nullptr); }
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan buffer) override { return sendto_impl(buffer, nullptr, 0); }
private:
const Info m_info;
};
} }

View File

@ -24,12 +24,8 @@ namespace Kernel
ASSERT(m_lock_depth > 0); ASSERT(m_lock_depth > 0);
else else
{ {
pid_t expected = -1; while (!m_locker.compare_exchange(-1, tid))
while (!m_locker.compare_exchange(expected, tid))
{
Scheduler::get().yield(); Scheduler::get().yield();
expected = -1;
}
ASSERT(m_lock_depth == 0); ASSERT(m_lock_depth == 0);
if (Scheduler::current_tid()) if (Scheduler::current_tid())
Thread::current().add_mutex(); Thread::current().add_mutex();
@ -44,8 +40,7 @@ namespace Kernel
ASSERT(m_lock_depth > 0); ASSERT(m_lock_depth > 0);
else else
{ {
pid_t expected = -1; if (!m_locker.compare_exchange(-1, tid))
if (!m_locker.compare_exchange(expected, tid))
return false; return false;
ASSERT(m_lock_depth == 0); ASSERT(m_lock_depth == 0);
if (Scheduler::current_tid()) if (Scheduler::current_tid())
@ -94,12 +89,8 @@ namespace Kernel
bool has_priority = tid ? !Thread::current().is_userspace() : true; bool has_priority = tid ? !Thread::current().is_userspace() : true;
if (has_priority) if (has_priority)
m_queue_length++; m_queue_length++;
pid_t expected = -1; while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(-1, tid))
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
{
Scheduler::get().yield(); Scheduler::get().yield();
expected = -1;
}
ASSERT(m_lock_depth == 0); ASSERT(m_lock_depth == 0);
if (Scheduler::current_tid()) if (Scheduler::current_tid())
Thread::current().add_mutex(); Thread::current().add_mutex();
@ -115,8 +106,7 @@ namespace Kernel
else else
{ {
bool has_priority = tid ? !Thread::current().is_userspace() : true; bool has_priority = tid ? !Thread::current().is_userspace() : true;
pid_t expected = -1; if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(-1, tid))
if (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(expected, tid))
return false; return false;
if (has_priority) if (has_priority)
m_queue_length++; m_queue_length++;

View File

@ -26,12 +26,8 @@ namespace Kernel
auto id = Processor::current_id(); auto id = Processor::current_id();
ASSERT(m_locker != id); ASSERT(m_locker != id);
ProcessorID expected = PROCESSOR_NONE; while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
while (!m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire))
{
__builtin_ia32_pause(); __builtin_ia32_pause();
expected = PROCESSOR_NONE;
}
return state; return state;
} }
@ -71,12 +67,8 @@ namespace Kernel
ASSERT(m_lock_depth > 0); ASSERT(m_lock_depth > 0);
else else
{ {
ProcessorID expected = PROCESSOR_NONE; while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
while (!m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire))
{
__builtin_ia32_pause(); __builtin_ia32_pause();
expected = PROCESSOR_NONE;
}
ASSERT(m_lock_depth == 0); ASSERT(m_lock_depth == 0);
} }

View File

@ -44,14 +44,14 @@ namespace Kernel
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan); void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
virtual void unbind_socket(uint16_t port) override; virtual void unbind_socket(BAN::RefPtr<NetworkSocket>, uint16_t port) override;
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) override; virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) override;
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override; virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override; virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual Socket::Domain domain() const override { return Socket::Domain::INET ;} virtual SocketDomain domain() const override { return SocketDomain::INET ;}
virtual size_t header_size() const override { return sizeof(IPv4Header); } virtual size_t header_size() const override { return sizeof(IPv4Header); }
private: private:

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <kernel/FS/Socket.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
namespace Kernel namespace Kernel
@ -16,20 +15,22 @@ namespace Kernel
static_assert(sizeof(PseudoHeader) == 12); static_assert(sizeof(PseudoHeader) == 12);
class NetworkSocket; class NetworkSocket;
enum class SocketDomain;
enum class SocketType;
class NetworkLayer class NetworkLayer
{ {
public: public:
virtual ~NetworkLayer() {} virtual ~NetworkLayer() {}
virtual void unbind_socket(uint16_t port) = 0; virtual void unbind_socket(BAN::RefPtr<NetworkSocket>, uint16_t port) = 0;
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) = 0; virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) = 0;
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0; virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0; virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) = 0; virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, BAN::ConstByteSpan, const sockaddr*, socklen_t) = 0;
virtual Socket::Domain domain() const = 0; virtual SocketDomain domain() const = 0;
virtual size_t header_size() const = 0; virtual size_t header_size() const = 0;
protected: protected:

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/FS/Socket.h> #include <kernel/FS/TmpFS/FileSystem.h>
#include <kernel/Networking/IPv4Layer.h> #include <kernel/Networking/IPv4Layer.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -11,7 +12,7 @@
namespace Kernel namespace Kernel
{ {
class NetworkManager class NetworkManager : public TmpFileSystem
{ {
BAN_NON_COPYABLE(NetworkManager); BAN_NON_COPYABLE(NetworkManager);
BAN_NON_MOVABLE(NetworkManager); BAN_NON_MOVABLE(NetworkManager);
@ -24,18 +25,16 @@ namespace Kernel
BAN::Vector<BAN::RefPtr<NetworkInterface>> interfaces() { return m_interfaces; } BAN::Vector<BAN::RefPtr<NetworkInterface>> interfaces() { return m_interfaces; }
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t); BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_socket(SocketDomain, SocketType, mode_t, uid_t, gid_t);
void on_receive(NetworkInterface&, BAN::ConstByteSpan); void on_receive(NetworkInterface&, BAN::ConstByteSpan);
private: private:
NetworkManager() {} NetworkManager();
private: private:
BAN::UniqPtr<IPv4Layer> m_ipv4_layer; BAN::UniqPtr<IPv4Layer> m_ipv4_layer;
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces; BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
friend class BAN::UniqPtr<NetworkManager>;
}; };
} }

View File

@ -2,6 +2,7 @@
#include <BAN/WeakPtr.h> #include <BAN/WeakPtr.h>
#include <kernel/FS/Socket.h> #include <kernel/FS/Socket.h>
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkLayer.h> #include <kernel/Networking/NetworkLayer.h>
@ -15,7 +16,7 @@ namespace Kernel
UDP = 0x11, UDP = 0x11,
}; };
class NetworkSocket : public Socket, public BAN::Weakable<NetworkSocket> class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
{ {
BAN_NON_COPYABLE(NetworkSocket); BAN_NON_COPYABLE(NetworkSocket);
BAN_NON_MOVABLE(NetworkSocket); BAN_NON_MOVABLE(NetworkSocket);
@ -38,7 +39,7 @@ namespace Kernel
bool is_bound() const { return m_interface != nullptr; } bool is_bound() const { return m_interface != nullptr; }
protected: protected:
NetworkSocket(NetworkLayer&, const Socket::Info&); NetworkSocket(NetworkLayer&, ino_t, const TmpInodeInfo&);
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override; virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) override;

View File

@ -46,7 +46,7 @@ namespace Kernel
static constexpr size_t m_tcp_options_bytes = 4; static constexpr size_t m_tcp_options_bytes = 4;
public: public:
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&); static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, ino_t, const TmpInodeInfo&);
~TCPSocket(); ~TCPSocket();
virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; } virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; }
@ -141,7 +141,7 @@ namespace Kernel
}; };
private: private:
TCPSocket(NetworkLayer&, const Info&); TCPSocket(NetworkLayer&, ino_t, const TmpInodeInfo&);
void process_task(); void process_task();
void start_close_sequence(); void start_close_sequence();

View File

@ -23,7 +23,7 @@ namespace Kernel
class UDPSocket final : public NetworkSocket class UDPSocket final : public NetworkSocket
{ {
public: public:
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, const Socket::Info&); static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, ino_t, const TmpInodeInfo&);
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; } virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
@ -42,7 +42,7 @@ namespace Kernel
virtual bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }
private: private:
UDPSocket(NetworkLayer&, const Socket::Info&); UDPSocket(NetworkLayer&, ino_t, const TmpInodeInfo&);
~UDPSocket(); ~UDPSocket();
struct PacketInfo struct PacketInfo

View File

@ -9,13 +9,13 @@
namespace Kernel namespace Kernel
{ {
class UnixDomainSocket final : public Socket, public BAN::Weakable<UnixDomainSocket> class UnixDomainSocket final : public TmpInode, public BAN::Weakable<UnixDomainSocket>
{ {
BAN_NON_COPYABLE(UnixDomainSocket); BAN_NON_COPYABLE(UnixDomainSocket);
BAN_NON_MOVABLE(UnixDomainSocket); BAN_NON_MOVABLE(UnixDomainSocket);
public: public:
static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&); static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(SocketType, ino_t, const TmpInodeInfo&);
protected: protected:
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*) override;
@ -30,7 +30,7 @@ namespace Kernel
virtual bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }
private: private:
UnixDomainSocket(Socket::Type, const Socket::Info&); UnixDomainSocket(SocketType, ino_t, const TmpInodeInfo&);
~UnixDomainSocket(); ~UnixDomainSocket();
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan); BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan);
@ -58,7 +58,7 @@ namespace Kernel
}; };
private: private:
const Socket::Type m_socket_type; const SocketType m_socket_type;
BAN::String m_bound_path; BAN::String m_bound_path;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info; BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;

View File

@ -68,13 +68,19 @@ namespace Kernel
header.checksum = calculate_internet_checksum(BAN::ConstByteSpan::from(header), {}); header.checksum = calculate_internet_checksum(BAN::ConstByteSpan::from(header), {});
} }
void IPv4Layer::unbind_socket(uint16_t port) void IPv4Layer::unbind_socket(BAN::RefPtr<NetworkSocket> socket, uint16_t port)
{
{ {
SpinLockGuard _(m_bound_socket_lock); SpinLockGuard _(m_bound_socket_lock);
auto it = m_bound_sockets.find(port); auto it = m_bound_sockets.find(port);
ASSERT(it != m_bound_sockets.end()); if (it != m_bound_sockets.end())
{
ASSERT(it->value.lock() == socket);
m_bound_sockets.remove(it); m_bound_sockets.remove(it);
} }
}
NetworkManager::get().TmpFileSystem::remove_from_cache(socket);
}
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_unused(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> IPv4Layer::bind_socket_to_unused(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
{ {

View File

@ -19,7 +19,11 @@ namespace Kernel
BAN::ErrorOr<void> NetworkManager::initialize() BAN::ErrorOr<void> NetworkManager::initialize()
{ {
ASSERT(!s_instance); ASSERT(!s_instance);
auto manager = TRY(BAN::UniqPtr<NetworkManager>::create()); NetworkManager* manager_ptr = new NetworkManager();
if (manager_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto manager = BAN::UniqPtr<NetworkManager>::adopt(manager_ptr);
TRY(manager->TmpFileSystem::initialize(0777, 0, 0));
manager->m_ipv4_layer = TRY(IPv4Layer::create()); manager->m_ipv4_layer = TRY(IPv4Layer::create());
s_instance = BAN::move(manager); s_instance = BAN::move(manager);
return {}; return {};
@ -31,6 +35,10 @@ namespace Kernel
return *s_instance; return *s_instance;
} }
NetworkManager::NetworkManager()
: TmpFileSystem(128)
{ }
BAN::ErrorOr<void> NetworkManager::add_interface(PCI::Device& pci_device) BAN::ErrorOr<void> NetworkManager::add_interface(PCI::Device& pci_device)
{ {
BAN::RefPtr<NetworkInterface> interface; BAN::RefPtr<NetworkInterface> interface;
@ -64,21 +72,21 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<BAN::RefPtr<Socket>> NetworkManager::create_socket(Socket::Domain domain, Socket::Type type, mode_t mode, uid_t uid, gid_t gid) BAN::ErrorOr<BAN::RefPtr<TmpInode>> NetworkManager::create_socket(SocketDomain domain, SocketType type, mode_t mode, uid_t uid, gid_t gid)
{ {
switch (domain) switch (domain)
{ {
case Socket::Domain::INET: case SocketDomain::INET:
switch (type) switch (type)
{ {
case Socket::Type::DGRAM: case SocketType::DGRAM:
case Socket::Type::STREAM: case SocketType::STREAM:
break; break;
default: default:
return BAN::Error::from_errno(EPROTOTYPE); return BAN::Error::from_errno(EPROTOTYPE);
} }
break; break;
case Socket::Domain::UNIX: case SocketDomain::UNIX:
break; break;
default: default:
return BAN::Error::from_errno(EAFNOSUPPORT); return BAN::Error::from_errno(EAFNOSUPPORT);
@ -87,28 +95,30 @@ namespace Kernel
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
mode |= Inode::Mode::IFSOCK; mode |= Inode::Mode::IFSOCK;
auto socket_info = Socket::Info { .mode = mode, .uid = uid, .gid = gid }; auto inode_info = create_inode_info(mode, uid, gid);
BAN::RefPtr<Socket> socket; ino_t ino = TRY(allocate_inode(inode_info));
BAN::RefPtr<TmpInode> socket;
switch (domain) switch (domain)
{ {
case Socket::Domain::INET: case SocketDomain::INET:
{ {
switch (type) switch (type)
{ {
case Socket::Type::DGRAM: case SocketType::DGRAM:
socket = TRY(UDPSocket::create(*m_ipv4_layer, socket_info)); socket = TRY(UDPSocket::create(*m_ipv4_layer, ino, inode_info));
break; break;
case Socket::Type::STREAM: case SocketType::STREAM:
socket = TRY(TCPSocket::create(*m_ipv4_layer, socket_info)); socket = TRY(TCPSocket::create(*m_ipv4_layer, ino, inode_info));
break; break;
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
break; break;
} }
case Socket::Domain::UNIX: case SocketDomain::UNIX:
{ {
socket = TRY(UnixDomainSocket::create(type, socket_info)); socket = TRY(UnixDomainSocket::create(type, ino, inode_info));
break; break;
} }
default: default:

View File

@ -6,8 +6,8 @@
namespace Kernel namespace Kernel
{ {
NetworkSocket::NetworkSocket(NetworkLayer& network_layer, const Socket::Info& info) NetworkSocket::NetworkSocket(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
: Socket(info) : TmpInode(NetworkManager::get(), ino, inode_info)
, m_network_layer(network_layer) , m_network_layer(network_layer)
{ } { }

View File

@ -23,9 +23,9 @@ namespace Kernel
static constexpr size_t s_window_buffer_size = 15 * PAGE_SIZE; static constexpr size_t s_window_buffer_size = 15 * PAGE_SIZE;
static_assert(s_window_buffer_size <= UINT16_MAX); static_assert(s_window_buffer_size <= UINT16_MAX);
BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info) BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
{ {
auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, info)); auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, ino, inode_info));
socket->m_recv_window.buffer = TRY(VirtualRange::create_to_vaddr_range( socket->m_recv_window.buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(), PageTable::kernel(),
KERNEL_OFFSET, KERNEL_OFFSET,
@ -48,13 +48,11 @@ namespace Kernel
reinterpret_cast<TCPSocket*>(socket_ptr)->process_task(); reinterpret_cast<TCPSocket*>(socket_ptr)->process_task();
}, socket.ptr() }, socket.ptr()
); );
// hack to keep socket alive until its process starts
socket->ref();
return socket; return socket;
} }
TCPSocket::TCPSocket(NetworkLayer& network_layer, const Info& info) TCPSocket::TCPSocket(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
: NetworkSocket(network_layer, info) : NetworkSocket(network_layer, ino, inode_info)
{ {
m_send_window.start_seq = Random::get_u32() & 0x7FFFFFFF; m_send_window.start_seq = Random::get_u32() & 0x7FFFFFFF;
m_send_window.current_seq = m_send_window.start_seq; m_send_window.current_seq = m_send_window.start_seq;
@ -91,7 +89,7 @@ namespace Kernel
BAN::RefPtr<TCPSocket> return_inode; BAN::RefPtr<TCPSocket> return_inode;
{ {
auto return_inode_tmp = TRY(NetworkManager::get().create_socket(m_network_layer.domain(), Socket::Type::STREAM, mode().mode & ~Mode::TYPE_MASK, uid(), gid())); auto return_inode_tmp = TRY(NetworkManager::get().create_socket(m_network_layer.domain(), SocketType::STREAM, mode().mode & ~Mode::TYPE_MASK, uid(), gid()));
return_inode = static_cast<TCPSocket*>(return_inode_tmp.ptr()); return_inode = static_cast<TCPSocket*>(return_inode_tmp.ptr());
} }
@ -607,9 +605,13 @@ namespace Kernel
// NOTE: Only listen socket can unbind the socket as // NOTE: Only listen socket can unbind the socket as
// listen socket is always alive to redirect packets // listen socket is always alive to redirect packets
if (!m_listen_parent) if (!m_listen_parent)
m_network_layer.unbind_socket(m_port); m_network_layer.unbind_socket(this, m_port);
else else
{
m_listen_parent->remove_listen_child(this); m_listen_parent->remove_listen_child(this);
// Listen children are not actually bound, so they have to be manually removed
NetworkManager::get().TmpFileSystem::remove_from_cache(this);
}
m_interface = nullptr; m_interface = nullptr;
m_port = PORT_NONE; m_port = PORT_NONE;
dprintln_if(DEBUG_TCP, "Socket unbound"); dprintln_if(DEBUG_TCP, "Socket unbound");
@ -641,7 +643,6 @@ namespace Kernel
static constexpr uint32_t retransmit_timeout_ms = 1000; static constexpr uint32_t retransmit_timeout_ms = 1000;
BAN::RefPtr<TCPSocket> keep_alive { this }; BAN::RefPtr<TCPSocket> keep_alive { this };
this->unref();
while (m_process) while (m_process)
{ {
@ -656,8 +657,8 @@ namespace Kernel
continue; continue;
} }
// This is the last instance // This is the last instance (one instance in network manager and another keep_alive)
if (ref_count() == 1) if (ref_count() == 2)
{ {
if (m_state == State::Listen) if (m_state == State::Listen)
{ {

View File

@ -5,9 +5,9 @@
namespace Kernel namespace Kernel
{ {
BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(NetworkLayer& network_layer, const Socket::Info& info) BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
{ {
auto socket = TRY(BAN::RefPtr<UDPSocket>::create(network_layer, info)); auto socket = TRY(BAN::RefPtr<UDPSocket>::create(network_layer, ino, inode_info));
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range( socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(), PageTable::kernel(),
KERNEL_OFFSET, KERNEL_OFFSET,
@ -19,14 +19,14 @@ namespace Kernel
return socket; return socket;
} }
UDPSocket::UDPSocket(NetworkLayer& network_layer, const Socket::Info& info) UDPSocket::UDPSocket(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
: NetworkSocket(network_layer, info) : NetworkSocket(network_layer, ino, inode_info)
{ } { }
UDPSocket::~UDPSocket() UDPSocket::~UDPSocket()
{ {
if (is_bound()) if (is_bound())
m_network_layer.unbind_socket(m_port); m_network_layer.unbind_socket(this, m_port);
m_port = PORT_NONE; m_port = PORT_NONE;
m_interface = nullptr; m_interface = nullptr;
} }

View File

@ -15,9 +15,9 @@ namespace Kernel
static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE; static constexpr size_t s_packet_buffer_size = 10 * PAGE_SIZE;
BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(Socket::Type socket_type, const Socket::Info& info) BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> UnixDomainSocket::create(SocketType socket_type, ino_t ino, const TmpInodeInfo& inode_info)
{ {
auto socket = TRY(BAN::RefPtr<UnixDomainSocket>::create(socket_type, info)); auto socket = TRY(BAN::RefPtr<UnixDomainSocket>::create(socket_type, ino, inode_info));
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range( socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
PageTable::kernel(), PageTable::kernel(),
KERNEL_OFFSET, KERNEL_OFFSET,
@ -29,17 +29,17 @@ namespace Kernel
return socket; return socket;
} }
UnixDomainSocket::UnixDomainSocket(Socket::Type socket_type, const Socket::Info& info) UnixDomainSocket::UnixDomainSocket(SocketType socket_type, ino_t ino, const TmpInodeInfo& inode_info)
: Socket(info) : TmpInode(NetworkManager::get(), ino, inode_info)
, m_socket_type(socket_type) , m_socket_type(socket_type)
{ {
switch (socket_type) switch (socket_type)
{ {
case Socket::Type::STREAM: case SocketType::STREAM:
case Socket::Type::SEQPACKET: case SocketType::SEQPACKET:
m_info.emplace<ConnectionInfo>(); m_info.emplace<ConnectionInfo>();
break; break;
case Socket::Type::DGRAM: case SocketType::DGRAM:
m_info.emplace<ConnectionlessInfo>(); m_info.emplace<ConnectionlessInfo>();
break; break;
default: default:
@ -55,6 +55,7 @@ namespace Kernel
auto it = s_bound_sockets.find(m_bound_path); auto it = s_bound_sockets.find(m_bound_path);
if (it != s_bound_sockets.end()) if (it != s_bound_sockets.end())
s_bound_sockets.remove(it); s_bound_sockets.remove(it);
m_bound_path.clear();
} }
if (m_info.has<ConnectionInfo>()) if (m_info.has<ConnectionInfo>())
{ {
@ -62,6 +63,7 @@ namespace Kernel
if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>()) if (auto connection = connection_info.connection.lock(); connection && connection->m_info.has<ConnectionInfo>())
connection->m_info.get<ConnectionInfo>().target_closed = true; connection->m_info.get<ConnectionInfo>().target_closed = true;
} }
m_info.clear();
} }
BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len) BAN::ErrorOr<long> UnixDomainSocket::accept_impl(sockaddr* address, socklen_t* address_len)
@ -87,7 +89,7 @@ namespace Kernel
BAN::RefPtr<UnixDomainSocket> return_inode; BAN::RefPtr<UnixDomainSocket> return_inode;
{ {
auto return_inode_tmp = TRY(NetworkManager::get().create_socket(Socket::Domain::UNIX, m_socket_type, mode().mode & ~Mode::TYPE_MASK, uid(), gid())); auto return_inode_tmp = TRY(NetworkManager::get().create_socket(SocketDomain::UNIX, m_socket_type, mode().mode & ~Mode::TYPE_MASK, uid(), gid()));
return_inode = reinterpret_cast<UnixDomainSocket*>(return_inode_tmp.ptr()); return_inode = reinterpret_cast<UnixDomainSocket*>(return_inode_tmp.ptr());
} }
@ -225,10 +227,10 @@ namespace Kernel
{ {
switch (m_socket_type) switch (m_socket_type)
{ {
case Socket::Type::STREAM: case SocketType::STREAM:
return true; return true;
case Socket::Type::SEQPACKET: case SocketType::SEQPACKET:
case Socket::Type::DGRAM: case SocketType::DGRAM:
return false; return false;
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -346,8 +348,7 @@ namespace Kernel
if (m_info.has<ConnectionInfo>()) if (m_info.has<ConnectionInfo>())
{ {
auto& connection_info = m_info.get<ConnectionInfo>(); auto& connection_info = m_info.get<ConnectionInfo>();
bool expected = true; if (connection_info.target_closed.compare_exchange(true, false))
if (connection_info.target_closed.compare_exchange(expected, false))
return 0; return 0;
if (!connection_info.connection) if (!connection_info.connection)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);

View File

@ -97,38 +97,38 @@ namespace Kernel
{ {
bool valid_protocol = true; bool valid_protocol = true;
Socket::Domain sock_domain; SocketDomain sock_domain;
switch (domain) switch (domain)
{ {
case AF_INET: case AF_INET:
sock_domain = Socket::Domain::INET; sock_domain = SocketDomain::INET;
break; break;
case AF_INET6: case AF_INET6:
sock_domain = Socket::Domain::INET6; sock_domain = SocketDomain::INET6;
break; break;
case AF_UNIX: case AF_UNIX:
sock_domain = Socket::Domain::UNIX; sock_domain = SocketDomain::UNIX;
valid_protocol = false; valid_protocol = false;
break; break;
default: default:
return BAN::Error::from_errno(EPROTOTYPE); return BAN::Error::from_errno(EPROTOTYPE);
} }
Socket::Type sock_type; SocketType sock_type;
switch (type) switch (type)
{ {
case SOCK_STREAM: case SOCK_STREAM:
sock_type = Socket::Type::STREAM; sock_type = SocketType::STREAM;
if (protocol != IPPROTO_TCP) if (protocol != IPPROTO_TCP)
valid_protocol = false; valid_protocol = false;
break; break;
case SOCK_DGRAM: case SOCK_DGRAM:
sock_type = Socket::Type::DGRAM; sock_type = SocketType::DGRAM;
if (protocol != IPPROTO_UDP) if (protocol != IPPROTO_UDP)
valid_protocol = false; valid_protocol = false;
break; break;
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
sock_type = Socket::Type::SEQPACKET; sock_type = SocketType::SEQPACKET;
valid_protocol = false; valid_protocol = false;
break; break;
default: default:

View File

@ -1,7 +1,5 @@
#include "LibGUI/Window.h" #include "LibGUI/Window.h"
#include <BAN/ScopeGuard.h>
#include <LibFont/Font.h> #include <LibFont/Font.h>
#include <fcntl.h> #include <fcntl.h>
@ -18,7 +16,7 @@ namespace LibGUI
Window::~Window() Window::~Window()
{ {
munmap(m_framebuffer_smo, m_width * m_height * 4); munmap(m_framebuffer, m_width * m_height * 4);
close(m_server_fd); close(m_server_fd);
} }
@ -27,13 +25,9 @@ namespace LibGUI
if (title.size() >= sizeof(WindowCreatePacket::title)) if (title.size() >= sizeof(WindowCreatePacket::title))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
BAN::Vector<uint32_t> framebuffer;
TRY(framebuffer.resize(width * height));
int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); int server_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (server_fd == -1) if (server_fd == -1)
return BAN::Error::from_errno(errno); return BAN::Error::from_errno(errno);
BAN::ScopeGuard server_closer([server_fd] { close(server_fd); });
if (fcntl(server_fd, F_SETFL, fcntl(server_fd, F_GETFL) | O_CLOEXEC) == -1) if (fcntl(server_fd, F_SETFL, fcntl(server_fd, F_GETFL) | O_CLOEXEC) == -1)
return BAN::Error::from_errno(errno); return BAN::Error::from_errno(errno);
@ -52,8 +46,11 @@ namespace LibGUI
timespec current_time; timespec current_time;
clock_gettime(CLOCK_MONOTONIC, &current_time); clock_gettime(CLOCK_MONOTONIC, &current_time);
time_t duration_s = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_nsec >= start_time.tv_nsec); time_t duration_s = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_nsec >= start_time.tv_nsec);
if (duration_s > 1) if (duration_s > 10)
{
close(server_fd);
return BAN::Error::from_errno(ETIMEDOUT); return BAN::Error::from_errno(ETIMEDOUT);
}
timespec sleep_time; timespec sleep_time;
sleep_time.tv_sec = 0; sleep_time.tv_sec = 0;
@ -67,22 +64,28 @@ namespace LibGUI
strncpy(packet.title, title.data(), title.size()); strncpy(packet.title, title.data(), title.size());
packet.title[title.size()] = '\0'; packet.title[title.size()] = '\0';
if (send(server_fd, &packet, sizeof(packet), 0) != sizeof(packet)) if (send(server_fd, &packet, sizeof(packet), 0) != sizeof(packet))
{
close(server_fd);
return BAN::Error::from_errno(errno); return BAN::Error::from_errno(errno);
}
WindowCreateResponse response; WindowCreateResponse response;
if (recv(server_fd, &response, sizeof(response), 0) != sizeof(response)) if (recv(server_fd, &response, sizeof(response), 0) != sizeof(response))
{
close(server_fd);
return BAN::Error::from_errno(errno); return BAN::Error::from_errno(errno);
}
void* framebuffer_addr = smo_map(response.framebuffer_smo_key); void* framebuffer_addr = smo_map(response.framebuffer_smo_key);
if (framebuffer_addr == nullptr) if (framebuffer_addr == nullptr)
{
close(server_fd);
return BAN::Error::from_errno(errno); return BAN::Error::from_errno(errno);
}
server_closer.disable();
return TRY(BAN::UniqPtr<Window>::create( return TRY(BAN::UniqPtr<Window>::create(
server_fd, server_fd,
static_cast<uint32_t*>(framebuffer_addr), static_cast<uint32_t*>(framebuffer_addr),
BAN::move(framebuffer),
width, width,
height height
)); ));
@ -140,8 +143,8 @@ namespace LibGUI
uint32_t amount_abs = BAN::Math::abs(amount); uint32_t amount_abs = BAN::Math::abs(amount);
if (amount_abs == 0 || amount_abs >= height()) if (amount_abs == 0 || amount_abs >= height())
return; return;
uint32_t* dst = (amount > 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data(); uint32_t* dst = (amount > 0) ? m_framebuffer + width() * amount_abs : m_framebuffer;
uint32_t* src = (amount < 0) ? m_framebuffer.data() + width() * amount_abs : m_framebuffer.data(); uint32_t* src = (amount < 0) ? m_framebuffer + width() * amount_abs : m_framebuffer;
memmove(dst, src, width() * (height() - amount_abs) * 4); memmove(dst, src, width() * (height() - amount_abs) * 4);
} }
@ -169,9 +172,6 @@ namespace LibGUI
if (!clamp_to_framebuffer(x, y, width, height)) if (!clamp_to_framebuffer(x, y, width, height))
return true; return true;
for (uint32_t i = 0; i < height; i++)
memcpy(&m_framebuffer_smo[(y + i) * m_width + x], &m_framebuffer[(y + i) * m_width + x], width * sizeof(uint32_t));
WindowInvalidatePacket packet; WindowInvalidatePacket packet;
packet.x = x; packet.x = x;
packet.y = y; packet.y = y;

View File

@ -136,10 +136,9 @@ namespace LibGUI
int server_fd() const { return m_server_fd; } int server_fd() const { return m_server_fd; }
private: private:
Window(int server_fd, uint32_t* framebuffer_smo, BAN::Vector<uint32_t>&& framebuffer, uint32_t width, uint32_t height) Window(int server_fd, uint32_t* framebuffer, uint32_t width, uint32_t height)
: m_server_fd(server_fd) : m_server_fd(server_fd)
, m_framebuffer(framebuffer) , m_framebuffer(framebuffer)
, m_framebuffer_smo(framebuffer_smo)
, m_width(width) , m_width(width)
, m_height(height) , m_height(height)
{ } { }
@ -148,9 +147,7 @@ namespace LibGUI
private: private:
int m_server_fd; int m_server_fd;
uint32_t* m_framebuffer;
BAN::Vector<uint32_t> m_framebuffer;
uint32_t* m_framebuffer_smo;
uint32_t m_width; uint32_t m_width;
uint32_t m_height; uint32_t m_height;

View File

@ -99,9 +99,10 @@ int main(int argc, char** argv)
{ {
ssize_t nrecv = recv(socket, buffer, sizeof(buffer), 0); ssize_t nrecv = recv(socket, buffer, sizeof(buffer), 0);
if (nrecv == -1) if (nrecv == -1)
{
perror("recv"); perror("recv");
if (nrecv <= 0)
break; break;
}
write(STDOUT_FILENO, buffer, nrecv); write(STDOUT_FILENO, buffer, nrecv);
} }