mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 19:57:45 +00:00
LibCore: Move GIODevice hierarchy from LibGUI to LibCore.
This commit is contained in:
parent
fc1d3074de
commit
cfd6e6cc36
19 changed files with 112 additions and 112 deletions
|
@ -1,42 +0,0 @@
|
|||
#include <LibGUI/GFile.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
GFile::GFile(const String& filename)
|
||||
: m_filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
GFile::~GFile()
|
||||
{
|
||||
if (mode() != NotOpen)
|
||||
close();
|
||||
}
|
||||
|
||||
bool GFile::open(GIODevice::OpenMode mode)
|
||||
{
|
||||
int flags = 0;
|
||||
if ((mode & GIODevice::ReadWrite) == GIODevice::ReadWrite) {
|
||||
flags |= O_RDWR | O_CREAT;
|
||||
} else if (mode & GIODevice::ReadOnly) {
|
||||
flags |= O_RDONLY;
|
||||
} else if (mode & GIODevice::WriteOnly) {
|
||||
flags |= O_WRONLY | O_CREAT;
|
||||
}
|
||||
if (mode & GIODevice::Append)
|
||||
flags |= O_APPEND;
|
||||
if (mode & GIODevice::Truncate)
|
||||
flags |= O_TRUNC;
|
||||
if (mode & GIODevice::MustBeNew)
|
||||
flags |= O_EXCL;
|
||||
int fd = ::open(m_filename.characters(), flags, 0666);
|
||||
if (fd < 0) {
|
||||
set_error(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
set_fd(fd);
|
||||
set_mode(mode);
|
||||
return true;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibGUI/GIODevice.h>
|
||||
#include <AK/AKString.h>
|
||||
|
||||
class GFile final : public GIODevice {
|
||||
public:
|
||||
GFile() { }
|
||||
explicit GFile(const String&);
|
||||
virtual ~GFile() override;
|
||||
|
||||
String filename() const { return m_filename; }
|
||||
void set_filename(const String& filename) { m_filename = filename; }
|
||||
|
||||
virtual bool open(GIODevice::OpenMode) override;
|
||||
|
||||
virtual const char* class_name() const override { return "GFile"; }
|
||||
|
||||
private:
|
||||
String m_filename;
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
#include <LibGUI/GHttpJob.h>
|
||||
#include <LibGUI/GHttpResponse.h>
|
||||
#include <LibGUI/GTCPSocket.h>
|
||||
#include <LibCore/CTCPSocket.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -98,7 +98,7 @@ void GHttpJob::on_socket_connected()
|
|||
void GHttpJob::start()
|
||||
{
|
||||
ASSERT(!m_socket);
|
||||
m_socket = new GTCPSocket(this);
|
||||
m_socket = new CTCPSocket(this);
|
||||
m_socket->on_connected = [this] {
|
||||
printf("Socket on_connected callback\n");
|
||||
on_socket_connected();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <LibGUI/GHttpRequest.h>
|
||||
#include <AK/HashMap.h>
|
||||
|
||||
class GTCPSocket;
|
||||
class CTCPSocket;
|
||||
|
||||
class GHttpJob final : public GNetworkJob {
|
||||
public:
|
||||
|
@ -26,7 +26,7 @@ private:
|
|||
};
|
||||
|
||||
GHttpRequest m_request;
|
||||
GTCPSocket* m_socket { nullptr };
|
||||
CTCPSocket* m_socket { nullptr };
|
||||
State m_state { State::InStatus };
|
||||
int m_code { -1 };
|
||||
HashMap<String, String> m_headers;
|
||||
|
|
|
@ -1,175 +0,0 @@
|
|||
#include <LibGUI/GIODevice.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdio.h>
|
||||
|
||||
GIODevice::GIODevice(CObject* parent)
|
||||
: CObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
GIODevice::~GIODevice()
|
||||
{
|
||||
}
|
||||
|
||||
const char* GIODevice::error_string() const
|
||||
{
|
||||
return strerror(m_error);
|
||||
}
|
||||
|
||||
ByteBuffer GIODevice::read(int max_size)
|
||||
{
|
||||
if (m_fd < 0)
|
||||
return { };
|
||||
if (!max_size)
|
||||
return { };
|
||||
auto buffer = ByteBuffer::create_uninitialized(max_size);
|
||||
auto* buffer_ptr = (char*)buffer.pointer();
|
||||
int remaining_buffer_space = buffer.size();
|
||||
if (!m_buffered_data.is_empty()) {
|
||||
int taken_from_buffered = min(remaining_buffer_space, m_buffered_data.size());
|
||||
memcpy(buffer_ptr, m_buffered_data.data(), taken_from_buffered);
|
||||
Vector<byte> new_buffered_data;
|
||||
new_buffered_data.append(m_buffered_data.data() + taken_from_buffered, m_buffered_data.size() - taken_from_buffered);
|
||||
m_buffered_data = move(new_buffered_data);
|
||||
remaining_buffer_space -= taken_from_buffered;
|
||||
buffer_ptr += taken_from_buffered;
|
||||
}
|
||||
if (!remaining_buffer_space)
|
||||
return buffer;
|
||||
int nread = ::read(m_fd, buffer_ptr, remaining_buffer_space);
|
||||
if (nread < 0) {
|
||||
set_error(errno);
|
||||
return { };
|
||||
}
|
||||
if (nread == 0) {
|
||||
set_eof(true);
|
||||
return { };
|
||||
}
|
||||
buffer.trim(nread);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool GIODevice::can_read_from_fd() const
|
||||
{
|
||||
// FIXME: Can we somehow remove this once GSocket is implemented using non-blocking sockets?
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(m_fd, &rfds);
|
||||
struct timeval timeout { 0, 0 };
|
||||
int rc = select(m_fd + 1, &rfds, nullptr, nullptr, &timeout);
|
||||
if (rc < 0) {
|
||||
// NOTE: We don't set m_error here.
|
||||
perror("GIODevice::can_read: select");
|
||||
return false;
|
||||
}
|
||||
return FD_ISSET(m_fd, &rfds);
|
||||
}
|
||||
|
||||
bool GIODevice::can_read_line()
|
||||
{
|
||||
if (m_eof && !m_buffered_data.is_empty())
|
||||
return true;
|
||||
if (m_buffered_data.contains_slow('\n'))
|
||||
return true;
|
||||
if (!can_read_from_fd())
|
||||
return false;
|
||||
populate_read_buffer();
|
||||
return m_buffered_data.contains_slow('\n');
|
||||
}
|
||||
|
||||
bool GIODevice::can_read() const
|
||||
{
|
||||
return !m_buffered_data.is_empty() || can_read_from_fd();
|
||||
}
|
||||
|
||||
ByteBuffer GIODevice::read_all()
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
if (!m_buffered_data.is_empty()) {
|
||||
buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size());
|
||||
m_buffered_data.clear();
|
||||
}
|
||||
|
||||
while (can_read_from_fd()) {
|
||||
char read_buffer[4096];
|
||||
int nread = ::read(m_fd, read_buffer, sizeof(read_buffer));
|
||||
if (nread < 0) {
|
||||
set_error(nread);
|
||||
return buffer;
|
||||
}
|
||||
if (nread == 0) {
|
||||
set_eof(true);
|
||||
break;
|
||||
}
|
||||
buffer.append(read_buffer, nread);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ByteBuffer GIODevice::read_line(int max_size)
|
||||
{
|
||||
if (m_fd < 0)
|
||||
return { };
|
||||
if (!max_size)
|
||||
return { };
|
||||
if (!can_read_line())
|
||||
return { };
|
||||
if (m_eof) {
|
||||
if (m_buffered_data.size() > max_size) {
|
||||
printf("GIODevice::read_line: At EOF but there's more than max_size(%d) buffered\n", max_size);
|
||||
return { };
|
||||
}
|
||||
auto buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size());
|
||||
m_buffered_data.clear();
|
||||
return buffer;
|
||||
}
|
||||
auto line = ByteBuffer::create_uninitialized(max_size + 1);
|
||||
int line_index = 0;
|
||||
while (line_index < max_size) {
|
||||
byte ch = m_buffered_data[line_index];
|
||||
line[line_index++] = ch;
|
||||
if (ch == '\n') {
|
||||
Vector<byte> new_buffered_data;
|
||||
new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index);
|
||||
m_buffered_data = move(new_buffered_data);
|
||||
line[line_index] = '\0';
|
||||
line.trim(line_index + 1);
|
||||
return line;
|
||||
}
|
||||
}
|
||||
return { };
|
||||
}
|
||||
|
||||
bool GIODevice::populate_read_buffer()
|
||||
{
|
||||
if (m_fd < 0)
|
||||
return false;
|
||||
auto buffer = ByteBuffer::create_uninitialized(PAGE_SIZE);
|
||||
int nread = ::read(m_fd, buffer.pointer(), buffer.size());
|
||||
if (nread < 0) {
|
||||
set_error(errno);
|
||||
return false;
|
||||
}
|
||||
if (nread == 0) {
|
||||
set_eof(true);
|
||||
return false;
|
||||
}
|
||||
buffer.trim(nread);
|
||||
m_buffered_data.append(buffer.pointer(), buffer.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GIODevice::close()
|
||||
{
|
||||
if (fd() < 0 || mode() == NotOpen)
|
||||
return false;
|
||||
int rc = ::close(fd());
|
||||
if (rc < 0) {
|
||||
set_error(rc);
|
||||
return false;
|
||||
}
|
||||
set_fd(-1);
|
||||
set_mode(GIODevice::NotOpen);
|
||||
return true;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibCore/CObject.h>
|
||||
#include <AK/ByteBuffer.h>
|
||||
|
||||
class GIODevice : public CObject {
|
||||
public:
|
||||
enum OpenMode {
|
||||
NotOpen = 0,
|
||||
ReadOnly = 1,
|
||||
WriteOnly = 2,
|
||||
ReadWrite = 3,
|
||||
Append = 4,
|
||||
Truncate = 8,
|
||||
MustBeNew = 16,
|
||||
};
|
||||
|
||||
virtual ~GIODevice() override;
|
||||
|
||||
int fd() const { return m_fd; }
|
||||
unsigned mode() const { return m_mode; }
|
||||
bool eof() const { return m_eof; }
|
||||
|
||||
int error() const { return m_error; }
|
||||
const char* error_string() const;
|
||||
|
||||
bool has_error() const { return m_error != 0; }
|
||||
|
||||
ByteBuffer read(int max_size);
|
||||
ByteBuffer read_line(int max_size);
|
||||
ByteBuffer read_all();
|
||||
|
||||
// FIXME: I would like this to be const but currently it needs to call populate_read_buffer().
|
||||
bool can_read_line();
|
||||
|
||||
bool can_read() const;
|
||||
|
||||
virtual bool open(GIODevice::OpenMode) = 0;
|
||||
virtual bool close();
|
||||
|
||||
virtual const char* class_name() const override { return "GIODevice"; }
|
||||
|
||||
protected:
|
||||
explicit GIODevice(CObject* parent = nullptr);
|
||||
|
||||
void set_fd(int fd) { m_fd = fd; }
|
||||
void set_mode(OpenMode mode) { m_mode = mode; }
|
||||
void set_error(int error) { m_error = error; }
|
||||
void set_eof(bool eof) { m_eof = eof; }
|
||||
|
||||
private:
|
||||
bool populate_read_buffer();
|
||||
bool can_read_from_fd() const;
|
||||
|
||||
int m_fd { -1 };
|
||||
int m_error { 0 };
|
||||
bool m_eof { false };
|
||||
OpenMode m_mode { NotOpen };
|
||||
Vector<byte> m_buffered_data;
|
||||
};
|
|
@ -1,93 +0,0 @@
|
|||
#include <LibGUI/GSocket.h>
|
||||
#include <LibCore/CNotifier.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
GSocket::GSocket(Type type, CObject* parent)
|
||||
: GIODevice(parent)
|
||||
, m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
GSocket::~GSocket()
|
||||
{
|
||||
}
|
||||
|
||||
bool GSocket::connect(const String& hostname, int port)
|
||||
{
|
||||
auto* hostent = gethostbyname(hostname.characters());
|
||||
if (!hostent) {
|
||||
dbgprintf("GSocket::connect: Unable to resolve '%s'\n", hostname.characters());
|
||||
return false;
|
||||
}
|
||||
|
||||
IPv4Address host_address((const byte*)hostent->h_addr_list[0]);
|
||||
dbgprintf("GSocket::connect: Resolved '%s' to %s\n", hostname.characters(), host_address.to_string().characters());
|
||||
return connect(host_address, port);
|
||||
}
|
||||
|
||||
bool GSocket::connect(const GSocketAddress& address, int port)
|
||||
{
|
||||
ASSERT(!is_connected());
|
||||
ASSERT(address.type() == GSocketAddress::Type::IPv4);
|
||||
ASSERT(port > 0 && port <= 65535);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
auto ipv4_address = address.ipv4_address();
|
||||
memcpy(&addr.sin_addr.s_addr, &ipv4_address, sizeof(IPv4Address));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
m_destination_address = address;
|
||||
m_destination_port = port;
|
||||
|
||||
printf("Connecting to %s...", address.to_string().characters());
|
||||
fflush(stdout);
|
||||
int rc = ::connect(fd(), (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (rc < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
printf("in progress.\n");
|
||||
m_notifier = make<CNotifier>(fd(), CNotifier::Event::Write);
|
||||
m_notifier->on_ready_to_write = [this] {
|
||||
printf("%s{%p} connected!\n", class_name(), this);
|
||||
m_connected = true;
|
||||
m_notifier->set_event_mask(CNotifier::Event::None);
|
||||
if (on_connected)
|
||||
on_connected();
|
||||
};
|
||||
return true;
|
||||
}
|
||||
perror("connect");
|
||||
exit(1);
|
||||
}
|
||||
printf("ok!\n");
|
||||
m_connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteBuffer GSocket::receive(int max_size)
|
||||
{
|
||||
auto buffer = read(max_size);
|
||||
if (eof()) {
|
||||
dbgprintf("GSocket{%p}: Connection appears to have closed in receive().\n", this);
|
||||
m_connected = false;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool GSocket::send(const ByteBuffer& data)
|
||||
{
|
||||
int nsent = ::send(fd(), data.pointer(), data.size(), 0);
|
||||
if (nsent < 0) {
|
||||
set_error(nsent);
|
||||
return false;
|
||||
}
|
||||
ASSERT(nsent == data.size());
|
||||
return true;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibGUI/GIODevice.h>
|
||||
#include <LibGUI/GSocketAddress.h>
|
||||
|
||||
class CNotifier;
|
||||
|
||||
class GSocket : public GIODevice {
|
||||
public:
|
||||
enum class Type { Invalid, TCP, UDP };
|
||||
virtual ~GSocket() override;
|
||||
|
||||
bool connect(const String& hostname, int port);
|
||||
bool connect(const GSocketAddress&, int port);
|
||||
|
||||
ByteBuffer receive(int max_size);
|
||||
bool send(const ByteBuffer&);
|
||||
|
||||
bool is_connected() const { return m_connected; }
|
||||
|
||||
GSocketAddress source_address() const { return m_source_address; }
|
||||
int source_port() const { return m_source_port; }
|
||||
|
||||
GSocketAddress destination_address() const { return m_source_address; }
|
||||
int destination_port() const { return m_destination_port; }
|
||||
|
||||
Function<void()> on_connected;
|
||||
|
||||
virtual const char* class_name() const override { return "GSocket"; }
|
||||
|
||||
protected:
|
||||
GSocket(Type, CObject* parent);
|
||||
|
||||
GSocketAddress m_source_address;
|
||||
GSocketAddress m_destination_address;
|
||||
int m_source_port { -1 };
|
||||
int m_destination_port { -1 };
|
||||
bool m_connected { false };
|
||||
|
||||
private:
|
||||
virtual bool open(GIODevice::OpenMode) override { ASSERT_NOT_REACHED(); }
|
||||
Type m_type { Type::Invalid };
|
||||
OwnPtr<CNotifier> m_notifier;
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Kernel/Net/IPv4.h>
|
||||
|
||||
class GSocketAddress {
|
||||
public:
|
||||
enum class Type { Invalid, IPv4, Local };
|
||||
|
||||
GSocketAddress() { }
|
||||
GSocketAddress(const IPv4Address& address)
|
||||
: m_type(Type::IPv4)
|
||||
, m_ipv4_address(address)
|
||||
{
|
||||
}
|
||||
|
||||
Type type() const { return m_type; }
|
||||
bool is_valid() const { return m_type != Type::Invalid; }
|
||||
IPv4Address ipv4_address() const { return m_ipv4_address; }
|
||||
|
||||
String to_string() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::IPv4: return m_ipv4_address.to_string();
|
||||
default: return "[GSocketAddress]";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Type m_type { Type::Invalid };
|
||||
IPv4Address m_ipv4_address;
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
#include <LibGUI/GTCPSocket.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
GTCPSocket::GTCPSocket(CObject* parent)
|
||||
: GSocket(GSocket::Type::TCP, parent)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
if (fd < 0) {
|
||||
set_error(fd);
|
||||
} else {
|
||||
set_fd(fd);
|
||||
set_mode(GIODevice::ReadWrite);
|
||||
set_error(0);
|
||||
}
|
||||
}
|
||||
|
||||
GTCPSocket::~GTCPSocket()
|
||||
{
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#include <LibGUI/GSocket.h>
|
||||
|
||||
class GTCPSocket final : public GSocket {
|
||||
public:
|
||||
explicit GTCPSocket(CObject* parent);
|
||||
virtual ~GTCPSocket() override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
@ -10,8 +10,6 @@ SHAREDGRAPHICS_OBJS = \
|
|||
|
||||
LIBGUI_OBJS = \
|
||||
GPainter.o \
|
||||
GIODevice.o \
|
||||
GFile.o \
|
||||
GButton.o \
|
||||
GCheckBox.o \
|
||||
GEventLoop.o \
|
||||
|
@ -39,8 +37,6 @@ LIBGUI_OBJS = \
|
|||
GSortingProxyModel.o \
|
||||
GStackWidget.o \
|
||||
GScrollableWidget.o \
|
||||
GSocket.o \
|
||||
GTCPSocket.o \
|
||||
GMessageBox.o \
|
||||
GInputBox.o \
|
||||
GDialog.o \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue