summaryrefslogtreecommitdiff
path: root/src/mmo
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-04-18 22:09:42 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-04-18 22:23:16 -0700
commit7f16d356995d4e9c29105f98d502a7e51a4c775d (patch)
tree3fc9f782d67f68d44c36d0dff2c197fc33dac206 /src/mmo
parent56e149a51562b9d2620bc9037a81735c29ea95af (diff)
parent6d631217271fcdc57143a7f8e03a2595a93ab50f (diff)
downloadtmwa-7f16d356995d4e9c29105f98d502a7e51a4c775d.tar.gz
tmwa-7f16d356995d4e9c29105f98d502a7e51a4c775d.tar.bz2
tmwa-7f16d356995d4e9c29105f98d502a7e51a4c775d.tar.xz
tmwa-7f16d356995d4e9c29105f98d502a7e51a4c775d.zip
Merge tag 'v14.4.18' into master
Conflicts: src/admin/ladmin.cpp src/char/char.cpp src/login/login.cpp src/map/chrif.cpp src/map/clif.cpp src/mmo/socket.cpp
Diffstat (limited to 'src/mmo')
-rw-r--r--src/mmo/socket.cpp109
-rw-r--r--src/mmo/socket.hpp49
2 files changed, 101 insertions, 57 deletions
diff --git a/src/mmo/socket.cpp b/src/mmo/socket.cpp
index 364e769..2fec6c1 100644
--- a/src/mmo/socket.cpp
+++ b/src/mmo/socket.cpp
@@ -56,6 +56,39 @@ static
std::array<std::unique_ptr<Session>, FD_SETSIZE> session;
#pragma GCC diagnostic pop
+Session::Session(SessionIO io, SessionParsers p)
+: created()
+, connected()
+, eof()
+, timed_close()
+, rdata(), wdata()
+, max_rdata(), max_wdata()
+, rdata_size(), wdata_size()
+, rdata_pos()
+, client_ip()
+, func_recv()
+, func_send()
+, func_parse()
+, func_delete()
+, for_inferior()
+, session_data()
+, fd()
+{
+ set_io(io);
+ set_parsers(p);
+}
+void Session::set_io(SessionIO io)
+{
+ func_send = io.func_send;
+ func_recv = io.func_recv;
+}
+void Session::set_parsers(SessionParsers p)
+{
+ func_parse = p.func_parse;
+ func_delete = p.func_delete;
+}
+
+
void set_session(io::FD fd, std::unique_ptr<Session> sess)
{
int f = fd.uncast_dammit();
@@ -98,25 +131,10 @@ size_t RFIFOSPACE(Session *s)
}
-/// Discard all input
-static
-void null_parse(Session *s);
-/// Default parser for new connections
-static
-void (*default_func_parse)(Session *) = null_parse;
-
-void set_defaultparse(void (*defaultparse)(Session *))
-{
- default_func_parse = defaultparse;
-}
-
/// Read from socket to the queue
static
void recv_to_fifo(Session *s)
{
- if (s->eof)
- return;
-
ssize_t len = s->fd.read(&s->rdata[s->rdata_size],
RFIFOSPACE(s));
@@ -127,16 +145,13 @@ void recv_to_fifo(Session *s)
}
else
{
- s->eof = 1;
+ s->set_eof();
}
}
static
void send_from_fifo(Session *s)
{
- if (s->eof)
- return;
-
ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size);
if (len > 0)
@@ -151,18 +166,16 @@ void send_from_fifo(Session *s)
}
else
{
- s->eof = 1;
+ s->set_eof();
}
}
static
-void null_parse(Session *s)
+void nothing_delete(Session *s)
{
- PRINTF("null_parse : %d\n"_fmt, s);
- RFIFOSKIP(s, RFIFOREST(s));
+ (void)s;
}
-
static
void connect_client(Session *ls)
{
@@ -211,23 +224,21 @@ void connect_client(Session *ls)
fd.fcntl(F_SETFL, O_NONBLOCK);
- set_session(fd, make_unique<Session>());
+ set_session(fd, make_unique<Session>(
+ SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo},
+ ls->for_inferior));
Session *s = get_session(fd);
s->fd = fd;
s->rdata.new_(RFIFO_SIZE);
s->wdata.new_(WFIFO_SIZE);
-
s->max_rdata = RFIFO_SIZE;
s->max_wdata = WFIFO_SIZE;
- s->func_recv = recv_to_fifo;
- s->func_send = send_from_fifo;
- s->func_parse = default_func_parse;
s->client_ip = IP4Address(client_address.sin_addr);
s->created = TimeT::now();
s->connected = 0;
}
-Session *make_listen_port(uint16_t port)
+Session *make_listen_port(uint16_t port, SessionParsers inferior)
{
struct sockaddr_in server_address;
io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0);
@@ -276,18 +287,20 @@ Session *make_listen_port(uint16_t port)
readfds.set(fd);
- set_session(fd, make_unique<Session>());
+ set_session(fd, make_unique<Session>(
+ SessionIO{func_recv: connect_client, func_send: nullptr},
+ SessionParsers{func_parse: nullptr, func_delete: nothing_delete}));
Session *s = get_session(fd);
+ s->for_inferior = inferior;
s->fd = fd;
- s->func_recv = connect_client;
s->created = TimeT::now();
s->connected = 1;
return s;
}
-Session *make_connection(IP4Address ip, uint16_t port)
+Session *make_connection(IP4Address ip, uint16_t port, SessionParsers parsers)
{
struct sockaddr_in server_address;
io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0);
@@ -329,7 +342,9 @@ Session *make_connection(IP4Address ip, uint16_t port)
readfds.set(fd);
- set_session(fd, make_unique<Session>());
+ set_session(fd, make_unique<Session>(
+ SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo},
+ parsers));
Session *s = get_session(fd);
s->fd = fd;
s->rdata.new_(RFIFO_SIZE);
@@ -337,9 +352,6 @@ Session *make_connection(IP4Address ip, uint16_t port)
s->max_rdata = RFIFO_SIZE;
s->max_wdata = WFIFO_SIZE;
- s->func_recv = recv_to_fifo;
- s->func_send = send_from_fifo;
- s->func_parse = default_func_parse;
s->created = TimeT::now();
s->connected = 1;
@@ -350,6 +362,8 @@ void delete_session(Session *s)
{
if (!s)
return;
+ // this needs to be before the fd_max--
+ s->func_delete(s);
io::FD fd = s->fd;
// If this was the highest fd, decrease it
@@ -434,13 +448,13 @@ void do_sendrecv(interval_t next_ms)
Session *s = get_session(i);
if (!s)
continue;
- if (wfd.isset(i))
+ if (wfd.isset(i) && !s->eof)
{
if (s->func_send)
//send_from_fifo(i);
s->func_send(s);
}
- if (rfd.isset(i))
+ if (rfd.isset(i) && !s->eof)
{
if (s->func_recv)
//recv_to_fifo(i);
@@ -461,23 +475,22 @@ void do_parsepacket(void)
&& static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT)
{
PRINTF("Session #%d timed out\n"_fmt, s);
- s->eof = 1;
+ s->set_eof();
}
- if (!s->rdata_size && !s->eof)
- continue;
- if (s->func_parse)
+ if (s->rdata_size && !s->eof && s->func_parse)
{
s->func_parse(s);
/// some func_parse may call delete_session
+ // (that's kind of evil)
s = get_session(i);
- if (s && s->eof)
- {
- delete_session(s);
- s = nullptr;
- }
if (!s)
continue;
}
+ if (s->eof)
+ {
+ delete_session(s);
+ continue;
+ }
/// Reclaim buffer space for what was read
RFIFOFLUSH(s);
}
diff --git a/src/mmo/socket.hpp b/src/mmo/socket.hpp
index 3b411e3..c166794 100644
--- a/src/mmo/socket.hpp
+++ b/src/mmo/socket.hpp
@@ -51,16 +51,40 @@ struct SessionDeleter
void operator()(SessionData *sd);
};
-// Struct declaration
+struct Session;
+struct SessionIO
+{
+ void (*func_recv)(Session *);
+ void (*func_send)(Session *);
+};
+
+struct SessionParsers
+{
+ void (*func_parse)(Session *);
+ void (*func_delete)(Session *);
+};
struct Session
{
+ Session(SessionIO, SessionParsers);
+ Session(Session&&) = delete;
+ Session& operator = (Session&&) = delete;
+
+ void set_io(SessionIO);
+ void set_parsers(SessionParsers);
+
/// Checks whether a newly-connected socket actually does anything
TimeT created;
bool connected;
+private:
/// Flag needed since structure must be freed in a server-dependent manner
bool eof;
+public:
+ void set_eof() { eof = true; }
+
+ /// Currently used by clif_setwaitclose
+ Timer timed_close;
/// Since this is a single-threaded application, it can't block
/// These are the read/write queues
@@ -74,6 +98,7 @@ struct Session
IP4Address client_ip;
+private:
/// Send or recieve
/// Only called when select() indicates the socket is ready
/// If, after that, nothing is read, it sets eof
@@ -83,12 +108,23 @@ struct Session
/// This is the important one
/// Set to different functions depending on whether the connection
/// is a player or a server/ladmin
- /// Can be set explicitly or via set_defaultparse
void (*func_parse)(Session *);
+ /// Cleanup function since we're not fully RAII yet
+ void (*func_delete)(Session *);
+
+public:
+ // this really ought to be part of session_data, once that gets sane
+ SessionParsers for_inferior;
+
/// Server-specific data type
+ // (this really should include the deleter, but ...)
std::unique_ptr<SessionData, SessionDeleter> session_data;
io::FD fd;
+
+ friend void do_sendrecv(interval_t next);
+ friend void do_parsepacket(void);
+ friend void delete_session(Session *);
};
inline
@@ -123,10 +159,10 @@ 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
-Session *make_listen_port(uint16_t port);
+Session *make_listen_port(uint16_t port, SessionParsers inferior);
/// Connect to an address, return a connected socket or -1
// FIXME - this is IPv4 only!
-Session *make_connection(IP4Address ip, uint16_t port);
+Session *make_connection(IP4Address ip, uint16_t port, SessionParsers);
/// free() the structure and close() the fd
void delete_session(Session *);
/// Make a the internal queues bigger
@@ -136,11 +172,6 @@ void do_sendrecv(interval_t next);
/// Call the parser function for every socket that has read data
void do_parsepacket(void);
-/// Change the default parser for newly connected clients
-// typically called once per server, but individual clients may identify
-// themselves as servers
-void set_defaultparse(void(*defaultparse)(Session *));
-
template<class T>
uint8_t *pod_addressof_m(T& structure)
{