clientlist.h

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** \file clientlist.h Interface for ClientList class */
00020 
00021 #ifndef __CLIENTLIST_H__
00022 #define __CLIENTLIST_H__
00023 
00024 #include <hn/hnfwd.h>
00025 #include "ed2kfwd.h"
00026 #include "clients.h"
00027 
00028 namespace Detail {
00029         struct CList;
00030 }
00031 
00032 /**
00033  * ClientList manages all clients currently in use. A client is considered
00034  * "in use" when it has DownloadClient and/or UploadClient members alive.
00035  * This class owns the Client objects and is responsible for deleting the
00036  * clients, when the client submits EVT_DESTROY event.
00037  *
00038  * Clients can be found in this list by searching with the Client IP. Multiple
00039  * clients from same IP are allowed, in which case the differenciating can be
00040  * made based on the client's ports.
00041  */
00042 class ClientList {
00043         enum ClientListEvt {
00044                 EVT_REGEN_QUEUE  //!< Indicates ClientList to regen queue
00045         };
00046         DECLARE_EVENT_TABLE(ClientList*, ClientListEvt);
00047 public:
00048         static ClientList& instance() {
00049                 static ClientList *c = new ClientList;
00050                 return *c;
00051         }
00052 
00053         /**
00054          * Add a client which is to be connected. This method is generally
00055          * used by ServerList to notify us about callback requests.
00056          *
00057          * @param addr      Address the client is located at
00058          */
00059         void addClient(IPV4Address addr);
00060 
00061         /**
00062          * Add a client that shall act as "source" for a file.
00063          *
00064          * @param file       File offered by the client
00065          * @param caddr      Address of the client
00066          * @param saddr      Address of the server the client is on
00067          * @param doConn     Whether to establish connection with the client
00068          * @return           True if source was added, false otherwise
00069          *
00070          * \note This method returns false also when the hash was added to an
00071          *       already existing source.
00072          */
00073         bool addSource(
00074                 const Hash<ED2KHash> &file, IPV4Address caddr,
00075                 IPV4Address saddr, bool doConn = true
00076         );
00077 
00078         /**
00079          * Initializes clientlist, setting up data structures and network
00080          * connections as needed. This function should be called when the
00081          * module is initially loaded, but can also be called at any later
00082          * time on runtime to update/reset/restart the ClientList's internals.
00083          * On reason why you might want to call this is when you modify the
00084          * "TCP Port" value in ED2KConfig, in which case the main listener
00085          * must be restarted (done in this function).
00086          */
00087         void init();
00088 
00089         /**
00090          * Called on module exit; perform cleanup
00091          */
00092         void exit();
00093 private:
00094         ClientList();
00095         ~ClientList();
00096         ClientList(const ClientList&);
00097         ClientList& operator=(const ClientList&);
00098 
00099         //! Event handler for client events
00100         void onClientEvent(Client *c, ClientEvent evt);
00101 
00102         //! Event handler for socket server events
00103         void onServerEvent(ED2KServerSocket *s, SocketEvent evt);
00104 
00105         /**
00106          * Erase a client from all known containers and delete the object.
00107          *
00108          * @param c      Client to be destroyed.
00109          */
00110         void removeClient(Client *c);
00111 
00112         /**
00113          * Handles Client::changeId() signal; changes the client's Id, and
00114          * updates our internal data structures to reflect the change.
00115          *
00116          * @param c         Client that changes it's ID
00117          * @param newId     New ID of the client
00118          */
00119         void onIdChange(Client *c, uint32_t newId);
00120 
00121         /**
00122          * Event handler for our own events. This is actually used for queue
00123          * updating timed callback events (however, the events emitted from
00124          * this class may also be intercepted by external watchers if
00125          * interested). This function is called from event loop and should never
00126          * be called directly.
00127          *
00128          * @param evt     Event that happened
00129          */
00130         void onClientListEvent(ClientList *, ClientListEvt evt);
00131 
00132         /**
00133          * Re-generates m_queue vector (from m_queued set), ordered by the
00134          * client's scores. Sets each client's m_uploadClient member's queue
00135          * ranking based on their position in the resulting m_queue vector.
00136          *
00137          * This function is called once per every X seconds, where X is the
00138          * queue update interval. The purpose of this is to be able to send
00139          * queue rankings to remote clients (thus each client's member m_qr
00140          * value will indicate it's current position in the queue), as well as
00141          * for picking up highest-ranking clients from the queue when we want
00142          * to start sending data to them.
00143          */
00144         void updateQueue();
00145 
00146         /**
00147          * Selects the next valid client from the queue (highest-ranking), and
00148          * starts new upload on the client.
00149          */
00150         void startNextUpload();
00151 
00152         /**
00153          * Checks if we are uploading ineffectivly (e.g. current global upload
00154          * rate is significently below what is the limit), and then attempts
00155          * to open up another upload slot.
00156          */
00157         void checkOpenMoreSlots();
00158 
00159         /**
00160          * Locates a specific client. by ID and TCP port
00161          *
00162          * @param addr     ClientID and TCP port of the searched client
00163          * @return         Pointer to the client, or 0 if not found
00164          */
00165         Client* findClient(IPV4Address addr);
00166 
00167         /**
00168          * Locate a specific client, by ID and UDP port
00169          *
00170          * @param addr     ClientID and UDP port of the searched client
00171          * @return         Pointer to the client, or 0 if not found
00172          */
00173         Client* findClientByUdp(IPV4Address addr);
00174 
00175         /**
00176          * Event handler for ClientUDP socket events.
00177          */
00178         void onUdpData(ED2KUDPSocket *src, SocketEvent evt);
00179 
00180 private:
00181         /**
00182          * List of all clients we have alive.
00183          */
00184         boost::scoped_ptr<Detail::CList> m_clients;
00185 
00186         /**
00187          * This is the queued clients list. The contents of this list are
00188          * ordered by the clients score, generated every X seconds. Note that
00189          * every X seconds, this container is cleared and re-filled from
00190          * m_queuedClients set. Also note that there may be dangling pointers
00191          * existing in this list, in worst-case scenario for up to X seconds
00192          * (e.g. until after next full regen). As such, if you access this
00193          * container, you need to make sure the pointer you just got is still
00194          * valid by looking it up from m_queuedClients set. If it is not found
00195          * there, the pointer is invalid and should be discarded.
00196          */
00197         std::list<Client*> m_queue;
00198 
00199         /**
00200          * This set contains all clients which have m_uploadClient member
00201          * pointer and are not currently uploading. This set is used as base for
00202          * building up the actual upload queue into m_queue list every X
00203          * seconds. The purpose of this set is to have a reference container in
00204          * which we can actually erase elements using fast integer-based lookups
00205          * (which we couldn't do in m_queue list since that one is ordered by
00206          * score).
00207          *
00208          * Note that we could achive the same purpose by using m_clients
00209          * container, however, m_clients also contains downloadclients, so
00210          * it would cause many more loops in there to find the queued clients
00211          * than it is to find them here. Also, this set is a more static entity
00212          * than m_queue member (which is completely regenerated often).
00213          */
00214         std::set<Client*> m_queued;
00215 
00216         /**
00217          * This set contains all clients that are currently in uploading state,
00218          * e.g. sending data. The number of elements allowed in this list
00219          * depends on various factors, however it should never go below 1.
00220          */
00221         std::set<Client*> m_uploading;
00222 
00223         /**
00224          * Main ED2K listener socket. This is where all incoming TCP clients
00225          * connect to. By default it is set to listen on port 4662, however it
00226          * may be changed in configuration, under key "TCP Port".
00227          *
00228          * Note that if you modify the listener address, you need to also call
00229          * ClientList::init() to restart the listener.
00230          */
00231         ED2KServerSocket *m_listener;
00232 
00233         /**
00234          * Input buffer for UDP data; the size is defined by UDP_BUFSIZE
00235          */
00236         boost::scoped_array<char> m_udpBuffer;
00237 };
00238 
00239 #endif