Serenity Operating System
at portability 181 lines 6.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/StringBuilder.h> 28#include <Kernel/FileSystem/FileDescription.h> 29#include <Kernel/Net/IPv4Socket.h> 30#include <Kernel/Net/LocalSocket.h> 31#include <Kernel/Net/Socket.h> 32#include <Kernel/Process.h> 33#include <Kernel/UnixTypes.h> 34#include <LibC/errno_numbers.h> 35 36//#define SOCKET_DEBUG 37 38namespace Kernel { 39 40KResultOr<NonnullRefPtr<Socket>> Socket::create(int domain, int type, int protocol) 41{ 42 switch (domain) { 43 case AF_LOCAL: 44 return LocalSocket::create(type & SOCK_TYPE_MASK); 45 case AF_INET: 46 return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol); 47 default: 48 return KResult(-EAFNOSUPPORT); 49 } 50} 51 52Socket::Socket(int domain, int type, int protocol) 53 : m_domain(domain) 54 , m_type(type) 55 , m_protocol(protocol) 56{ 57 auto& process = *Process::current; 58 m_origin = { process.pid(), process.uid(), process.gid() }; 59} 60 61Socket::~Socket() 62{ 63} 64 65void Socket::set_setup_state(SetupState new_setup_state) 66{ 67#ifdef SOCKET_DEBUG 68 kprintf("%s(%u) Socket{%p} setup state moving from %s to %s\n", Process::current->name().characters(), Process::current->pid(), this, to_string(m_setup_state), to_string(new_setup_state)); 69#endif 70 71 m_setup_state = new_setup_state; 72} 73 74RefPtr<Socket> Socket::accept() 75{ 76 LOCKER(m_lock); 77 if (m_pending.is_empty()) 78 return nullptr; 79#ifdef SOCKET_DEBUG 80 kprintf("%s(%u) Socket{%p} de-queueing connection\n", Process::current->name().characters(), Process::current->pid(), this); 81#endif 82 auto client = m_pending.take_first(); 83 ASSERT(!client->is_connected()); 84 auto& process = *Process::current; 85 client->m_acceptor = { process.pid(), process.uid(), process.gid() }; 86 client->m_connected = true; 87 client->m_role = Role::Accepted; 88 return client; 89} 90 91KResult Socket::queue_connection_from(NonnullRefPtr<Socket> peer) 92{ 93#ifdef SOCKET_DEBUG 94 kprintf("%s(%u) Socket{%p} queueing connection\n", Process::current->name().characters(), Process::current->pid(), this); 95#endif 96 LOCKER(m_lock); 97 if (m_pending.size() >= m_backlog) 98 return KResult(-ECONNREFUSED); 99 m_pending.append(peer); 100 return KSuccess; 101} 102 103KResult Socket::setsockopt(int level, int option, const void* value, socklen_t value_size) 104{ 105 ASSERT(level == SOL_SOCKET); 106 switch (option) { 107 case SO_SNDTIMEO: 108 if (value_size != sizeof(timeval)) 109 return KResult(-EINVAL); 110 m_send_timeout = *(const timeval*)value; 111 return KSuccess; 112 case SO_RCVTIMEO: 113 if (value_size != sizeof(timeval)) 114 return KResult(-EINVAL); 115 m_receive_timeout = *(const timeval*)value; 116 return KSuccess; 117 default: 118 dbg() << "setsockopt(" << option << ") at SOL_SOCKET not implemented."; 119 return KResult(-ENOPROTOOPT); 120 } 121} 122 123KResult Socket::getsockopt(FileDescription&, int level, int option, void* value, socklen_t* value_size) 124{ 125 ASSERT(level == SOL_SOCKET); 126 switch (option) { 127 case SO_SNDTIMEO: 128 if (*value_size < sizeof(timeval)) 129 return KResult(-EINVAL); 130 *(timeval*)value = m_send_timeout; 131 *value_size = sizeof(timeval); 132 return KSuccess; 133 case SO_RCVTIMEO: 134 if (*value_size < sizeof(timeval)) 135 return KResult(-EINVAL); 136 *(timeval*)value = m_receive_timeout; 137 *value_size = sizeof(timeval); 138 return KSuccess; 139 case SO_ERROR: 140 if (*value_size < sizeof(int)) 141 return KResult(-EINVAL); 142 dbg() << "getsockopt(SO_ERROR): FIXME!"; 143 *(int*)value = 0; 144 *value_size = sizeof(int); 145 return KSuccess; 146 default: 147 dbg() << "getsockopt(" << option << ") at SOL_SOCKET not implemented."; 148 return KResult(-ENOPROTOOPT); 149 } 150} 151 152ssize_t Socket::read(FileDescription& description, u8* buffer, ssize_t size) 153{ 154 if (is_shut_down_for_reading()) 155 return 0; 156 return recvfrom(description, buffer, size, 0, nullptr, 0); 157} 158 159ssize_t Socket::write(FileDescription& description, const u8* data, ssize_t size) 160{ 161 if (is_shut_down_for_writing()) 162 return -EPIPE; 163 return sendto(description, data, size, 0, nullptr, 0); 164} 165 166KResult Socket::shutdown(int how) 167{ 168 if (type() == SOCK_STREAM && !is_connected()) 169 return KResult(-ENOTCONN); 170 if (m_role == Role::Listener) 171 return KResult(-ENOTCONN); 172 if (!m_shut_down_for_writing && (how & SHUT_WR)) 173 shut_down_for_writing(); 174 if (!m_shut_down_for_reading && (how & SHUT_RD)) 175 shut_down_for_reading(); 176 m_shut_down_for_reading |= (how & SHUT_RD) != 0; 177 m_shut_down_for_writing |= (how & SHUT_WR) != 0; 178 return KSuccess; 179} 180 181}