1
Fork 0
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:
Andreas Kling 2019-04-10 20:22:23 +02:00
parent fc1d3074de
commit cfd6e6cc36
19 changed files with 112 additions and 112 deletions

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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();

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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()
{
}

View file

@ -1,10 +0,0 @@
#include <LibGUI/GSocket.h>
class GTCPSocket final : public GSocket {
public:
explicit GTCPSocket(CObject* parent);
virtual ~GTCPSocket() override;
private:
};

View file

@ -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 \