summaryrefslogtreecommitdiff
path: root/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/io')
-rw-r--r--src/io/fd.cpp164
-rw-r--r--src/io/fd.hpp159
-rw-r--r--src/io/line.cpp6
-rw-r--r--src/io/line.hpp5
-rw-r--r--src/io/line_test.cpp20
-rw-r--r--src/io/lock.cpp41
-rw-r--r--src/io/read.cpp18
-rw-r--r--src/io/read.hpp5
-rw-r--r--src/io/read_test.cpp20
-rw-r--r--src/io/write.cpp36
-rw-r--r--src/io/write.hpp6
-rw-r--r--src/io/write_test.cpp19
12 files changed, 414 insertions, 85 deletions
diff --git a/src/io/fd.cpp b/src/io/fd.cpp
new file mode 100644
index 0000000..87d3967
--- /dev/null
+++ b/src/io/fd.cpp
@@ -0,0 +1,164 @@
+#include "fd.hpp"
+// io/fd.cpp - 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 <fcntl.h>
+#include <unistd.h>
+
+#include "../strings/zstring.hpp"
+
+
+namespace io
+{
+ FD FD::open(ZString path, int flags, int mode)
+ {
+ return FD(::open(path.c_str(), flags, mode));
+ }
+ FD FD::socket(int domain, int type, int protocol)
+ {
+ return FD(::socket(domain, type, protocol));
+ }
+ FD FD::accept(struct sockaddr *addr, socklen_t *addrlen)
+ {
+ return FD(::accept(fd, addr, addrlen));
+ }
+ int FD::pipe(FD& r, FD& w)
+ {
+ int tmp[2] = {-1, -1};
+ int rv = ::pipe(tmp);
+ r = FD(tmp[0]);
+ w = FD(tmp[1]);
+ return rv;
+ }
+ int FD::pipe2(FD& r, FD& w, int flags)
+ {
+ int tmp[2] = {-1, -1};
+ int rv = ::pipe2(tmp, flags);
+ r = FD(tmp[0]);
+ w = FD(tmp[1]);
+ return rv;
+ }
+ FD FD::sysconf_SC_OPEN_MAX()
+ {
+ return FD(::sysconf(_SC_OPEN_MAX));
+ }
+
+ ssize_t FD::read(void *buf, size_t count)
+ {
+ return ::read(fd, buf, count);
+ }
+ ssize_t FD::write(const void *buf, size_t count)
+ {
+ return ::write(fd, buf, count);
+ }
+ ssize_t FD::pread(void *buf, size_t count, off_t offset)
+ {
+ return ::pread(fd, buf, count, offset);
+ }
+ ssize_t FD::pwrite(const void *buf, size_t count, off_t offset)
+ {
+ return ::pwrite(fd, buf, count, offset);
+ }
+ ssize_t FD::readv(const struct iovec *iov, int iovcnt)
+ {
+ return ::readv(fd, iov, iovcnt);
+ }
+ ssize_t FD::writev(const struct iovec *iov, int iovcnt)
+ {
+ return ::writev(fd, iov, iovcnt);
+ }
+ ssize_t FD::preadv(const struct iovec *iov, int iovcnt, off_t offset)
+ {
+ return ::preadv(fd, iov, iovcnt, offset);
+ }
+ ssize_t FD::pwritev(const struct iovec *iov, int iovcnt, off_t offset)
+ {
+ return ::pwritev(fd, iov, iovcnt, offset);
+ }
+
+ int FD::close()
+ {
+ return ::close(fd);
+ }
+ int FD::shutdown(int how)
+ {
+ return ::shutdown(fd, how);
+ }
+ int FD::getsockopt(int level, int optname, void *optval, socklen_t *optlen)
+ {
+ return ::getsockopt(fd, level, optname, optval, optlen);
+ }
+ int FD::setsockopt(int level, int optname, const void *optval, socklen_t optlen)
+ {
+ return ::setsockopt(fd, level, optname, optval, optlen);
+ }
+ int FD::fcntl(int cmd)
+ {
+ return ::fcntl(fd, cmd);
+ }
+ int FD::fcntl(int cmd, int arg)
+ {
+ return ::fcntl(fd, cmd, arg);
+ }
+ int FD::fcntl(int cmd, void *arg)
+ {
+ return ::fcntl(fd, cmd, arg);
+ }
+ int FD::listen(int backlog)
+ {
+ return ::listen(fd, backlog);
+ }
+ int FD::bind(const struct sockaddr *addr, socklen_t addrlen)
+ {
+ return ::bind(fd, addr, addrlen);
+ }
+ int FD::connect(const struct sockaddr *addr, socklen_t addrlen)
+ {
+ return ::connect(fd, addr, addrlen);
+ }
+ FD FD::dup()
+ {
+ return FD(::dup(fd));
+ }
+ FD FD::dup2(FD newfd)
+ {
+ return FD(::dup2(fd, newfd.fd));
+ }
+ FD FD::dup3(FD newfd, int flags)
+ {
+ return FD(::dup3(fd, newfd.fd, flags));
+ }
+
+ int FD_Set::select(int nfds, FD_Set *readfds, FD_Set *writefds, FD_Set *exceptfds, struct timeval *timeout)
+ {
+ return ::select(nfds,
+ readfds ? &readfds->fds : nullptr,
+ writefds ? &writefds->fds : nullptr,
+ exceptfds ? &exceptfds->fds : nullptr,
+ timeout);
+ }
+ int FD_Set::pselect(int nfds, FD_Set *readfds, FD_Set *writefds, FD_Set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask)
+ {
+ return ::pselect(nfds,
+ readfds ? &readfds->fds : nullptr,
+ writefds ? &writefds->fds : nullptr,
+ exceptfds ? &exceptfds->fds : nullptr,
+ timeout, sigmask);
+ }
+} // namespace io
diff --git a/src/io/fd.hpp b/src/io/fd.hpp
new file mode 100644
index 0000000..e4bcff7
--- /dev/null
+++ b/src/io/fd.hpp
@@ -0,0 +1,159 @@
+#ifndef TMWA_IO_FD_HPP
+#define TMWA_IO_FD_HPP
+// 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 "../sanity.hpp"
+
+# include <sys/select.h>
+# include <sys/socket.h>
+
+# include <unistd.h>
+
+# include "../strings/fwd.hpp"
+
+
+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
+ FD open(ZString path, int flags, int mode=0666);
+ 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 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)
+ {
+ FD_CLR(fd.uncast_dammit(), &fds);
+ }
+ bool isset(FD fd)
+ {
+ return FD_ISSET(fd.uncast_dammit(), &fds);
+ }
+ void set(FD fd)
+ {
+ FD_SET(fd.uncast_dammit(), &fds);
+ }
+
+ 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
+
+#endif //TMWA_IO_FD_HPP
diff --git a/src/io/line.cpp b/src/io/line.cpp
index 09dd8fb..83f439d 100644
--- a/src/io/line.cpp
+++ b/src/io/line.cpp
@@ -25,7 +25,7 @@
#include "../strings/mstring.hpp"
#include "../strings/zstring.hpp"
-#include "../io/cxxstdio.hpp"
+#include "cxxstdio.hpp"
#include "../poison.hpp"
@@ -62,7 +62,7 @@ namespace io
: filename(name), line(0), column(0), rf(name)
{}
- LineReader::LineReader(ZString name, int fd)
+ LineReader::LineReader(ZString name, FD fd)
: filename(name), line(0), column(0), rf(fd)
{}
@@ -94,7 +94,7 @@ namespace io
}
// sigh, copy-paste
// in just a couple months I can drop support for gcc 4.6 though
- LineCharReader::LineCharReader(ZString name, int fd)
+ LineCharReader::LineCharReader(ZString name, FD fd)
: LineReader(name, fd)
{
column = 1; // not 0, not whole line
diff --git a/src/io/line.hpp b/src/io/line.hpp
index 6dccfd9..78e1d25 100644
--- a/src/io/line.hpp
+++ b/src/io/line.hpp
@@ -24,6 +24,7 @@
# include "../strings/fstring.hpp"
# include "../strings/zstring.hpp"
+# include "fd.hpp"
# include "read.hpp"
@@ -67,7 +68,7 @@ namespace io
LineReader(ZString name);
LineReader(LineReader&&) = delete;
// needed for unit tests
- LineReader(ZString name, int fd);
+ LineReader(ZString name, FD fd);
bool read_line(Line& l);
bool is_open();
@@ -80,7 +81,7 @@ namespace io
explicit
LineCharReader(ZString name);
LineCharReader(LineCharReader&&) = delete;
- LineCharReader(ZString name, int fd);
+ LineCharReader(ZString name, FD fd);
bool get(LineChar& c);
void adv();
diff --git a/src/io/line_test.cpp b/src/io/line_test.cpp
index 8df6bbc..ae316c6 100644
--- a/src/io/line_test.cpp
+++ b/src/io/line_test.cpp
@@ -5,19 +5,19 @@
#include "../strings/zstring.hpp"
static
-int string_pipe(ZString sz)
+io::FD string_pipe(ZString sz)
{
- int pfd[2];
- if (-1 == pipe(pfd))
- return -1;
- if (sz.size() != write(pfd[1], sz.c_str(), sz.size()))
+ io::FD rfd, wfd;
+ if (-1 == io::FD::pipe(rfd, wfd))
+ return io::FD();
+ if (sz.size() != wfd.write(sz.c_str(), sz.size()))
{
- close(pfd[0]);
- close(pfd[1]);
- return -1;
+ rfd.close();
+ wfd.close();
+ return io::FD();
}
- close(pfd[1]);
- return pfd[0];
+ wfd.close();
+ return rfd;
}
TEST(io, line1)
diff --git a/src/io/lock.cpp b/src/io/lock.cpp
index 823b168..c7cbda8 100644
--- a/src/io/lock.cpp
+++ b/src/io/lock.cpp
@@ -23,7 +23,8 @@
#include "../strings/zstring.hpp"
-#include "../io/cxxstdio.hpp"
+#include "cxxstdio.hpp"
+#include "fd.hpp"
#include "../poison.hpp"
@@ -35,29 +36,29 @@ const int backup_count = 10;
/// Protected file writing
/// (Until the file is closed, it keeps the old file)
-// Start writing a tmpfile
-static
-int get_lock_open(ZString filename, int *info)
+namespace io
{
- int fd;
- int no = getpid();
-
- // Get a filename that doesn't already exist
- FString newfile;
- do
+ // Start writing a tmpfile
+ static
+ FD get_lock_open(ZString filename, int *info)
{
- newfile = STRPRINTF("%s_%d.tmp", filename, no++);
- fd = open(newfile.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0666);
+ FD fd;
+ int no = getpid();
+
+ // Get a filename that doesn't already exist
+ FString newfile;
+ do
+ {
+ newfile = STRPRINTF("%s_%d.tmp", filename, no++);
+ fd = FD::open(newfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ }
+ while (fd == FD() && errno == EEXIST);
+ if (fd == FD())
+ abort();
+ *info = --no;
+ return fd;
}
- while (fd == -1 && errno == EEXIST);
- if (fd == -1)
- abort();
- *info = --no;
- return fd;
-}
-namespace io
-{
WriteLock::WriteLock(FString fn, bool linebuffered)
: WriteFile(get_lock_open(fn, &tmp_suffix), linebuffered), filename(fn)
{}
diff --git a/src/io/read.cpp b/src/io/read.cpp
index 146ba81..fe2c765 100644
--- a/src/io/read.cpp
+++ b/src/io/read.cpp
@@ -32,31 +32,31 @@
namespace io
{
- ReadFile::ReadFile(int f)
+ ReadFile::ReadFile(FD f)
: fd(f), start(0), end(0)
{
}
ReadFile::ReadFile(ZString name)
- : fd(open(name.c_str(), O_RDONLY | O_CLOEXEC)), start(0), end(0)
+ : fd(FD::open(name, O_RDONLY | O_CLOEXEC)), start(0), end(0)
{
}
ReadFile::~ReadFile()
{
- close(fd);
- fd = -1;
+ fd.close();
+ fd = FD();
}
bool ReadFile::get(char& c)
{
if (start == end)
{
- if (fd == -1)
+ if (fd == FD())
return false;
- ssize_t rv = read(fd, &buf, sizeof(buf));
+ ssize_t rv = fd.read(&buf, sizeof(buf));
if (rv == 0 || rv == -1)
{
- close(fd);
- fd = -1;
+ fd.close();
+ fd = FD();
return false;
}
start = 0;
@@ -117,6 +117,6 @@ namespace io
bool ReadFile::is_open()
{
- return fd != -1;
+ return fd != FD();
}
} // namespace io
diff --git a/src/io/read.hpp b/src/io/read.hpp
index 8b910b6..14283c5 100644
--- a/src/io/read.hpp
+++ b/src/io/read.hpp
@@ -23,18 +23,19 @@
# include "../strings/fwd.hpp"
+# include "fd.hpp"
namespace io
{
class ReadFile
{
private:
- int fd;
+ FD fd;
unsigned short start, end;
char buf[4096];
public:
explicit
- ReadFile(int fd);
+ ReadFile(FD fd);
explicit
ReadFile(ZString name);
ReadFile(ReadFile&&) = delete;
diff --git a/src/io/read_test.cpp b/src/io/read_test.cpp
index 8c459cbb..ebb20ca 100644
--- a/src/io/read_test.cpp
+++ b/src/io/read_test.cpp
@@ -5,19 +5,19 @@
#include "../strings/zstring.hpp"
static
-int string_pipe(ZString sz)
+io::FD string_pipe(ZString sz)
{
- int pfd[2];
- if (-1 == pipe(pfd))
- return -1;
- if (sz.size() != write(pfd[1], sz.c_str(), sz.size()))
+ io::FD rfd, wfd;
+ if (-1 == io::FD::pipe(rfd, wfd))
+ return io::FD();
+ if (sz.size() != wfd.write(sz.c_str(), sz.size()))
{
- close(pfd[0]);
- close(pfd[1]);
- return -1;
+ rfd.close();
+ wfd.close();
+ return io::FD();
}
- close(pfd[1]);
- return pfd[0];
+ wfd.close();
+ return rfd;
}
TEST(io, read1)
diff --git a/src/io/write.cpp b/src/io/write.cpp
index 71f05ae..5993a69 100644
--- a/src/io/write.cpp
+++ b/src/io/write.cpp
@@ -30,18 +30,20 @@
namespace io
{
- WriteFile::WriteFile(int f, bool linebuffered)
+ WriteFile::WriteFile(FD f, bool linebuffered)
: fd(f), lb(linebuffered), buflen(0)
{}
WriteFile::WriteFile(ZString name, bool linebuffered)
- : fd(open(name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)), lb(linebuffered), buflen(0)
+ : fd(FD::open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)), lb(linebuffered), buflen(0)
{}
WriteFile::~WriteFile()
{
- if (fd != -1)
+ if (fd != FD())
{
- if (close() == -1)
+ if (!close())
+ {
abort();
+ }
}
}
@@ -69,7 +71,7 @@ namespace io
{buf + offset, buflen - offset},
{const_cast<char *>(dat), len},
};
- ssize_t rv = writev(fd, iov, 2);
+ ssize_t rv = fd.writev(iov, 2);
if (rv <= 0)
goto write_fail;
offset += rv;
@@ -81,7 +83,7 @@ namespace io
while (len > sizeof(buf))
{
- ssize_t rv = write(fd, dat, len);
+ ssize_t rv = fd.write(dat, len);
if (rv <= 0)
goto write_fail;
dat += rv;
@@ -102,7 +104,7 @@ namespace io
size_t remaining = rend - last_nl;
while (remaining)
{
- ssize_t rv = write(fd, buf + offset, remaining);
+ ssize_t rv = fd.write(buf + offset, remaining);
if (rv <= 0)
goto write_fail;
offset += rv;
@@ -115,8 +117,8 @@ namespace io
return;
write_fail:
- ::close(fd);
- fd = -1;
+ fd.close();
+ fd = FD();
return;
}
@@ -132,28 +134,28 @@ namespace io
size_t off = 0;
while (off < buflen)
{
- ssize_t rv = write(fd, buf + off, buflen - off);
+ ssize_t rv = fd.write(buf + off, buflen - off);
if (rv <= 0)
{
- ::close(fd);
- fd = -1;
+ fd.close();
+ fd = FD();
return false;
}
off += rv;
}
- int f = fd;
- fd = -1;
- return ::close(f) == 0;
+ FD f = fd;
+ fd = FD();
+ return f.close() == 0;
}
bool WriteFile::is_open()
{
- return fd != -1;
+ return fd != FD();
}
AppendFile::AppendFile(ZString name, bool linebuffered)
- : WriteFile(open(name.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666), linebuffered)
+ : WriteFile(FD::open(name, O_WRONLY | O_CREAT | O_APPEND, 0666), linebuffered)
{}
int do_vprint(WriteFile& out, const char *fmt, va_list ap)
diff --git a/src/io/write.hpp b/src/io/write.hpp
index 7134015..a52c176 100644
--- a/src/io/write.hpp
+++ b/src/io/write.hpp
@@ -25,19 +25,21 @@
# include "../strings/fwd.hpp"
+# include "fd.hpp"
+
namespace io
{
class WriteFile
{
private:
- int fd;
+ FD fd;
bool lb;
struct {} _unused;
unsigned short buflen;
char buf[4096];
public:
explicit
- WriteFile(int fd, bool linebuffered=false);
+ WriteFile(FD fd, bool linebuffered=false);
explicit
WriteFile(ZString name, bool linebuffered=false);
WriteFile(WriteFile&&) = delete;
diff --git a/src/io/write_test.cpp b/src/io/write_test.cpp
index 36ffe88..a9736b8 100644
--- a/src/io/write_test.cpp
+++ b/src/io/write_test.cpp
@@ -10,22 +10,21 @@
#include "../strings/xstring.hpp"
static
-int pipew(int& rfd)
+io::FD pipew(io::FD& rfd)
{
- int pfd[2];
- if (-1 == pipe2(pfd, O_NONBLOCK))
+ io::FD wfd;
+ if (-1 == io::FD::pipe2(rfd, wfd, O_NONBLOCK))
{
- rfd = -1;
- return -1;
+ rfd = io::FD();
+ return io::FD();
}
- rfd = pfd[0];
- return pfd[1];
+ return wfd;
}
class PipeWriter
{
private:
- int rfd;
+ io::FD rfd;
public:
io::WriteFile wf;
public:
@@ -34,7 +33,7 @@ public:
{}
~PipeWriter()
{
- close(rfd);
+ rfd.close();
}
FString slurp()
{
@@ -42,7 +41,7 @@ public:
char buf[4096];
while (true)
{
- ssize_t rv = read(rfd, buf, sizeof(buf));
+ ssize_t rv = rfd.read(buf, sizeof(buf));
if (rv == -1)
{
if (errno != EAGAIN)