summaryrefslogtreecommitdiffstats
path: root/src/utils/tokencollector.h
blob: 0923eac6c7ad0c6495b698ef4576b7e266f6b22b (plain)
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
/*
 *  The Mana Server
 *  Copyright (C) 2007-2010  The Mana World Development Team
 *
 *  This file is part of The Mana Server.
 *
 *  The Mana Server 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 2 of the License, or
 *  any later version.
 *
 *  The Mana Server 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 The Mana Server.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TOKENCOLLECTOR_H
#define TOKENCOLLECTOR_H

#include <stdint.h>
#include <string>
#include <list>
#include <time.h>

/**
 * Base class containing the generic implementation of TokenCollector.
 */
class TokenCollectorBase
{
        struct Item
        {
            std::string token; /**< Cookie used by the client. */
            intptr_t data;     /**< User data. */
            time_t timeStamp;  /**< Creation time. */
        };

        /**
         * List containing client already connected. Newer clients are at the
         * back of the list.
         */
        std::list<Item> mPendingClients;

        /**
         * List containing server data waiting for clients. Newer data are at
         * the back of the list.
         */
        std::list<Item> mPendingConnects;

        /**
         * Time at which the TokenCollector performed its last check.
         */
        time_t mLastCheck;

    protected:

        virtual void removedClient(intptr_t) = 0;
        virtual void removedConnect(intptr_t) = 0;
        virtual void foundMatch(intptr_t client, intptr_t connect) = 0;
        TokenCollectorBase();
        virtual ~TokenCollectorBase();
        void insertClient(const std::string &, intptr_t);
        void removeClient(intptr_t);
        void insertConnect(const std::string &, intptr_t);
        void removeOutdated(time_t);
};

/**
 * Compile-time check to ensure that Client and ServerData are simple enough
 * for TokenCollector.
 */
template< class T > struct _TC_CheckData;
template<> struct _TC_CheckData< int > {};
template< class T > struct _TC_CheckData< T * > {};

/**
 * A class for storing and matching tokens.
 *
 * The Handler class must provide three member functions:
 *  - deletePendingClient(Client),
 *  - deletePendingConnect(ServerData), and
 *  - tokenMatched(Client, ServerData).
 *
 * The delete members will be called whenever the collector considers that a
 * token has become obsolete and it is about to remove it.
 */
template< class Handler, class Client, class ServerData >
class TokenCollector: private TokenCollectorBase
{

    public:

        TokenCollector(Handler *h): mHandler(h)
        {
            _TC_CheckData<Client> ClientMustBeSimple;
            (void)&ClientMustBeSimple;
            _TC_CheckData<ServerData> ServerDataMustBeSimple;
            (void)&ServerDataMustBeSimple;
        }

        /**
         * Checks if the server expected this client token. If so, calls
         * Handler::tokenMatched. Otherwise marks the client as pending.
         */
        void addPendingClient(const std::string &token, Client data)
        { insertClient(token, (intptr_t)data); }

        /**
         * Checks if a client already registered this token. If so, calls
         * Handler::tokenMatched. Otherwise marks the data as pending.
         */
        void addPendingConnect(const std::string &token, ServerData data)
        { insertConnect(token, (intptr_t)data); }

        /**
         * Removes a pending client.
         * @note Does not call destroyPendingClient.
         */
        void deletePendingClient(Client data)
        { removeClient((intptr_t)data); }

    private:

        void removedClient(intptr_t data)
        { mHandler->deletePendingClient((Client)data); }

        void removedConnect(intptr_t data)
        { mHandler->deletePendingConnect((ServerData)data); }

        void foundMatch(intptr_t client, intptr_t data)
        { mHandler->tokenMatched((Client)client, (ServerData)data); }

        Handler *mHandler;
};

#endif // TOKENCOLLECTOR_H