clients.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 /**
00020  * @file clients.h Interface for Client classe
00021  */
00022 
00023 #ifndef __CLIENTS_H__
00024 #define __CLIENTS_H__
00025 
00026 #include <hn/object.h>
00027 #include <hn/ipv4addr.h>
00028 #include <hn/hash.h>
00029 #include "ed2ktypes.h"
00030 #include "publickey.h"
00031 #include <boost/tuple/tuple.hpp>
00032 
00033 //! Events emitted from Client objects
00034 enum ClientEvent {
00035         EVT_DESTROY,               //!< Client will be destroyed
00036         EVT_UPLOADREQ,             //!< Indicates we want to upload
00037         EVT_IDCHANGE,              //!< Client ID changed
00038         EVT_CANCEL_UPLOADREQ,      //!< Indicate we no longer want to send data
00039         EVT_CALLBACK_T,            //!< LowID callback timeout event
00040         EVT_REASKFILEPING,         //!< Delayed event for UDP reasks
00041         EVT_REASKTIMEOUT           //!< Delayed event for UDP reasks timeouts
00042 };
00043 
00044 namespace Detail {
00045         /**
00046          * \name Signals emitted from Client object
00047          *
00048          * These are declared here, as global, because we cannot use static data
00049          * in modules.
00050          */
00051         //!@{
00052         /**
00053          * Emitted when a client changes it's ID
00054          *
00055          * @param Client*   Client that changed it's ID
00056          * @param uint32_t  The new ID of the client
00057          */
00058         extern boost::signal<void (Client*, uint32_t)> changeId;
00059 
00060         /**
00061          * Emitted when a new source is discovered by a client
00062          *
00063          * @param Hash<ED2KHash>&  Hash of the file the source offers
00064          * @param IPV4Address      Source IP/port
00065          * @param IPV4Address      Server IP/port where the source is
00066          * @param bool             If true, attempt to connect to the client now
00067          * @return True if the source was added, false otherwise
00068          */
00069         extern boost::signal<
00070                 bool (const Hash<ED2KHash>&, IPV4Address, IPV4Address, bool)
00071         > foundSource;
00072 
00073         /**
00074          * Emitted when a new server is discovered
00075          *
00076          * @param IPV4Address   The server's IP/port
00077          */
00078         extern boost::signal<void (IPV4Address)> foundServer;
00079         //!@}
00080 }
00081 
00082 /**
00083  * Client object encapsulates a single remote client that we are communicating
00084  * with. The reasons for communication may be either because it wants something
00085  * from us, because we want something from it, or even both. The exact purpose
00086  * of the client is not defined by this object. Instead, the purpose is defined
00087  * by member objects DownloadClient and/or UploadClient. As long as the client
00088  * has at least a single purpose, it must be alive, however when it has
00089  * fulfulled it's purpose, and no longer contains neither UploadClient nor
00090  * DownloadClient, it must return to the source.
00091  */
00092 class Client : public Trackable {
00093 public:
00094         DECLARE_EVENT_TABLE(Client*, ClientEvent);
00095 
00096         //! @name get-to-know-you-chit-chat
00097         //@{
00098         void onPacket(const ED2KPacket::Hello &p);
00099         void onPacket(const ED2KPacket::HelloAnswer &p);
00100         void onPacket(const ED2KPacket::MuleInfo &p);
00101         void onPacket(const ED2KPacket::MuleInfoAnswer &p);
00102         //@}
00103         //! @name Uploading
00104         //@{
00105         void onPacket(const ED2KPacket::ReqFile &p);
00106         void onPacket(const ED2KPacket::SetReqFileId &p);
00107         void onPacket(const ED2KPacket::ReqHashSet &p);
00108         void onPacket(const ED2KPacket::StartUploadReq &p);
00109         void onPacket(const ED2KPacket::ReqChunks &p);
00110         void onPacket(const ED2KPacket::CancelTransfer &);
00111         //@}
00112         //! @name Downloading
00113         //@{
00114         void onPacket(const ED2KPacket::FileName &p);
00115         void onPacket(const ED2KPacket::FileDesc &p);
00116         void onPacket(const ED2KPacket::NoFile &p);
00117         void onPacket(const ED2KPacket::FileStatus &p);
00118         void onPacket(const ED2KPacket::HashSet &p);
00119         void onPacket(const ED2KPacket::AcceptUploadReq &);
00120         void onPacket(const ED2KPacket::QueueRanking &p);
00121         void onPacket(const ED2KPacket::MuleQueueRank &p);
00122         void onPacket(const ED2KPacket::DataChunk &p);
00123         void onPacket(const ED2KPacket::PackedChunk &p);
00124         //@}
00125         //! @name Source Exchange
00126         //@{
00127         void onPacket(const ED2KPacket::SourceExchReq &p);
00128         void onPacket(const ED2KPacket::AnswerSources &p);
00129         //@}
00130         //! @name Miscellanous
00131         //@{
00132         void onPacket(const ED2KPacket::Message &p);
00133         void onPacket(const ED2KPacket::ChangeId &p);
00134         //@}
00135         //! @name SecIdent
00136         //@{
00137         void onPacket(const ED2KPacket::SecIdentState &p);
00138         void onPacket(const ED2KPacket::PublicKey &p);
00139         void onPacket(const ED2KPacket::Signature &p);
00140         //@}
00141         //! @name UDP packets
00142         //@{
00143         void onPacket(const ED2KPacket::ReaskFilePing &p);
00144         void onPacket(const ED2KPacket::FileNotFound &p);
00145         void onPacket(const ED2KPacket::ReaskAck &p);
00146         void onPacket(const ED2KPacket::QueueFull &p);
00147         //@}
00148 
00149         //! @name Accessors for this client's information
00150         //@{
00151         Hash<MD4Hash> getHash()       const { return m_hash;                   }
00152         uint32_t      getId()         const { return m_id;                     }
00153         uint16_t      getTcpPort()    const { return m_tcpPort;                }
00154         uint16_t      getUdpPort()    const { return m_udpPort;                }
00155         IPV4Address   getServerAddr() const { return m_serverAddr;             }
00156         std::string   getNick()       const { return m_nick;                   }
00157         bool    supportsPreview()     const { return m_features       & 0x01;  }
00158         bool    supportsMultiPacket() const { return m_features       & 0x02;  }
00159         bool    supportsViewShared()  const { return m_features       &~0x04;  }
00160         bool    supportsPeerCache()   const { return m_features       & 0x08;  }
00161         uint8_t getCommentVer()       const { return m_features >>  4 & 0x0f;  }
00162         uint8_t getExtReqVer()        const { return m_features >>  8 & 0x0f;  }
00163         uint8_t getSrcExchVer()       const { return m_features >> 12 & 0x0f;  }
00164         uint8_t getSecIdentVer()      const { return m_features >> 16 & 0x0f;  }
00165         uint8_t getComprVer()         const { return m_features >> 20 & 0x0f;  }
00166         uint8_t getUdpVer()           const { return m_features >> 24 & 0x0f;  }
00167         bool    supportsUnicode()     const { return m_features >> 28 & 0x01;  }
00168         uint8_t getAICHVer()          const { return m_features >> 29 & 0x07;  }
00169         bool    isLowId()             const { return m_id < 0x00ffffff;        }
00170         bool    isHighId()            const { return m_id > 0x00ffffff;        }
00171         uint8_t getClientSoft()       const { return m_clientSoft >> 24;       }
00172         uint32_t getVerMjr()          const { return m_clientSoft >> 17 & 0x7f;}
00173         uint32_t getVerMin()          const { return m_clientSoft >> 10 & 0x7f;}
00174         uint32_t getVerPch()          const { return m_clientSoft >>  7 & 0x07;}
00175         uint32_t getVerBld()          const { return m_clientSoft       & 0x7f;}
00176         std::string getSoftStr() const;
00177         std::string getVerStr()  const;
00178         bool isMule() const; // returns true if this is an eMule-compat client
00179         //@}
00180 
00181         //! @name Other generic accessors
00182         //@{
00183         ED2KClientSocket* getSocket() const { return m_socket; }
00184         void setSocket(ED2KClientSocket *s) {
00185                 CHECK_THROW(m_socket);// don't allow overwriting existing socket
00186                 m_socket = s;
00187         }
00188         //@}
00189 
00190         void setServerAddr(IPV4Address addr) { m_serverAddr = addr; }
00191 
00192         /**
00193          * Start uploading to this client.
00194          *
00195          * \pre m_uploadClient member exists
00196          */
00197         void startUpload();
00198 
00199         /**
00200          * Request to download current requested file from this client
00201          * (e.g. sends ReqFile packet).
00202          */
00203         void reqDownload();
00204 
00205         /**
00206          * Send queue ranking to the remote client.
00207          *
00208          * \pre m_socket exists and is in connected state
00209          * \pre m_uploadClient exists
00210          */
00211         void sendQR();
00212 
00213         /**
00214          * Calculates client score, based on credits and wait time in queue
00215          * (if applicaple)
00216          */
00217         float getScore() const;
00218 
00219         /**
00220          * Add an offered file to this client's offered files list.
00221          *
00222          * @param file    Offered file
00223          * @param doConn  Whether we are allowed to establish connection too
00224          */
00225         void addOffered(Download *file, bool doConn = true);
00226 
00227         /**
00228          * Remove an offered file
00229          *
00230          * @param file    File this client is no longer offering
00231          * @param cleanUp If true, also cleanup our things from PartData
00232          */
00233         void remOffered(Download *file, bool cleanUp = true);
00234 
00235         /**
00236          * Check if the connection is currently established with this client.
00237          *
00238          * @returns true if yes, false otherwise
00239          */
00240         bool isConnected() const;
00241 
00242         /**
00243          * Check whether there's LowID callback in progress
00244          *
00245          * @return true if there's a LowID callback in progress, false otherwise
00246          */
00247         bool callbackInProgress() const { return m_callbackInProgress; }
00248 
00249         /**
00250          * Check whether we are currently in process of reasking the source.
00251          *
00252          * @return true if reasking is in progress, false otherwise
00253          */
00254         bool reaskInProgress() const { return m_reaskInProgress; }
00255 
00256         /**
00257          * Set the current client state to indicate that we are on remote
00258          * client's queue, waiting for an upload. This implies we have
00259          * m_sourceInfo member alive, and no m_downloadInfo.
00260          *
00261          * Don't confuse this with similar concept where the remote client is
00262          * queued on our upload queue.
00263          *
00264          * @param qr        Remote queue rank
00265          */
00266         void setOnQueue(uint32_t qr);
00267 
00268         /**
00269          * Resets all queue-related data and emits EVT_CANCEL_UPLOADREQ to
00270          * indicate that this client no longer wants anything from us.
00271          */
00272         void removeFromQueue();
00273 
00274         /**
00275          * Attempt to verify this client's identity
00276          */
00277         void verifyIdent();
00278 
00279         /**
00280          * Small helper function for retrieving client IP/ID/port combination
00281          * in printable format.
00282          */
00283         std::string getIpPort() const;
00284 
00285         /**
00286          * \name Accessors for extensions
00287          */
00288         //!@{
00289         Detail::SourceInfoPtr   getSourceInfo()   const { return m_sourceInfo; }
00290         Detail::QueueInfoPtr    getQueueInfo()    const { return m_queueInfo;  }
00291         Detail::UploadInfoPtr   getUploadInfo()   const { return m_uploadInfo; }
00292         Detail::DownloadInfoPtr getDownloadInfo() const {return m_downloadInfo;}
00293         //!@}
00294 private:
00295         friend class ClientList;
00296         Client();                                    //!< Forbidden
00297         ~Client();                                   //!< Allowed by ClientList
00298         Client(const Client&);                       //!< Copying forbidden
00299         const Client& operator=(const Client&);      //!< Copying forbidden
00300 
00301         /**
00302          * Only allowed constructor. The socket is required to initialize the
00303          * client and perform initial handshaking with the client.
00304          *
00305          * @param c         Socket connecting to this client.
00306          *
00307          * \pre  The socket must be in connected state, waiting for data.
00308          * \post The socket object ownership is transfered to this class.
00309          */
00310         Client(ED2KClientSocket *c);
00311 
00312         /**
00313          * Construct a "source" type client, which has a file to offer for us.
00314          *
00315          * @param addr     Address where the client is
00316          * @param file     File the client is offering
00317          */
00318         Client(IPV4Address addr, Download *file);
00319 
00320         /**
00321          * Event handler for socket events. This is called from event loop.
00322          *
00323          * @param c      Socket causing the event. Must match m_socket member
00324          * @param evt    The event that happened
00325          */
00326         void onSocketEvent(ED2KClientSocket *c, SocketEvent evt);
00327 
00328         /**
00329          * Scheduler the object for destruction. Note that the actual
00330          * destruction is performed by the owner of this object (ClientList).
00331          */
00332         void destroy();
00333 
00334         /**
00335          * Copy client information from the hello packet to internal variables.
00336          *
00337          * @param p        Packet to copy the data from
00338          *
00339          * \note This overwrites any existing information we might have stored
00340          *       for this client.
00341          */
00342         void storeInfo(const ED2KPacket::Hello &p);
00343 
00344         /**
00345          * Processes, extracts and stores all useful information from this
00346          * extinct packet, used by some older mule-based clients.
00347          *
00348          * @param p       MuleInfo packet to be processed
00349          */
00350         void processMuleInfo(const ED2KPacket::MuleInfo &p);
00351 
00352         /**
00353          * Merge sockets and parser from other client to this client, taking
00354          * ownership of those two.
00355          *
00356          * @param c     Other client to merge data from
00357          */
00358         void merge(Client *c);
00359 
00360         /**
00361          * Generalized version of upload requests - constructs the neccesery
00362          * members and emits the neccesery events, indicating the client wishes
00363          * to download something from us.
00364          *
00365          * @param hash      Hash of the file the client is interested in.
00366          */
00367         void onUploadReq(const Hash<ED2KHash> &hash);
00368 
00369         /**
00370          * Sends next three chunk requests to current downloadclient.
00371          *
00372          * @param onlyNew If set true, only new requests are sent
00373          */
00374         void sendChunkReqs(bool onlyNew = false);
00375 
00376         /**
00377          * Sends next chunk to socket (when uploading)
00378          */
00379         void sendNextChunk();
00380 
00381         /**
00382          * Establish connection with the remote client either by directly
00383          * connecting to it, or performing a low-id callback operation through
00384          * server.
00385          */
00386         void establishConnection();
00387 
00388         /**
00389          * Performs UDP reask for download.
00390          */
00391         void reaskForDownload();
00392 
00393         /**
00394          * Checks if this client is useful to us at all, and if not, emits
00395          * EVT_DESTROY.
00396          */
00397         void checkDestroy();
00398 
00399         /**
00400          * Send our signature to this client.
00401          *
00402          * \pre m_reqChallenge must be set to nonzero challenge value
00403          * \pre m_pubKey must exist and be valid
00404          * \post m_reqChallenge is set to 0
00405          */
00406         void sendSignature();
00407 
00408         //! Send our public key to this client
00409         void sendPublicKey();
00410 
00411         //! Called after successful handshake (and optionally, SecIdent), starts
00412         //! actual data transfer.
00413         void initTransfer();
00414 
00415         /**
00416          * Called by ClientList after received IDChange event from us, this
00417          * indicates that merging (if any) with existing client has been
00418          * completed, and we are ready to proceed, depending on context.
00419          *
00420          * If supported, the identity of the client will be verified (SecIdent),
00421          * and after that, depending on which extensions are present, operations
00422          * performed, e.g. start uploading/downloading.
00423          */
00424         void handshakeCompleted();
00425 
00426         /**
00427          * Verify the contents of the passed hashset by re-calculating the file-
00428          * hash from the chunkhashes.
00429          */
00430         void verifyHashSet(boost::shared_ptr<ED2KHashSet> hs);
00431 
00432         /**
00433          * Returns reference to pointer to ClientUDPSocket; only allowed to be
00434          * used by ClientList
00435          */
00436         static ED2KUDPSocket*& getUdpSocket();
00437 
00438         /**
00439          * @name Information we have on this client
00440          */
00441         //@{
00442         uint32_t      m_id;             //!< Client ID ( <= 0x00fffff == LowID )
00443         uint16_t      m_tcpPort;        //!< TCP port
00444         uint16_t      m_udpPort;        //!< UDP port
00445         uint32_t      m_features;       //!< Supported features
00446         Hash<MD4Hash> m_hash;           //!< Userhash
00447         PublicKey     m_pubKey;         //!< Client's public key
00448         IPV4Address   m_serverAddr;     //!< Server the client is connected to
00449         std::string   m_nick;           //!< User nickname
00450         uint32_t      m_clientSoft;     //!< Client soft and version
00451         //@}
00452 
00453         /**
00454          * @name Internal things
00455          */
00456         //@{
00457         boost::shared_ptr<ED2KParser<Client> > m_parser;    //!< Stream parser
00458         ED2KClientSocket*  m_socket;    //!< Socket
00459         Credits*           m_credits;   //!< May be 0
00460         //@}
00461 
00462         /**
00463          * Extensions to Client object (also called purposes). If none of these
00464          * exists, the client should be destroyed.
00465          */
00466         //@{
00467         Detail::QueueInfoPtr    m_queueInfo;
00468         Detail::UploadInfoPtr   m_uploadInfo;
00469         Detail::SourceInfoPtr   m_sourceInfo;
00470         Detail::DownloadInfoPtr m_downloadInfo;
00471         //@}
00472 
00473         // these are related to sources only, so should probably be moved to
00474         // SourceInfo class
00475         bool m_callbackInProgress; //!< TCP callback is in progress
00476         bool m_reaskInProgress;    //!< (UDP) reask is in progress
00477         uint8_t m_failedUdpReasks; //!< Number of failed UDP reasks (in row)
00478         uint64_t m_lastReaskTime;  //!< When was last source reask done
00479 
00480         // miscellanous stuff
00481 
00482         //! During identity verification, contains challenge sent TO the client
00483         uint32_t m_sentChallenge;
00484         //! During identity verification, contains challenge sent BY the client
00485         uint32_t m_reqChallenge;
00486 
00487         bool m_upReqInProgress; //!< State: Upload request is in progress
00488         bool m_dnReqInProgress; //!< State: Download request is in progress
00489 };
00490 
00491 
00492 #endif