From 9215c35975be745628e8188473154c7e476add55 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Tue, 4 Feb 2014 23:18:54 -0800 Subject: Wrap remaining FDs in a class --- src/io/fd.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/io/fd.hpp | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ src/io/line.cpp | 6 +- src/io/line.hpp | 5 +- src/io/line_test.cpp | 20 +++--- src/io/lock.cpp | 41 +++++++------ src/io/read.cpp | 18 +++--- src/io/read.hpp | 5 +- src/io/read_test.cpp | 20 +++--- src/io/write.cpp | 36 +++++------ src/io/write.hpp | 6 +- src/io/write_test.cpp | 19 +++--- 12 files changed, 414 insertions(+), 85 deletions(-) create mode 100644 src/io/fd.cpp create mode 100644 src/io/fd.hpp (limited to 'src/io') 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 +// +// 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 . + +#include +#include + +#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 +// +// 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 . + +# include "../sanity.hpp" + +# include +# include + +# include + +# 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(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) -- cgit v1.2.3-60-g2f50