summaryrefslogtreecommitdiff
path: root/src/io/fd.hpp
blob: 517c7af8e9a7d175aac28926deb91478c5a33a1b (plain) (blame)
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
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#pragma once
//    io/fd.hpp - typesafe (but not scopesafe) file descriptors
//
//    Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
//
//    This file is part of The Mana World (Athena server)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "fwd.hpp"

#include <sys/select.h>
#include <sys/socket.h>

#include "../diagnostics.hpp"


namespace tmwa
{
namespace io
{
    class FD
    {
    private:
        int fd;

        explicit
        FD(int f)
        : fd(f)
        {}
    public:
        FD()
        : fd(-1)
        {}

        int uncast_dammit() { return fd; }
        static
        FD cast_dammit(int f) { return FD(f); }

        static
        FD stdin() { return FD(0); }
        static
        FD stdout() { return FD(1); }
        static
        FD stderr() { return FD(2); }

        static const int DEFAULT_MODE = 0666;

        static
        FD open(ZString path, int flags, int mode=DEFAULT_MODE);
        static
        FD openat(FD dirfd, ZString path, int flags, int mode=DEFAULT_MODE);
        static
        FD socket(int domain, int type, int protocol);
        FD accept(struct sockaddr *addr, socklen_t *addrlen);
        static
        int pipe(FD& r, FD& w);
        static
        int pipe2(FD& r, FD& w, int flags);

        static
        FD sysconf_SC_OPEN_MAX();

        FD next() { return FD(fd + 1); }
        FD prev() { return FD(fd - 1); }

        ssize_t read(void *buf, size_t count);
        ssize_t write(const void *buf, size_t count);
        ssize_t send(const void *buf, size_t count, int flags);
        ssize_t sendto(const void *buf, size_t count, int flags,
                   const struct sockaddr *dest_addr, socklen_t addrlen);
        ssize_t sendmsg(const struct msghdr *msg, int flags);
        int sendmmsg(struct mmsghdr *msgvec, unsigned int vlen,
             unsigned int flags);
        ssize_t recv(void *buf, size_t len, int flags);
        ssize_t recvfrom(void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
        ssize_t recvmsg(struct msghdr *msg, int flags);
        ssize_t pread(void *buf, size_t count, off_t offset);
        ssize_t pwrite(const void *buf, size_t count, off_t offset);
        ssize_t readv(const struct iovec *iov, int iovcnt);
        ssize_t writev(const struct iovec *iov, int iovcnt);
        ssize_t preadv(const struct iovec *iov, int iovcnt, off_t offset);
        ssize_t pwritev(const struct iovec *iov, int iovcnt, off_t offset);

        int close();
        int shutdown(int);
        int getsockopt(int level, int optname, void *optval, socklen_t *optlen);
        int setsockopt(int level, int optname, const void *optval, socklen_t optlen);
        // ...
        int fcntl(int cmd);
        int fcntl(int cmd, int arg);
        int fcntl(int cmd, void *arg);
        int listen(int backlog);
        int bind(const struct sockaddr *addr, socklen_t addrlen);
        int connect(const struct sockaddr *addr, socklen_t addrlen);
        FD dup();
        FD dup2(FD newfd);
        FD dup3(FD newfd, int flags);


        friend
        bool operator == (FD l, FD r)
        {
            return l.fd == r.fd;
        }
        friend
        bool operator != (FD l, FD r)
        {
            return l.fd != r.fd;
        }
        friend
        bool operator < (FD l, FD r)
        {
            return l.fd < r.fd;
        }
        friend
        bool operator <= (FD l, FD r)
        {
            return l.fd <= r.fd;
        }
        friend
        bool operator > (FD l, FD r)
        {
            return l.fd > r.fd;
        }
        friend
        bool operator >= (FD l, FD r)
        {
            return l.fd >= r.fd;
        }
    };

    class FD_Set
    {
    private:
        fd_set fds;
    public:
        FD_Set()
        {
            FD_ZERO(&fds);
        }
        void clr(FD fd)
        {
            DIAG_PUSH();
            DIAG_I(old_style_cast);
            FD_CLR(fd.uncast_dammit(), &fds);
            DIAG_POP();
        }
        bool isset(FD fd)
        {
            DIAG_PUSH();
            DIAG_I(old_style_cast);
            return FD_ISSET(fd.uncast_dammit(), &fds);
            DIAG_POP();
        }
        void set(FD fd)
        {
            DIAG_PUSH();
            DIAG_I(old_style_cast);
            FD_SET(fd.uncast_dammit(), &fds);
            DIAG_POP();
        }

        static
        int select(int nfds, FD_Set *readfds, FD_Set *writefds, FD_Set *exceptfds, struct timeval *timeout);
        static
        int pselect(int nfds, FD_Set *readfds, FD_Set *writefds, FD_Set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
    };
} // namespace io
} // namespace tmwa