summaryrefslogtreecommitdiff
path: root/Kernel/Net/Socket.cpp
blob: 83c7256d00864245363ae86aa9eb2668e15530b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <Kernel/Net/Socket.h>
#include <Kernel/Net/LocalSocket.h>
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/UnixTypes.h>
#include <Kernel/Process.h>
#include <LibC/errno_numbers.h>

KResultOr<Retained<Socket>> Socket::create(int domain, int type, int protocol)
{
    (void)protocol;
    switch (domain) {
    case AF_LOCAL:
        return LocalSocket::create(type & SOCK_TYPE_MASK);
    case AF_INET:
        return IPv4Socket::create(type & SOCK_TYPE_MASK, protocol);
    default:
        return KResult(-EAFNOSUPPORT);
    }
}

Socket::Socket(int domain, int type, int protocol)
    : m_lock("Socket")
    , m_domain(domain)
    , m_type(type)
    , m_protocol(protocol)
{
    m_origin_pid = current->pid();
}

Socket::~Socket()
{
}

KResult Socket::listen(int backlog)
{
    LOCKER(m_lock);
    if (m_type != SOCK_STREAM)
        return KResult(-EOPNOTSUPP);
    m_backlog = backlog;
    kprintf("Socket{%p} listening with backlog=%d\n", this, m_backlog);
    return KSuccess;
}

RetainPtr<Socket> Socket::accept()
{
    LOCKER(m_lock);
    if (m_pending.is_empty())
        return nullptr;
    auto client = m_pending.take_first();
    ASSERT(!client->is_connected());
    client->m_connected = true;
    return client;
}

KResult Socket::queue_connection_from(Socket& peer)
{
    LOCKER(m_lock);
    if (m_pending.size() >= m_backlog)
        return KResult(-ECONNREFUSED);
    m_pending.append(peer);
    return KSuccess;
}

KResult Socket::setsockopt(int level, int option, const void* value, socklen_t value_size)
{
    ASSERT(level == SOL_SOCKET);
    switch (option) {
    case SO_SNDTIMEO:
        if (value_size != sizeof(timeval))
            return KResult(-EINVAL);
        m_send_timeout = *(const timeval*)value;
        return KSuccess;
    case SO_RCVTIMEO:
        if (value_size != sizeof(timeval))
            return KResult(-EINVAL);
        m_receive_timeout = *(const timeval*)value;
        return KSuccess;
    default:
        kprintf("%s(%u): setsockopt() at SOL_SOCKET with unimplemented option %d\n", option);
        return KResult(-ENOPROTOOPT);
    }
}

KResult Socket::getsockopt(int level, int option, void* value, socklen_t* value_size)
{
    ASSERT(level == SOL_SOCKET);
    switch (option) {
    case SO_SNDTIMEO:
        if (*value_size < sizeof(timeval))
            return KResult(-EINVAL);
        *(timeval*)value = m_send_timeout;
        *value_size = sizeof(timeval);
        return KSuccess;
    case SO_RCVTIMEO:
        if (*value_size < sizeof(timeval))
            return KResult(-EINVAL);
        *(timeval*)value = m_receive_timeout;
        *value_size = sizeof(timeval);
        return KSuccess;
    default:
        kprintf("%s(%u): getsockopt() at SOL_SOCKET with unimplemented option %d\n", option);
        return KResult(-ENOPROTOOPT);
    }
}

void Socket::load_receive_deadline()
{
    kgettimeofday(m_receive_deadline);
    m_receive_deadline.tv_sec += m_receive_timeout.tv_sec;
    m_receive_deadline.tv_usec += m_receive_timeout.tv_usec;
    m_receive_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
    m_receive_deadline.tv_usec %= 1000000;
}

void Socket::load_send_deadline()
{
    kgettimeofday(m_send_deadline);
    m_send_deadline.tv_sec += m_send_timeout.tv_sec;
    m_send_deadline.tv_usec += m_send_timeout.tv_usec;
    m_send_deadline.tv_sec += (m_send_timeout.tv_usec / 1000000) * 1;
    m_send_deadline.tv_usec %= 1000000;
}