posix.hpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#pragma once


#include <felspar/io/socket_descriptor.hpp>
#include <felspar/exceptions/system_error.hpp>

#include <cstdint>

#if __has_include(<unistd.h>)
#include <unistd.h>
#endif


namespace felspar::posix {

A very simple type for RAII management of a file descriptor

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
    class fd {
        io::socket_descriptor f;

        static void close_socket_if_valid(io::socket_descriptor const s) {
            if (s != io::invalid_handle) {
#ifdef FELSPAR_WINSOCK2
                ::closesocket(s);
#else
                ::close(s);
#endif
            }
        }

      public:
        fd() : f{io::invalid_handle} {}
        explicit fd(io::socket_descriptor f) : f{f} {}
        fd(fd &&o) : f{std::exchange(o.f, io::invalid_handle)} {}
        fd(fd const &) = delete;
        ~fd() { close_socket_if_valid(f); }

        fd &operator=(fd &&o) {
            fd s{std::exchange(f, std::exchange(o.f, io::invalid_handle))};
            return *this;
        }
        fd &operator=(fd const &) = delete;

true if the file descriptor looks valid

46
47
48
49
        explicit operator bool() const noexcept {
            return f != io::invalid_handle;
        }
        io::socket_descriptor native_handle() const noexcept { return f; }

Release the file descriptor

53
54
55
        io::socket_descriptor release() noexcept {
            return std::exchange(f, io::invalid_handle);
        }

Close the FD

This performs a blocking close. You should use the warden's asynchronous close if you can.

63
64
65
66
67
        void close() noexcept {
            io::socket_descriptor c = std::exchange(f, io::invalid_handle);
            close_socket_if_valid(c);
        }
    };

select handling

Set the number of open file descriptors this process can use to the maximum allowed range. This is only set at a lower level due to the poor design of the select system call, so if we promise never to use select we can have a much higher number. Returns the old limit and the new limit

78
    std::pair<std::size_t, std::size_t> promise_to_never_use_select();

Set the listen queue length for the socket

82
83
84
85
86
87
88
89
90
91
92
93
    void
            listen(io::socket_descriptor fd,
                   int backlog,
                   felspar::source_location const & =
                           felspar::source_location::current());
    inline void
            listen(posix::fd const &fd,
                   int backlog,
                   felspar::source_location const &loc =
                           felspar::source_location::current()) {
        listen(fd.native_handle(), backlog, loc);
    }

Set a file descriptor to non-blocking mode

 97
 98
 99
100
101
102
103
104
105
106
    void set_non_blocking(
            io::socket_descriptor sock,
            felspar::source_location const & =
                    felspar::source_location::current());
    inline void set_non_blocking(
            fd const &sock,
            felspar::source_location const &loc =
                    felspar::source_location::current()) {
        return set_non_blocking(sock.native_handle(), loc);
    }

Set a socket port for re-use

110
111
112
113
114
115
116
117
118
119
    void set_reuse_port(
            io::socket_descriptor sock,
            felspar::source_location const & =
                    felspar::source_location::current());
    inline void set_reuse_port(
            fd const &sock,
            felspar::source_location const &loc =
                    felspar::source_location::current()) {
        return set_reuse_port(sock.native_handle(), loc);
    }

Bind

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    void
            bind(io::socket_descriptor sock,
                 std::uint32_t addr,
                 std::uint16_t port,
                 felspar::source_location const & =
                         felspar::source_location::current());
    inline void
            bind(fd const &sock,
                 std::uint32_t const addr,
                 std::uint16_t const port,
                 felspar::source_location const &loc =
                         felspar::source_location::current()) {
        posix::bind(sock.native_handle(), addr, port, loc);
    }
    inline void bind_to_any_address(
            io::socket_descriptor sock,
            std::uint16_t port,
            felspar::source_location const &loc =
                    felspar::source_location::current()) {
        posix::bind(sock, INADDR_ANY, port, loc);
    }
    inline void bind_to_any_address(
            fd const &sock,
            std::uint16_t const port,
            felspar::source_location const &loc =
                    felspar::source_location::current()) {
        posix::bind(sock.native_handle(), INADDR_ANY, port, loc);
    }


}