summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-02-04 23:18:54 -0800
committerBen Longbons <b.r.longbons@gmail.com>2014-02-06 11:18:37 -0800
commit9215c35975be745628e8188473154c7e476add55 (patch)
tree14d4f5d51381f8a59803233c24dfafc846ddf583 /src/common
parent9544985ccbb20d7f8377c63a4e59d1ff97b844ac (diff)
downloadtmwa-9215c35975be745628e8188473154c7e476add55.tar.gz
tmwa-9215c35975be745628e8188473154c7e476add55.tar.bz2
tmwa-9215c35975be745628e8188473154c7e476add55.tar.xz
tmwa-9215c35975be745628e8188473154c7e476add55.zip
Wrap remaining FDs in a class
Diffstat (limited to 'src/common')
-rw-r--r--src/common/core.cpp2
-rw-r--r--src/common/iter.hpp97
-rw-r--r--src/common/iter_test.cpp82
-rw-r--r--src/common/socket.cpp181
-rw-r--r--src/common/socket.hpp30
-rw-r--r--src/common/utils2.hpp53
6 files changed, 294 insertions, 151 deletions
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<ZString *>(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 <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 <iterator>
+
+
+/// Simple class to use a pair of iterators with foreach
+template<class It>
+class IteratorPair
+{
+ It _b, _e;
+public:
+ IteratorPair(It b, It e)
+ : _b(b), _e(e)
+ {}
+
+ It begin() { return _b; }
+ It end() { return _e; }
+};
+
+template<class It>
+IteratorPair<It> iterator_pair(It b, It e)
+{
+ return {b, e};
+}
+
+template<class T>
+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 T, class Math=PassthroughMath<T>>
+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<class T>
+IteratorPair<ValueIterator<T>> 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 <gtest/gtest.h>
+
+#include "../strings/xstring.hpp"
+
+TEST(iterpair, string)
+{
+ IteratorPair<ValueIterator<char>> pair = value_range('0', ':');
+ const char *str = "0123456789";
+ EXPECT_TRUE(std::equal(pair.begin(), pair.end(), str));
+}
+
+TEST(iterpair, signed8)
+{
+ IteratorPair<ValueIterator<int8_t>> 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<ValueIterator<uint8_t>> 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<std::unique_ptr<Session>, FD_SETSIZE> session;
#pragma GCC diagnostic pop
+void set_session(io::FD fd, std::unique_ptr<Session> 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<ValueIterator<io::FD, IncrFD>> 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<struct sockaddr *>(&client_address), &len);
- if (fd == -1)
+ io::FD fd = ls->fd.accept(reinterpret_cast<struct sockaddr *>(&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>();
- Session *s = session[fd].get();
+ set_session(fd, make_unique<Session>());
+ 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<struct sockaddr *>(&server_address),
+ if (fd.bind(reinterpret_cast<struct sockaddr *>(&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>();
- Session *s = session[fd].get();
+ set_session(fd, make_unique<Session>());
+ 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<struct sockaddr *>(&server_address),
+ fd.connect(reinterpret_cast<struct sockaddr *>(&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>();
- Session *s = session[fd].get();
+ set_session(fd, make_unique<Session>());
+ 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<time_t>(TimeT::now()) - static_cast<time_t>(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<SessionData, SessionDeleter> 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<std::unique_ptr<Session>, FD_SETSIZE> session;
-/// Maximum used FD, +1
-extern int fd_max;
+void set_session(io::FD fd, std::unique_ptr<Session> 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<ValueIterator<io::FD, IncrFD>> 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 <memory>
# include <type_traits>
+# include "iter.hpp"
+
# ifdef __clang__
# define FALLTHROUGH [[clang::fallthrough]]
# else
@@ -92,25 +94,6 @@ public:
}
};
-template<class It>
-class IteratorPair
-{
- It _b, _e;
-public:
- IteratorPair(It b, It e)
- : _b(b), _e(e)
- {}
-
- It begin() { return _b; }
- It end() { return _e; }
-};
-
-template<class It>
-IteratorPair<It> 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<class E>
@@ -177,41 +160,19 @@ E operator ~ (E r) \
}
template<class E>
-class EnumValueIterator
+class EnumMath
{
typedef typename underlying_type<E>::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<class E>
-IteratorPair<EnumValueIterator<E>> erange(E b, E e)
+IteratorPair<ValueIterator<E, EnumMath<E>>> erange(E b, E e)
{
return {b, e};
}