diff options
Diffstat (limited to 'src/mmo')
-rw-r--r-- | src/mmo/socket.cpp | 109 | ||||
-rw-r--r-- | src/mmo/socket.hpp | 49 |
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) { |