mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:38:11 +00:00
LibGUI: Add GTCPSocket and base class GSocket (inherits from GIODevice.)
And use these to do the line-by-line reading automagically instead of having that logic in IRCClient. This will definitely come in handy.
This commit is contained in:
parent
d466f2634d
commit
8e3d0a23d5
12 changed files with 267 additions and 86 deletions
|
@ -26,6 +26,7 @@ IRCClient::IRCClient(const String& address, int port)
|
||||||
, m_nickname("anon")
|
, m_nickname("anon")
|
||||||
, m_log(IRCLogBuffer::create())
|
, m_log(IRCLogBuffer::create())
|
||||||
{
|
{
|
||||||
|
m_socket = new GTCPSocket(this);
|
||||||
m_client_window_list_model = new IRCWindowListModel(*this);
|
m_client_window_list_model = new IRCWindowListModel(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,37 +36,15 @@ IRCClient::~IRCClient()
|
||||||
|
|
||||||
bool IRCClient::connect()
|
bool IRCClient::connect()
|
||||||
{
|
{
|
||||||
if (m_socket_fd != -1) {
|
if (m_socket->is_connected())
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
|
||||||
|
|
||||||
m_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
IPv4Address ipv4_address(127, 0, 0, 1);
|
||||||
if (m_socket_fd < 0) {
|
bool success = m_socket->connect(GSocketAddress(ipv4_address), m_port);
|
||||||
perror("socket");
|
if (!success)
|
||||||
exit(1);
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
m_notifier = make<GNotifier>(m_socket->fd(), GNotifier::Read);
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons(m_port);
|
|
||||||
int rc = inet_pton(AF_INET, m_hostname.characters(), &addr.sin_addr);
|
|
||||||
if (rc < 0) {
|
|
||||||
perror("inet_pton");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Connecting to %s...", m_hostname.characters());
|
|
||||||
fflush(stdout);
|
|
||||||
rc = ::connect(m_socket_fd, (struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
if (rc < 0) {
|
|
||||||
perror("connect");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf("ok!\n");
|
|
||||||
|
|
||||||
m_notifier = make<GNotifier>(m_socket_fd, GNotifier::Read);
|
|
||||||
m_notifier->on_ready_to_read = [this] (GNotifier&) { receive_from_server(); };
|
m_notifier->on_ready_to_read = [this] (GNotifier&) { receive_from_server(); };
|
||||||
|
|
||||||
send_user();
|
send_user();
|
||||||
|
@ -78,35 +57,20 @@ bool IRCClient::connect()
|
||||||
|
|
||||||
void IRCClient::receive_from_server()
|
void IRCClient::receive_from_server()
|
||||||
{
|
{
|
||||||
char buffer[4096];
|
while (m_socket->can_read_line()) {
|
||||||
int nread = recv(m_socket_fd, buffer, sizeof(buffer) - 1, 0);
|
auto line = m_socket->read_line(4096);
|
||||||
if (nread < 0) {
|
if (line.is_null()) {
|
||||||
perror("recv");
|
if (!m_socket->is_connected()) {
|
||||||
exit(1);
|
printf("IRCClient: Connection closed!\n");
|
||||||
}
|
exit(1);
|
||||||
if (nread == 0) {
|
}
|
||||||
printf("IRCClient: Connection closed!\n");
|
ASSERT_NOT_REACHED();
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
buffer[nread] = '\0';
|
|
||||||
#if 0
|
|
||||||
printf("Received: '%s'\n", buffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int i = 0; i < nread; ++i) {
|
|
||||||
char ch = buffer[i];
|
|
||||||
if (ch == '\r')
|
|
||||||
continue;
|
|
||||||
if (ch == '\n') {
|
|
||||||
process_line();
|
|
||||||
m_line_buffer.clear_with_capacity();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
m_line_buffer.append(ch);
|
process_line(move(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRCClient::process_line()
|
void IRCClient::process_line(ByteBuffer&& line)
|
||||||
{
|
{
|
||||||
Message msg;
|
Message msg;
|
||||||
Vector<char> prefix;
|
Vector<char> prefix;
|
||||||
|
@ -121,7 +85,12 @@ void IRCClient::process_line()
|
||||||
InTrailingParameter,
|
InTrailingParameter,
|
||||||
} state = Start;
|
} state = Start;
|
||||||
|
|
||||||
for (char ch : m_line_buffer) {
|
for (int i = 0; i < line.size(); ++i) {
|
||||||
|
char ch = line[i];
|
||||||
|
if (ch == '\r')
|
||||||
|
continue;
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case Start:
|
case Start:
|
||||||
if (ch == ':') {
|
if (ch == ':') {
|
||||||
|
@ -175,8 +144,7 @@ void IRCClient::process_line()
|
||||||
|
|
||||||
void IRCClient::send(const String& text)
|
void IRCClient::send(const String& text)
|
||||||
{
|
{
|
||||||
int rc = ::send(m_socket_fd, text.characters(), text.length(), 0);
|
if (!m_socket->send(ByteBuffer::wrap((void*)text.characters(), text.length()))) {
|
||||||
if (rc < 0) {
|
|
||||||
perror("send");
|
perror("send");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/CircularQueue.h>
|
#include <AK/CircularQueue.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
|
#include <LibGUI/GTCPSocket.h>
|
||||||
#include "IRCLogBuffer.h"
|
#include "IRCLogBuffer.h"
|
||||||
#include "IRCWindow.h"
|
#include "IRCWindow.h"
|
||||||
|
|
||||||
|
@ -12,12 +13,12 @@ class IRCQuery;
|
||||||
class IRCWindowListModel;
|
class IRCWindowListModel;
|
||||||
class GNotifier;
|
class GNotifier;
|
||||||
|
|
||||||
class IRCClient {
|
class IRCClient final : public GObject {
|
||||||
friend class IRCChannel;
|
friend class IRCChannel;
|
||||||
friend class IRCQuery;
|
friend class IRCQuery;
|
||||||
public:
|
public:
|
||||||
IRCClient(const String& address, int port = 6667);
|
IRCClient(const String& address, int port = 6667);
|
||||||
~IRCClient();
|
virtual ~IRCClient() override;
|
||||||
|
|
||||||
bool connect();
|
bool connect();
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@ public:
|
||||||
IRCQuery& ensure_query(const String& name);
|
IRCQuery& ensure_query(const String& name);
|
||||||
IRCChannel& ensure_channel(const String& name);
|
IRCChannel& ensure_channel(const String& name);
|
||||||
|
|
||||||
|
const char* class_name() const override { return "IRCClient"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Message {
|
struct Message {
|
||||||
String prefix;
|
String prefix;
|
||||||
|
@ -72,7 +75,7 @@ private:
|
||||||
void send_nick();
|
void send_nick();
|
||||||
void send_pong(const String& server);
|
void send_pong(const String& server);
|
||||||
void send_privmsg(const String& target, const String&);
|
void send_privmsg(const String& target, const String&);
|
||||||
void process_line();
|
void process_line(ByteBuffer&&);
|
||||||
void handle_join(const Message&);
|
void handle_join(const Message&);
|
||||||
void handle_part(const Message&);
|
void handle_part(const Message&);
|
||||||
void handle_ping(const Message&);
|
void handle_ping(const Message&);
|
||||||
|
@ -84,8 +87,9 @@ private:
|
||||||
void handle_user_command(const String&);
|
void handle_user_command(const String&);
|
||||||
|
|
||||||
String m_hostname;
|
String m_hostname;
|
||||||
int m_port { 0 };
|
int m_port { 6667 };
|
||||||
int m_socket_fd { -1 };
|
|
||||||
|
GTCPSocket* m_socket { nullptr };
|
||||||
|
|
||||||
String m_nickname;
|
String m_nickname;
|
||||||
Vector<char> m_line_buffer;
|
Vector<char> m_line_buffer;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/NetworkOrdered.h>
|
#include <Kernel/NetworkOrdered.h>
|
||||||
#include <Kernel/StdLib.h>
|
|
||||||
|
|
||||||
enum class IPv4Protocol : word {
|
enum class IPv4Protocol : word {
|
||||||
ICMP = 1,
|
ICMP = 1,
|
||||||
|
@ -19,7 +18,10 @@ public:
|
||||||
IPv4Address() { }
|
IPv4Address() { }
|
||||||
IPv4Address(const byte data[4])
|
IPv4Address(const byte data[4])
|
||||||
{
|
{
|
||||||
memcpy(m_data, data, 4);
|
m_data[0] = data[0];
|
||||||
|
m_data[1] = data[1];
|
||||||
|
m_data[2] = data[2];
|
||||||
|
m_data[3] = data[3];
|
||||||
}
|
}
|
||||||
IPv4Address(byte a, byte b, byte c, byte d)
|
IPv4Address(byte a, byte b, byte c, byte d)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,17 +40,3 @@ bool GFile::open(GIODevice::OpenMode mode)
|
||||||
set_mode(mode);
|
set_mode(mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GFile::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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ public:
|
||||||
void set_filename(const String& filename) { m_filename = filename; }
|
void set_filename(const String& filename) { m_filename = filename; }
|
||||||
|
|
||||||
virtual bool open(GIODevice::OpenMode) override;
|
virtual bool open(GIODevice::OpenMode) override;
|
||||||
virtual bool close() override;
|
|
||||||
|
|
||||||
virtual const char* class_name() const override { return "GFile"; }
|
virtual const char* class_name() const override { return "GFile"; }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include <LibGUI/GIODevice.h>
|
#include <LibGUI/GIODevice.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
GIODevice::GIODevice(GObject* parent)
|
GIODevice::GIODevice(GObject* parent)
|
||||||
: GObject(parent)
|
: GObject(parent)
|
||||||
|
@ -44,26 +46,63 @@ ByteBuffer GIODevice::read(int max_size)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GIODevice::can_read() 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())
|
||||||
|
return false;
|
||||||
|
populate_read_buffer();
|
||||||
|
return m_buffered_data.contains_slow('\n');
|
||||||
|
}
|
||||||
|
|
||||||
ByteBuffer GIODevice::read_line(int max_size)
|
ByteBuffer GIODevice::read_line(int max_size)
|
||||||
{
|
{
|
||||||
if (m_fd < 0)
|
if (m_fd < 0)
|
||||||
return { };
|
return { };
|
||||||
if (!max_size)
|
if (!max_size)
|
||||||
return { };
|
return { };
|
||||||
auto line = ByteBuffer::create_uninitialized(max_size);
|
if (!can_read_line())
|
||||||
int line_index = 0;
|
return { };
|
||||||
while (line_index < line.size()) {
|
if (m_eof) {
|
||||||
if (line_index >= m_buffered_data.size()) {
|
if (m_buffered_data.size() > max_size) {
|
||||||
if (!populate_read_buffer())
|
dbgprintf("GIODevice::read_line: At EOF but there's more than max_size(%d) buffered\n", max_size);
|
||||||
return { };
|
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];
|
byte ch = m_buffered_data[line_index];
|
||||||
line[line_index++] = ch;
|
line[line_index++] = ch;
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
Vector<byte> new_buffered_data;
|
Vector<byte> new_buffered_data;
|
||||||
new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index);
|
new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index);
|
||||||
m_buffered_data = move(new_buffered_data);
|
m_buffered_data = move(new_buffered_data);
|
||||||
line.trim(line_index);
|
line[line_index] = '\0';
|
||||||
|
line.trim(line_index + 1);
|
||||||
|
dbgprintf("GIODevice::read_line: '%s'\n", line.pointer());
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +123,21 @@ bool GIODevice::populate_read_buffer()
|
||||||
set_eof(true);
|
set_eof(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
buffer.trim(nread);
|
||||||
m_buffered_data.append(buffer.pointer(), buffer.size());
|
m_buffered_data.append(buffer.pointer(), buffer.size());
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -29,8 +29,13 @@ public:
|
||||||
ByteBuffer read(int max_size);
|
ByteBuffer read(int max_size);
|
||||||
ByteBuffer read_line(int max_size);
|
ByteBuffer read_line(int max_size);
|
||||||
|
|
||||||
|
// 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 open(GIODevice::OpenMode) = 0;
|
||||||
virtual bool close() = 0;
|
virtual bool close();
|
||||||
|
|
||||||
virtual const char* class_name() const override { return "GIODevice"; }
|
virtual const char* class_name() const override { return "GIODevice"; }
|
||||||
|
|
||||||
|
|
64
LibGUI/GSocket.cpp
Normal file
64
LibGUI/GSocket.cpp
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <LibGUI/GSocket.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
GSocket::GSocket(Type type, GObject* parent)
|
||||||
|
: GIODevice(parent)
|
||||||
|
, m_type(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GSocket::~GSocket()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
printf("Connecting to %s...", address.to_string().characters());
|
||||||
|
fflush(stdout);
|
||||||
|
int rc = ::connect(fd(), (struct sockaddr*)&addr, sizeof(addr));
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("connect");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("ok!\n");
|
||||||
|
|
||||||
|
m_destination_address = address;
|
||||||
|
m_destination_port = port;
|
||||||
|
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;
|
||||||
|
}
|
68
LibGUI/GSocket.h
Normal file
68
LibGUI/GSocket.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibGUI/GIODevice.h>
|
||||||
|
#include <AK/AKString.h>
|
||||||
|
#include <Kernel/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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GSocket : public GIODevice {
|
||||||
|
public:
|
||||||
|
enum class Type { Invalid, TCP, UDP };
|
||||||
|
virtual ~GSocket() override;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "GSocket"; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GSocket(Type, GObject* 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 };
|
||||||
|
|
||||||
|
};
|
19
LibGUI/GTCPSocket.cpp
Normal file
19
LibGUI/GTCPSocket.cpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <LibGUI/GTCPSocket.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
GTCPSocket::GTCPSocket(GObject* parent)
|
||||||
|
: GSocket(GSocket::Type::TCP, parent)
|
||||||
|
{
|
||||||
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
set_error(fd);
|
||||||
|
} else {
|
||||||
|
set_fd(fd);
|
||||||
|
set_mode(GIODevice::ReadWrite);
|
||||||
|
set_error(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GTCPSocket::~GTCPSocket()
|
||||||
|
{
|
||||||
|
}
|
10
LibGUI/GTCPSocket.h
Normal file
10
LibGUI/GTCPSocket.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <LibGUI/GSocket.h>
|
||||||
|
|
||||||
|
class GTCPSocket final : public GSocket {
|
||||||
|
public:
|
||||||
|
explicit GTCPSocket(GObject* parent);
|
||||||
|
virtual ~GTCPSocket() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
|
@ -40,6 +40,8 @@ LIBGUI_OBJS = \
|
||||||
GStackWidget.o \
|
GStackWidget.o \
|
||||||
GEvent.o \
|
GEvent.o \
|
||||||
GScrollableWidget.o \
|
GScrollableWidget.o \
|
||||||
|
GSocket.o \
|
||||||
|
GTCPSocket.o \
|
||||||
GWindow.o
|
GWindow.o
|
||||||
|
|
||||||
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue