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/admin/ladmin.cpp | 2 +- src/char/char.cpp | 25 ++++--- src/common/core.cpp | 2 - src/common/iter.hpp | 97 +++++++++++++++++++++++++ src/common/iter_test.cpp | 82 +++++++++++++++++++++ src/common/socket.cpp | 181 +++++++++++++++++++++++------------------------ src/common/socket.hpp | 30 +++++--- src/common/utils2.hpp | 53 ++------------ 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 +++-- src/map/atcommand.cpp | 82 ++++++++++----------- src/map/chrif.cpp | 25 +++---- src/map/clif.cpp | 33 +++++---- src/map/intif.cpp | 4 +- src/map/map.cpp | 43 +++++------ src/map/mob.cpp | 7 +- src/map/party.cpp | 14 ++-- src/map/pc.cpp | 4 +- src/map/script.cpp | 14 ++-- src/monitor/main.cpp | 21 +++--- 30 files changed, 851 insertions(+), 367 deletions(-) create mode 100644 src/common/iter.hpp create mode 100644 src/common/iter_test.cpp create mode 100644 src/io/fd.cpp create mode 100644 src/io/fd.hpp (limited to 'src') diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index 6b49f35..2c9382c 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -1778,7 +1778,7 @@ void prompt(void) // get command and parameter // TODO figure out a better way to do stdio - static auto cin = make_unique(dup(0)); + static auto cin = make_unique(io::FD::stdin().dup()); FString buf; cin->getline(buf); diff --git a/src/char/char.cpp b/src/char/char.cpp index f98fc4b..fe9bf9a 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -1046,16 +1046,16 @@ static int disconnect_player(int accound_id) { // disconnect player if online on char-server - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + if (!get_session(i)) continue; - struct char_session_data *sd = static_cast(session[i]->session_data.get()); + struct char_session_data *sd = static_cast(get_session(i)->session_data.get()); if (sd) { if (sd->account_id == accound_id) { - session[i]->eof = 1; + get_session(i)->eof = 1; return 1; } } @@ -1142,9 +1142,9 @@ void parse_tologin(Session *ls) if (RFIFOREST(ls) < 51) return; // PRINTF("parse_tologin 2713 : %d\n", RFIFOB(fd,6)); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; sd = static_cast(s2->session_data.get()); @@ -1188,9 +1188,9 @@ void parse_tologin(Session *ls) case 0x2717: if (RFIFOREST(ls) < 50) return; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; sd = static_cast(s2->session_data.get()); @@ -1464,13 +1464,12 @@ void parse_tologin(Session *ls) if (RFIFOREST(ls) < 7) return; { - int acc, status, i; - acc = RFIFOL(ls, 2); - status = RFIFOB(ls, 6); + int acc = RFIFOL(ls, 2); + int status = RFIFOB(ls, 6); - for (i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; sd = static_cast(s2->session_data.get()); diff --git a/src/common/core.cpp b/src/common/core.cpp index fe2f660..d57e970 100644 --- a/src/common/core.cpp +++ b/src/common/core.cpp @@ -78,8 +78,6 @@ void sig_proc(int) */ int main(int argc, char **argv) { - do_socket(); - // ZString args[argc]; is (deliberately!) not supported by clang yet ZString *args = static_cast(alloca(argc * sizeof(ZString))); for (int i = 0; i < argc; ++i) diff --git a/src/common/iter.hpp b/src/common/iter.hpp new file mode 100644 index 0000000..5b39588 --- /dev/null +++ b/src/common/iter.hpp @@ -0,0 +1,97 @@ +#ifndef TMWA_COMMON_ITER_HPP +#define TMWA_COMMON_ITER_HPP +// iter.hpp - tools for dealing with iterators +// +// Copyright © 2012-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 + + +/// Simple class to use a pair of iterators with foreach +template +class IteratorPair +{ + It _b, _e; +public: + IteratorPair(It b, It e) + : _b(b), _e(e) + {} + + It begin() { return _b; } + It end() { return _e; } +}; + +template +IteratorPair iterator_pair(It b, It e) +{ + return {b, e}; +} + +template +class PassthroughMath +{ +public: + static + T inced(T v) { return ++v; } +}; + +// An iterator that just directly contains an integer-like value +// TODO port this once the new integer API happens +template> +class ValueIterator +{ + T value; +public: + typedef std::forward_iterator_tag iterator_category; + typedef void difference_type; + typedef T value_type; + typedef void reference; + typedef void pointer; +public: + ValueIterator(T v) + : value(v) + {} + + T operator *() + { + return value; + } + ValueIterator& operator++ () + { + value = Math::inced(value); + return *this; + } + friend bool operator == (ValueIterator l, ValueIterator r) + { + return l.value == r.value; + } + friend bool operator != (ValueIterator l, ValueIterator r) + { + return !(l == r); + } +}; + +template +IteratorPair> value_range(T b, T e) +{ + return {b, e}; +} + +#endif // TMWA_COMMON_ITER_HPP diff --git a/src/common/iter_test.cpp b/src/common/iter_test.cpp new file mode 100644 index 0000000..647ebf9 --- /dev/null +++ b/src/common/iter_test.cpp @@ -0,0 +1,82 @@ +#include "iter.hpp" + +#include + +#include "../strings/xstring.hpp" + +TEST(iterpair, string) +{ + IteratorPair> pair = value_range('0', ':'); + const char *str = "0123456789"; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), str)); +} + +TEST(iterpair, signed8) +{ + IteratorPair> pair = value_range(int8_t(-128), int8_t(127)); + int8_t arr[255] = + { + -128, -127, -126, -125, -124, -123, -122, -121, -120, + -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, + -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, + -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, + -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, + -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, + -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, + -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, + -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, + -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, + -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, + -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, + -9, -8, -7, -6, -5, -4, -3, -2, -1, + 0, 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, + }; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr + 0)); +} + +TEST(iterpair, unsigned8) +{ + IteratorPair> pair = value_range(uint8_t(0), uint8_t(255)); + uint8_t arr[255] = + { + 0, 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, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, + }; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr)); +} diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 1c5bcbc..b5f6379 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -19,7 +19,8 @@ #include "../poison.hpp" static -fd_set readfds; +io::FD_Set readfds; +static int fd_max; static @@ -29,9 +30,35 @@ const uint32_t WFIFO_SIZE = 65536; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" +static std::array, FD_SETSIZE> session; #pragma GCC diagnostic pop +void set_session(io::FD fd, std::unique_ptr sess) +{ + int f = fd.uncast_dammit(); + assert (0 <= f && f < FD_SETSIZE); + session[f] = std::move(sess); +} +Session *get_session(io::FD fd) +{ + int f = fd.uncast_dammit(); + if (0 <= f && f < FD_SETSIZE) + return session[f].get(); + return nullptr; +} +void reset_session(io::FD fd) +{ + int f = fd.uncast_dammit(); + assert (0 <= f && f < FD_SETSIZE); + session[f] = nullptr; +} +int get_fd_max() { return fd_max; } +IteratorPair> iter_fds() +{ + return {io::FD::cast_dammit(0), io::FD::cast_dammit(fd_max)}; +} + /// clean up by discarding handled bytes inline void RFIFOFLUSH(Session *s) @@ -68,7 +95,7 @@ void recv_to_fifo(Session *s) if (s->eof) return; - ssize_t len = read(s->fd, &s->rdata[s->rdata_size], + ssize_t len = s->fd.read(&s->rdata[s->rdata_size], RFIFOSPACE(s)); if (len > 0) @@ -88,7 +115,7 @@ void send_from_fifo(Session *s) if (s->eof) return; - ssize_t len = write(s->fd, &s->wdata[0], s->wdata_size); + ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); if (len > 0) { @@ -120,53 +147,50 @@ void connect_client(Session *ls) struct sockaddr_in client_address; socklen_t len = sizeof(client_address); - int fd = accept(ls->fd, reinterpret_cast(&client_address), &len); - if (fd == -1) + io::FD fd = ls->fd.accept(reinterpret_cast(&client_address), &len); + if (fd == io::FD()) { perror("accept"); return; } - if (fd >= SOFT_LIMIT) + if (fd.uncast_dammit() >= SOFT_LIMIT) { - FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd); - shutdown(fd, SHUT_RDWR); - close(fd); + FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd.uncast_dammit()); + fd.shutdown(SHUT_RDWR); + fd.close(); return; } - if (fd_max <= fd) + if (fd_max <= fd.uncast_dammit()) { - fd_max = fd + 1; + fd_max = fd.uncast_dammit() + 1; } const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! /// Testing shows this is indeed a good idea. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); // Linux-ism: Set socket options to optimize for thin streams // See http://lwn.net/Articles/308919/ and // Documentation/networking/tcp-thin.txt .. Kernel 3.2+ #ifdef TCP_THIN_LINEAR_TIMEOUTS - setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); #endif #ifdef TCP_THIN_DUPACK - setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); #endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); - session[fd] = make_unique(); - Session *s = session[fd].get(); + set_session(fd, make_unique()); + Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); s->wdata.new_(WFIFO_SIZE); @@ -184,27 +208,27 @@ void connect_client(Session *ls) Session *make_listen_port(uint16_t port) { struct sockaddr_in server_address; - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) + io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); + if (fd == io::FD()) { perror("socket"); return nullptr; } - if (fd_max <= fd) - fd_max = fd + 1; + if (fd_max <= fd.uncast_dammit()) + fd_max = fd.uncast_dammit() + 1; - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! // I'm not convinced this is a good idea; although in minimizes the // latency for an individual write, it increases traffic in general. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; #pragma GCC diagnostic push @@ -216,25 +240,22 @@ Session *make_listen_port(uint16_t port) server_address.sin_port = htons(port); #pragma GCC diagnostic pop - if (bind(fd, reinterpret_cast(&server_address), + if (fd.bind(reinterpret_cast(&server_address), sizeof(server_address)) == -1) { perror("bind"); exit(1); } - if (listen(fd, 5) == -1) + if (fd.listen(5) == -1) { /* error */ perror("listen"); exit(1); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - session[fd] = make_unique(); - Session *s = session[fd].get(); + set_session(fd, make_unique()); + Session *s = get_session(fd); s->fd = fd; s->func_recv = connect_client; @@ -247,25 +268,25 @@ Session *make_listen_port(uint16_t port) Session *make_connection(IP4Address ip, uint16_t port) { struct sockaddr_in server_address; - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) + io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); + if (fd == io::FD()) { perror("socket"); return nullptr; } - if (fd_max <= fd) - fd_max = fd + 1; + if (fd_max <= fd.uncast_dammit()) + fd_max = fd.uncast_dammit() + 1; const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! // I'm not convinced this is a good idea; although in minimizes the // latency for an individual write, it increases traffic in general. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; server_address.sin_addr = in_addr(ip); @@ -277,20 +298,17 @@ Session *make_connection(IP4Address ip, uint16_t port) server_address.sin_port = htons(port); #pragma GCC diagnostic pop - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); /// Errors not caught - we must not block /// Let the main select() loop detect when we know the state - connect(fd, reinterpret_cast(&server_address), + fd.connect(reinterpret_cast(&server_address), sizeof(struct sockaddr_in)); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - session[fd] = make_unique(); - Session *s = session[fd].get(); + set_session(fd, make_unique()); + Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); s->wdata.new_(WFIFO_SIZE); @@ -311,26 +329,23 @@ void delete_session(Session *s) if (!s) return; - int fd = s->fd; + io::FD fd = s->fd; // If this was the highest fd, decrease it // We could add a loop to decrement fd_max further for every null session, // but this is cheap and good enough for the typical case - if (fd == fd_max - 1) + if (fd.uncast_dammit() == fd_max - 1) fd_max--; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_CLR(fd, &readfds); -#pragma GCC diagnostic pop + readfds.clr(fd); { s->rdata.delete_(); s->wdata.delete_(); s->session_data.reset(); - session[fd].reset(); + reset_session(fd); } // just close() would try to keep sending buffers - shutdown(fd, SHUT_RDWR); - close(fd); + fd.shutdown(SHUT_RDWR); + fd.close(); } void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) @@ -362,18 +377,12 @@ void WFIFOSET(Session *s, size_t len) void do_sendrecv(interval_t next_ms) { - fd_set rfd = readfds, wfd; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_ZERO(&wfd); -#pragma GCC diagnostic pop - for (int i = 0; i < fd_max; i++) + io::FD_Set rfd = readfds, wfd; + for (io::FD i : iter_fds()) { - if (session[i] && session[i]->wdata_size) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(i, &wfd); -#pragma GCC diagnostic pop + Session *s = get_session(i); + if (s && s->wdata_size) + wfd.set(i); } struct timeval timeout; { @@ -382,26 +391,20 @@ void do_sendrecv(interval_t next_ms) timeout.tv_sec = next_s.count(); timeout.tv_usec = next_us.count(); } - if (select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) + if (io::FD_Set::select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) return; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - if (FD_ISSET(i, &wfd)) -#pragma GCC diagnostic pop + if (wfd.isset(i)) { if (s->func_send) //send_from_fifo(i); s->func_send(s); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - if (FD_ISSET(i, &rfd)) -#pragma GCC diagnostic pop + if (rfd.isset(i)) { if (s->func_recv) //recv_to_fifo(i); @@ -413,15 +416,15 @@ void do_sendrecv(interval_t next_ms) void do_parsepacket(void) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; if (!s->connected && static_cast(TimeT::now()) - static_cast(s->created) > CONNECT_TIMEOUT) { - PRINTF("Session #%d timed out\n", i); + PRINTF("Session #%d timed out\n", s); s->eof = 1; } if (!s->rdata_size && !s->eof) @@ -438,14 +441,6 @@ void do_parsepacket(void) } } -void do_socket(void) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_ZERO(&readfds); -#pragma GCC diagnostic pop -} - void RFIFOSKIP(Session *s, size_t len) { s->rdata_pos += len; diff --git a/src/common/socket.hpp b/src/common/socket.hpp index 4d51604..6d0ca01 100644 --- a/src/common/socket.hpp +++ b/src/common/socket.hpp @@ -13,6 +13,8 @@ # include "../strings/vstring.hpp" # include "../strings/xstring.hpp" +# include "../io/fd.hpp" + # include "dumb_ptr.hpp" # include "ip.hpp" # include "utils.hpp" @@ -64,13 +66,13 @@ struct Session /// Server-specific data type std::unique_ptr session_data; - int fd; + io::FD fd; }; inline int convert_for_printf(Session *s) { - return s->fd; + return s->fd.uncast_dammit(); } // save file descriptors for important stuff @@ -79,12 +81,23 @@ constexpr int SOFT_LIMIT = FD_SETSIZE - 50; // socket timeout to establish a full connection in seconds constexpr int CONNECT_TIMEOUT = 15; -/// Everyone who has connected -// note: call delete_session(i) to null out an element -extern std::array, FD_SETSIZE> session; -/// Maximum used FD, +1 -extern int fd_max; +void set_session(io::FD fd, std::unique_ptr sess); +Session *get_session(io::FD fd); +void reset_session(io::FD fd); +int get_fd_max(); + +class IncrFD +{ +public: + static + io::FD inced(io::FD v) + { + return io::FD::cast_dammit(v.uncast_dammit() + 1); + } +}; +IteratorPair> iter_fds(); + /// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, /// but exit if bind() or listen() fails @@ -101,9 +114,6 @@ void do_sendrecv(interval_t next); /// Call the parser function for every socket that has read data void do_parsepacket(void); -/// An init function -void do_socket(void); - /// Change the default parser for newly connected clients // typically called once per server, but individual clients may identify // themselves as servers diff --git a/src/common/utils2.hpp b/src/common/utils2.hpp index 0f72aff..ac55a5a 100644 --- a/src/common/utils2.hpp +++ b/src/common/utils2.hpp @@ -9,6 +9,8 @@ # include # include +# include "iter.hpp" + # ifdef __clang__ # define FALLTHROUGH [[clang::fallthrough]] # else @@ -92,25 +94,6 @@ public: } }; -template -class IteratorPair -{ - It _b, _e; -public: - IteratorPair(It b, It e) - : _b(b), _e(e) - {} - - It begin() { return _b; } - It end() { return _e; } -}; - -template -IteratorPair iterator_pair(It b, It e) -{ - return {b, e}; -} - // std::underlying_type isn't supported until gcc 4.7 // this is a poor man's emulation template @@ -177,41 +160,19 @@ E operator ~ (E r) \ } template -class EnumValueIterator +class EnumMath { typedef typename underlying_type::type U; - E value; public: - EnumValueIterator(E v) - : value(v) - {} - - E operator *() - { - return value; - } - EnumValueIterator& operator++ () - { - value = E(U(value) + 1); - return *this; - } - EnumValueIterator& operator-- () - { - value = E(U(value) - 1); - return *this; - } - friend bool operator == (EnumValueIterator l, EnumValueIterator r) - { - return l.value == r.value; - } - friend bool operator != (EnumValueIterator l, EnumValueIterator r) + static + E inced(E v) { - return !(l == r); + return E(U(v) + 1); } }; template -IteratorPair> erange(E b, E e) +IteratorPair>> erange(E b, E e) { return {b, e}; } 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) diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 931a4d0..f5deab8 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -715,9 +715,9 @@ ATCE atcommand_who(Session *s, dumb_ptr sd, count = 0; GM_level = pc_isGM(sd); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -778,9 +778,9 @@ ATCE atcommand_whogroup(Session *s, dumb_ptr sd, count = 0; GM_level = pc_isGM(sd); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -842,9 +842,9 @@ ATCE atcommand_whomap(Session *s, dumb_ptr sd, count = 0; GM_level = pc_isGM(sd); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -903,9 +903,9 @@ ATCE atcommand_whomapgroup(Session *s, dumb_ptr sd, count = 0; GM_level = pc_isGM(sd); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -963,9 +963,9 @@ ATCE atcommand_whogm(Session *s, dumb_ptr sd, count = 0; GM_level = pc_isGM(sd); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -1522,9 +1522,9 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr sd, if (sd->bl_m->flag.pvp) { sd->bl_m->flag.pvp = 0; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -1561,9 +1561,9 @@ ATCE atcommand_pvpon(Session *s, dumb_ptr sd, if (!sd->bl_m->flag.pvp && !sd->bl_m->flag.nopvp) { sd->bl_m->flag.pvp = 1; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2155,9 +2155,9 @@ ATCE atcommand_character_stats_all(Session *s, dumb_ptr, int count; count = 0; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2395,9 +2395,9 @@ static ATCE atcommand_doom(Session *s, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2419,9 +2419,9 @@ static ATCE atcommand_doommap(Session *s, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2458,9 +2458,9 @@ static ATCE atcommand_raise(Session *s, dumb_ptr, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2475,9 +2475,9 @@ static ATCE atcommand_raisemap(Session *s, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2687,9 +2687,9 @@ static ATCE atcommand_kickall(Session *s, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -2905,9 +2905,9 @@ static ATCE atcommand_mapexit(Session *, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -3318,9 +3318,9 @@ ATCE atcommand_recallall(Session *s, dumb_ptr sd, } count = 0; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -3374,9 +3374,9 @@ ATCE atcommand_partyrecall(Session *s, dumb_ptr sd, (p = party_search(atoi(message.c_str()))) != NULL) { count = 0; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -3475,9 +3475,9 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr sd, break; case 1: clif_displaymessage(s, "----- Players in Map -----"); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -3486,7 +3486,7 @@ ATCE atcommand_mapinfo(Session *s, dumb_ptr sd, { output = STRPRINTF( "Player '%s' (session #%d) | Location: %d,%d", - pl_sd->status.name, i, pl_sd->bl_x, pl_sd->bl_y); + pl_sd->status.name, s2, pl_sd->bl_x, pl_sd->bl_y); clif_displaymessage(s, output); } } @@ -3797,9 +3797,9 @@ ATCE atcommand_effect(Session *s, dumb_ptr sd, } else { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -5031,9 +5031,9 @@ ATCE atcommand_ipcheck(Session *s, dumb_ptr, // We now have the IP address of a character. // Loop over all logged in sessions looking for matches. - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; pl_sd = dumb_ptr(static_cast(s2->session_data.get())); @@ -5059,9 +5059,9 @@ static ATCE atcommand_doomspot(Session *s, dumb_ptr sd, ZString) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 959186c..ab67b5c 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -202,15 +202,15 @@ int chrif_changemapserver(dumb_ptr sd, nullpo_retr(-1, sd); IP4Address s_ip; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; if (dumb_ptr(static_cast(s->session_data.get())) == sd) { assert (s == sd->sess); - s_ip = session[i]->client_ip; + s_ip = s->client_ip; break; } } @@ -321,12 +321,12 @@ int chrif_authreq(dumb_ptr sd) if (!sd || !char_session || !sd->bl_id || !sd->login_id1) return -1; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; - if (dumb_ptr(static_cast(session[i]->session_data.get())) == sd) + if (dumb_ptr(static_cast(s->session_data.get())) == sd) { assert (s == sd->sess); WFIFOW(char_session, 0) = 0x2afc; @@ -334,7 +334,7 @@ int chrif_authreq(dumb_ptr sd) WFIFOL(char_session, 6) = sd->char_id; WFIFOL(char_session, 10) = sd->login_id1; WFIFOL(char_session, 14) = sd->login_id2; - WFIFOIP(char_session, 18) = session[i]->client_ip; + WFIFOIP(char_session, 18) = s->client_ip; WFIFOSET(char_session, 22); break; } @@ -355,9 +355,9 @@ int chrif_charselectreq(dumb_ptr sd) return -1; IP4Address s_ip; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; if (dumb_ptr(static_cast(s->session_data.get())) == sd) @@ -1157,11 +1157,12 @@ void send_users_tochar(TimerData *, tick_t) return; WFIFOW(char_session, 0) = 0x2aff; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - dumb_ptr sd = dumb_ptr(static_cast(session[i]->session_data.get())); + dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); if (sd && sd->state.auth && !((battle_config.hide_GM_session || sd->state.shroud_active diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 0429600..61c47d9 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -165,11 +165,12 @@ int clif_countusers(void) { int users = 0; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - dumb_ptr sd = dumb_ptr(static_cast(session[i]->session_data.get())); + dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); if (sd && sd->state.auth && !(battle_config.hide_GM_session && pc_isGM(sd))) users++; } @@ -182,11 +183,12 @@ int clif_countusers(void) */ int clif_foreachclient(std::function)> func) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - dumb_ptr sd = dumb_ptr(static_cast(session[i]->session_data.get())); + dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); if (sd && sd->state.auth) func(sd); } @@ -302,9 +304,9 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr bl, SendWho type switch (type) { case SendWho::ALL_CLIENT: // 全クライアントに送信 - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); @@ -320,9 +322,9 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr bl, SendWho type } break; case SendWho::ALL_SAMEMAP: // 同じマップの全クライアントに送信 - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); @@ -402,9 +404,9 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr bl, SendWho type } } } - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); @@ -3379,11 +3381,12 @@ int clif_specialeffect(dumb_ptr bl, int type, int flag) if (flag == 2) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - dumb_ptr sd = dumb_ptr(static_cast(session[i]->session_data.get())); + dumb_ptr sd = dumb_ptr(static_cast(s->session_data.get())); if (sd && sd->state.auth && sd->bl_m == bl->bl_m) clif_specialeffect(sd, type, 1); } diff --git a/src/map/intif.cpp b/src/map/intif.cpp index 006be1c..7d699dd 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -315,9 +315,9 @@ void mapif_parse_WisToGM(Session *s) CharName Wisp_name = stringish(RFIFO_STRING<24>(s, 4)); FString message = RFIFO_STRING(s, 30, len); // information is sended to all online GM - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s2 = session[i].get(); + Session *s2 = get_session(i); if (!s2) continue; dumb_ptr pl_sd = dumb_ptr(static_cast(s2->session_data.get())); diff --git a/src/map/map.cpp b/src/map/map.cpp index 3817422..2600412 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -871,13 +871,14 @@ dumb_ptr map_id2sd(int id) return (struct map_session_data*)bl; return NULL; */ - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - if (session[i]->session_data) + if (s->session_data) { - map_session_data *sd = static_cast(session[i]->session_data.get()); + map_session_data *sd = static_cast(s->session_data.get()); if (sd->bl_id == id) return dumb_ptr(sd); } @@ -905,13 +906,13 @@ CharName map_charid2nick(int id) /* [Fate] Operations to iterate over active map sessions */ static -dumb_ptr map_get_session(int i) +dumb_ptr map_get_session(io::FD i) { - if (i >= 0 && i < fd_max) { - if (!session[i]) + Session *s = get_session(i); + if (!s) return nullptr; - map_session_data *d = static_cast(session[i]->session_data.get()); + map_session_data *d = static_cast(s->session_data.get()); if (d && d->state.auth) return dumb_ptr(d); } @@ -922,9 +923,9 @@ dumb_ptr map_get_session(int i) static dumb_ptr map_get_session_forward(int start) { - for (int i = start; i < fd_max; i++) + for (int i = start; i < get_fd_max(); i++) { - dumb_ptr d = map_get_session(i); + dumb_ptr d = map_get_session(io::FD::cast_dammit(i)); if (d) return d; } @@ -935,10 +936,9 @@ dumb_ptr map_get_session_forward(int start) static dumb_ptr map_get_session_backward(int start) { - int i; - for (i = start; i >= 0; i--) + for (int i = start; i >= 0; i--) { - dumb_ptr d = map_get_session(i); + dumb_ptr d = map_get_session(io::FD::cast_dammit(i)); if (d) return d; } @@ -953,17 +953,17 @@ dumb_ptr map_get_first_session(void) dumb_ptr map_get_next_session(dumb_ptr d) { - return map_get_session_forward(d->sess->fd + 1); + return map_get_session_forward(d->sess->fd.uncast_dammit() + 1); } dumb_ptr map_get_last_session(void) { - return map_get_session_backward(fd_max); + return map_get_session_backward(get_fd_max()); } dumb_ptr map_get_prev_session(dumb_ptr d) { - return map_get_session_backward(d->sess->fd - 1); + return map_get_session_backward(d->sess->fd.uncast_dammit() - 1); } /*========================================== @@ -974,11 +974,12 @@ dumb_ptr map_get_prev_session(dumb_ptr d) */ dumb_ptr map_nick2sd(CharName nick) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - map_session_data *pl_sd = static_cast(session[i]->session_data.get()); + map_session_data *pl_sd = static_cast(s->session_data.get()); if (pl_sd && pl_sd->state.auth) { { @@ -1611,8 +1612,8 @@ void term_func(void) BL::NUL); } - for (int i = 0; i < fd_max; i++) - delete_session(session[i].get()); + for (io::FD i : iter_fds()) + delete_session(get_session(i)); map_removenpc(); diff --git a/src/map/mob.cpp b/src/map/mob.cpp index d68c580..7a73df5 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -2652,11 +2652,12 @@ int mob_damage(dumb_ptr src, dumb_ptr md, int damage, sd = mvp_sd; else { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - dumb_ptr tmp_sd = dumb_ptr(static_cast(session[i]->session_data.get())); + dumb_ptr tmp_sd = dumb_ptr(static_cast(s->session_data.get())); if (tmp_sd && tmp_sd->state.auth) { if (md->bl_m == tmp_sd->bl_m) diff --git a/src/map/party.cpp b/src/map/party.cpp index 09f103e..b2ce340 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -126,11 +126,12 @@ int party_check_member(struct party *p) { nullpo_ret(p); - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - map_session_data *sd = static_cast(session[i]->session_data.get()); + map_session_data *sd = static_cast(s->session_data.get()); if (sd && sd->state.auth) { if (sd->status.party_id == p->party_id) @@ -165,11 +166,12 @@ int party_check_member(struct party *p) // 情報所得失敗(そのIDのキャラを全部未所属にする) int party_recv_noinfo(int party_id) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - map_session_data *sd = static_cast(session[i]->session_data.get()); + map_session_data *sd = static_cast(s->session_data.get()); if (sd && sd->state.auth) { if (sd->status.party_id == party_id) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 168d124..8d242ae 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -5201,13 +5201,13 @@ void pc_autosave_sub(dumb_ptr sd) { nullpo_retv(sd); - if (save_flag == 0 && sd->sess->fd > last_save_fd) + if (save_flag == 0 && sd->sess->fd.uncast_dammit() > last_save_fd) { pc_makesavestatus(sd); chrif_save(sd); save_flag = 1; - last_save_fd = sd->sess->fd; + last_save_fd = sd->sess->fd.uncast_dammit(); } } diff --git a/src/map/script.cpp b/src/map/script.cpp index 6bd4543..c154182 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -3367,11 +3367,12 @@ void builtin_pvpon(ScriptState *st) if (battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris] return; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - map_session_data *pl_sd = static_cast(session[i]->session_data.get()); + map_session_data *pl_sd = static_cast(s->session_data.get()); if (pl_sd && pl_sd->state.auth) { if (m == pl_sd->bl_m && !pl_sd->pvp_timer) @@ -3401,11 +3402,12 @@ void builtin_pvpoff(ScriptState *st) if (battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris] return; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - if (!session[i]) + Session *s = get_session(i); + if (!s) continue; - map_session_data *pl_sd = static_cast(session[i]->session_data.get()); + map_session_data *pl_sd = static_cast(s->session_data.get()); if (pl_sd && pl_sd->state.auth) { if (m == pl_sd->bl_m) diff --git a/src/monitor/main.cpp b/src/monitor/main.cpp index 1bc9880..352b375 100644 --- a/src/monitor/main.cpp +++ b/src/monitor/main.cpp @@ -20,6 +20,7 @@ #include "../strings/xstring.hpp" #include "../io/cxxstdio.hpp" +#include "../io/fd.hpp" #include "../io/read.hpp" #include "../common/config_parse.hpp" @@ -183,19 +184,21 @@ int main(int argc, char *argv[]) { //make sure all possible file descriptors are free for use by the servers //if there are file descriptors higher than the max open from before the limit dropped, that's not our problem - int fd = sysconf(_SC_OPEN_MAX); - while (--fd > 2) - if (close(fd) == 0) - FPRINTF(stderr, "close fd %d\n", fd); - fd = open("/dev/null", O_RDWR); - if (fd < 0) + io::FD fd = io::FD::sysconf_SC_OPEN_MAX(); + while ((fd = fd.prev()) > io::FD::stderr()) + { + if (fd.close() == 0) + FPRINTF(stderr, "close fd %d\n", fd.uncast_dammit()); + } + fd = io::FD::open("/dev/null", O_RDWR); + if (fd == io::FD()) { perror("open /dev/null"); exit(1); } - dup2(fd, 0); - dup2(fd, 1); - close(fd); + fd.dup2(io::FD::stdin()); + fd.dup2(io::FD::stdout()); + fd.close(); } while (1) { -- cgit v1.2.3-60-g2f50