forked from Bananymous/banan-os
				
			Kernel: Make nonblocking sockets unblocking :)
This commit is contained in:
		
							parent
							
								
									c9132d984b
								
							
						
					
					
						commit
						15045cc486
					
				|  | @ -169,6 +169,7 @@ namespace Kernel | ||||||
| 	private: | 	private: | ||||||
| 		BAN::WeakPtr<SharedFileData> m_shared_region; | 		BAN::WeakPtr<SharedFileData> m_shared_region; | ||||||
| 		friend class FileBackedRegion; | 		friend class FileBackedRegion; | ||||||
|  | 		friend class OpenFileDescriptorSet; | ||||||
| 		friend class SharedFileData; | 		friend class SharedFileData; | ||||||
| 		friend class TTY; | 		friend class TTY; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | @ -47,6 +47,9 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 		BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len); | 		BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len); | ||||||
| 
 | 
 | ||||||
|  | 		BAN::ErrorOr<size_t> recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len); | ||||||
|  | 		BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len); | ||||||
|  | 
 | ||||||
| 		BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const; | 		BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const; | ||||||
| 		BAN::ErrorOr<BAN::StringView> path_of(int) const; | 		BAN::ErrorOr<BAN::StringView> path_of(int) const; | ||||||
| 		BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int); | 		BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int); | ||||||
|  |  | ||||||
|  | @ -226,51 +226,33 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) | 	BAN::ErrorOr<size_t> TCPSocket::sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) | ||||||
| 	{ | 	{ | ||||||
|  | 		(void)address; | ||||||
|  | 		(void)address_len; | ||||||
|  | 
 | ||||||
| 		if (address) | 		if (address) | ||||||
| 			return BAN::Error::from_errno(EISCONN); | 			return BAN::Error::from_errno(EISCONN); | ||||||
| 		if (!m_has_connected) | 		if (!m_has_connected) | ||||||
| 			return BAN::Error::from_errno(ENOTCONN); | 			return BAN::Error::from_errno(ENOTCONN); | ||||||
| 
 | 
 | ||||||
| 		if (message.size() > m_send_window.buffer->size()) | 		while (m_send_window.data_size == m_send_window.buffer->size()) | ||||||
| 		{ |  | ||||||
| 			size_t nsent = 0; |  | ||||||
| 			while (nsent < message.size()) |  | ||||||
| 			{ |  | ||||||
| 				const size_t to_send = BAN::Math::min<size_t>(message.size() - nsent, m_send_window.buffer->size()); |  | ||||||
| 				TRY(sendto_impl(message.slice(nsent, to_send), address, address_len)); |  | ||||||
| 				nsent += to_send; |  | ||||||
| 			} |  | ||||||
| 			return nsent; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		while (true) |  | ||||||
| 		{ | 		{ | ||||||
| 			if (m_state != State::Established) | 			if (m_state != State::Established) | ||||||
| 				return return_with_maybe_zero(); | 				return return_with_maybe_zero(); | ||||||
| 			if (m_send_window.data_size + message.size() <= m_send_window.buffer->size()) |  | ||||||
| 				break; |  | ||||||
| 			LockFreeGuard free(m_mutex); | 			LockFreeGuard free(m_mutex); | ||||||
| 			TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false)); | 			TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		const size_t to_send = BAN::Math::min<size_t>(message.size(), m_send_window.buffer->size() - m_send_window.data_size); | ||||||
|  | 
 | ||||||
| 		{ | 		{ | ||||||
| 			auto* buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr()); | 			auto* buffer = reinterpret_cast<uint8_t*>(m_send_window.buffer->vaddr()); | ||||||
| 			memcpy(buffer + m_send_window.data_size, message.data(), message.size()); | 			memcpy(buffer + m_send_window.data_size, message.data(), to_send); | ||||||
| 			m_send_window.data_size += message.size(); | 			m_send_window.data_size += to_send; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		const uint32_t target_ack = m_send_window.start_seq + m_send_window.data_size; |  | ||||||
| 		m_thread_blocker.unblock(); | 		m_thread_blocker.unblock(); | ||||||
| 
 | 
 | ||||||
| 		while (m_send_window.current_ack < target_ack) | 		return to_send; | ||||||
| 		{ |  | ||||||
| 			if (m_state != State::Established) |  | ||||||
| 				return return_with_maybe_zero(); |  | ||||||
| 			LockFreeGuard free(m_mutex); |  | ||||||
| 			TRY(Thread::current().block_or_eintr_or_timeout_ms(m_thread_blocker, 100, false)); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return message.size(); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool TCPSocket::can_read_impl() const | 	bool TCPSocket::can_read_impl() const | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include <kernel/FS/Pipe.h> | #include <kernel/FS/Pipe.h> | ||||||
| #include <kernel/FS/VirtualFileSystem.h> | #include <kernel/FS/VirtualFileSystem.h> | ||||||
|  | #include <kernel/Lock/LockGuard.h> | ||||||
| #include <kernel/Networking/NetworkManager.h> | #include <kernel/Networking/NetworkManager.h> | ||||||
| #include <kernel/OpenFileDescriptorSet.h> | #include <kernel/OpenFileDescriptorSet.h> | ||||||
| 
 | 
 | ||||||
|  | @ -298,11 +299,13 @@ namespace Kernel | ||||||
| 	{ | 	{ | ||||||
| 		TRY(validate_fd(fd)); | 		TRY(validate_fd(fd)); | ||||||
| 		auto& open_file = m_open_files[fd]; | 		auto& open_file = m_open_files[fd]; | ||||||
|  | 		if (open_file.inode()->mode().ifsock()) | ||||||
|  | 			return recvfrom(fd, buffer, nullptr, nullptr); | ||||||
| 		if (!(open_file.status_flags() & O_RDONLY)) | 		if (!(open_file.status_flags() & O_RDONLY)) | ||||||
| 			return BAN::Error::from_errno(EBADF); | 			return BAN::Error::from_errno(EBADF); | ||||||
| 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read()) | 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read()) | ||||||
| 			return 0; | 			return 0; | ||||||
| 		size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer)); | 		const size_t nread = TRY(open_file.inode()->read(open_file.offset(), buffer)); | ||||||
| 		open_file.offset() += nread; | 		open_file.offset() += nread; | ||||||
| 		return nread; | 		return nread; | ||||||
| 	} | 	} | ||||||
|  | @ -311,13 +314,15 @@ namespace Kernel | ||||||
| 	{ | 	{ | ||||||
| 		TRY(validate_fd(fd)); | 		TRY(validate_fd(fd)); | ||||||
| 		auto& open_file = m_open_files[fd]; | 		auto& open_file = m_open_files[fd]; | ||||||
|  | 		if (open_file.inode()->mode().ifsock()) | ||||||
|  | 			return sendto(fd, buffer, nullptr, 0); | ||||||
| 		if (!(open_file.status_flags() & O_WRONLY)) | 		if (!(open_file.status_flags() & O_WRONLY)) | ||||||
| 			return BAN::Error::from_errno(EBADF); | 			return BAN::Error::from_errno(EBADF); | ||||||
| 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write()) | 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write()) | ||||||
| 			return 0; | 			return BAN::Error::from_errno(EWOULDBLOCK); | ||||||
| 		if (open_file.status_flags() & O_APPEND) | 		if (open_file.status_flags() & O_APPEND) | ||||||
| 			open_file.offset() = open_file.inode()->size(); | 			open_file.offset() = open_file.inode()->size(); | ||||||
| 		size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer)); | 		const size_t nwrite = TRY(open_file.inode()->write(open_file.offset(), buffer)); | ||||||
| 		open_file.offset() += nwrite; | 		open_file.offset() += nwrite; | ||||||
| 		return nwrite; | 		return nwrite; | ||||||
| 	} | 	} | ||||||
|  | @ -340,6 +345,43 @@ namespace Kernel | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	BAN::ErrorOr<size_t> OpenFileDescriptorSet::recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) | ||||||
|  | 	{ | ||||||
|  | 		TRY(validate_fd(fd)); | ||||||
|  | 		auto& open_file = m_open_files[fd]; | ||||||
|  | 		if (!open_file.inode()->mode().ifsock()) | ||||||
|  | 			return BAN::Error::from_errno(ENOTSOCK); | ||||||
|  | 		LockGuard _(open_file.inode()->m_mutex); | ||||||
|  | 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_read()) | ||||||
|  | 			return BAN::Error::from_errno(EWOULDBLOCK); | ||||||
|  | 		return open_file.inode()->recvfrom(buffer, address, address_len); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	BAN::ErrorOr<size_t> OpenFileDescriptorSet::sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len) | ||||||
|  | 	{ | ||||||
|  | 		TRY(validate_fd(fd)); | ||||||
|  | 		auto& open_file = m_open_files[fd]; | ||||||
|  | 		if (!open_file.inode()->mode().ifsock()) | ||||||
|  | 			return BAN::Error::from_errno(ENOTSOCK); | ||||||
|  | 		if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write()) | ||||||
|  | 			return BAN::Error::from_errno(EWOULDBLOCK); | ||||||
|  | 
 | ||||||
|  | 		LockGuard _(open_file.inode()->m_mutex); | ||||||
|  | 
 | ||||||
|  | 		size_t total_sent = 0; | ||||||
|  | 		while (total_sent < buffer.size()) | ||||||
|  | 		{ | ||||||
|  | 			if ((open_file.status_flags() & O_NONBLOCK) && !open_file.inode()->can_write()) | ||||||
|  | 				return total_sent; | ||||||
|  | 			const size_t nsend = TRY(open_file.inode()->sendto(buffer.slice(total_sent), address, address_len)); | ||||||
|  | 			if (nsend == 0) | ||||||
|  | 				return 0; | ||||||
|  | 			total_sent += nsend; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return total_sent; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const | 	BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const | ||||||
| 	{ | 	{ | ||||||
| 		TRY(validate_fd(fd)); | 		TRY(validate_fd(fd)); | ||||||
|  |  | ||||||
|  | @ -1321,16 +1321,8 @@ namespace Kernel | ||||||
| 		TRY(validate_pointer_access(arguments->message, arguments->length, false)); | 		TRY(validate_pointer_access(arguments->message, arguments->length, false)); | ||||||
| 		TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false)); | 		TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len, false)); | ||||||
| 
 | 
 | ||||||
| 		auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket)); | 		auto message = BAN::ConstByteSpan(static_cast<const uint8_t*>(arguments->message), arguments->length); | ||||||
| 		if (!inode->mode().ifsock()) | 		return TRY(m_open_file_descriptors.sendto(arguments->socket, message, arguments->dest_addr, arguments->dest_len)); | ||||||
| 			return BAN::Error::from_errno(ENOTSOCK); |  | ||||||
| 
 |  | ||||||
| 		const auto status_flags = TRY(m_open_file_descriptors.status_flags_of(arguments->socket)); |  | ||||||
| 		if ((status_flags & O_NONBLOCK) && !inode->can_write()) |  | ||||||
| 			return BAN::Error::from_errno(EAGAIN); |  | ||||||
| 
 |  | ||||||
| 		BAN::ConstByteSpan message { reinterpret_cast<const uint8_t*>(arguments->message), arguments->length }; |  | ||||||
| 		return TRY(inode->sendto(message, arguments->dest_addr, arguments->dest_len)); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments) | 	BAN::ErrorOr<long> Process::sys_recvfrom(sys_recvfrom_t* arguments) | ||||||
|  | @ -1349,16 +1341,8 @@ namespace Kernel | ||||||
| 			TRY(validate_pointer_access(arguments->address, *arguments->address_len, true)); | 			TRY(validate_pointer_access(arguments->address, *arguments->address_len, true)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket)); | 		auto message = BAN::ByteSpan(static_cast<uint8_t*>(arguments->buffer), arguments->length); | ||||||
| 		if (!inode->mode().ifsock()) | 		return TRY(m_open_file_descriptors.recvfrom(arguments->socket, message, arguments->address, arguments->address_len)); | ||||||
| 			return BAN::Error::from_errno(ENOTSOCK); |  | ||||||
| 
 |  | ||||||
| 		const auto status_flags = TRY(m_open_file_descriptors.status_flags_of(arguments->socket)); |  | ||||||
| 		if ((status_flags & O_NONBLOCK) && !inode->can_read()) |  | ||||||
| 			return BAN::Error::from_errno(EAGAIN); |  | ||||||
| 
 |  | ||||||
| 		BAN::ByteSpan buffer { reinterpret_cast<uint8_t*>(arguments->buffer), arguments->length }; |  | ||||||
| 		return TRY(inode->recvfrom(buffer, arguments->address, arguments->address_len)); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg) | 	BAN::ErrorOr<long> Process::sys_ioctl(int fildes, int request, void* arg) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue