mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +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); |  | ||||||
|     } |  | ||||||
|     if (nread == 0) { |  | ||||||
|                 printf("IRCClient: Connection closed!\n"); |                 printf("IRCClient: Connection closed!\n"); | ||||||
|                 exit(1); |                 exit(1); | ||||||
|             } |             } | ||||||
|     buffer[nread] = '\0'; |             ASSERT_NOT_REACHED(); | ||||||
| #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
	
	 Andreas Kling
						Andreas Kling