|
|
f07ad6 |
#ifndef CONNECTION_H
|
|
|
f07ad6 |
#define CONNECTION_H
|
|
|
f07ad6 |
|
|
|
f07ad6 |
|
|
|
f07ad6 |
#include <cstring></cstring>
|
|
|
f07ad6 |
|
|
|
f07ad6 |
#include <deque></deque>
|
|
|
f07ad6 |
#include <mutex></mutex>
|
|
|
f07ad6 |
|
|
|
f07ad6 |
#include "error.h"
|
|
|
f07ad6 |
#include "address.h"
|
|
|
f07ad6 |
|
|
|
f07ad6 |
|
|
|
f07ad6 |
enum : ErrorCode {
|
|
|
f07ad6 |
ERR_CONNECTION_COMMON = ERR_CONNECTION,
|
|
|
f07ad6 |
ERR_CONNECTION_FAILED,
|
|
|
f07ad6 |
ERR_CONNECTION_UNFINISHED_TASKS,
|
|
|
f07ad6 |
ERR_CONNECTION_LOST,
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
|
|
|
f07ad6 |
class Protocol;
|
|
|
f07ad6 |
class Socket;
|
|
|
f07ad6 |
class Server;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
|
|
|
f07ad6 |
class Connection {
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
typedef unsigned long long ReqId;
|
|
|
f07ad6 |
typedef std::recursive_mutex Mutex;
|
|
|
f07ad6 |
typedef std::lock_guard<mutex> Lock;</mutex>
|
|
|
f07ad6 |
|
|
|
f07ad6 |
template<typename t=""></typename>
|
|
|
f07ad6 |
struct TRWReq {
|
|
|
f07ad6 |
typedef T Type;
|
|
|
f07ad6 |
typedef std::deque< TRWReq<t> > Queue;</t>
|
|
|
f07ad6 |
|
|
|
f07ad6 |
ReqId id;
|
|
|
f07ad6 |
void *userData;
|
|
|
f07ad6 |
Type *data;
|
|
|
f07ad6 |
size_t size;
|
|
|
f07ad6 |
size_t doneSize;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
inline TRWReq(ReqId id = 0, void *userData = nullptr, Type *data = nullptr, size_t size = 0):
|
|
|
f07ad6 |
id(id), userData(userData), data(data), size(size), doneSize() { }
|
|
|
f07ad6 |
|
|
|
f07ad6 |
inline bool success() const
|
|
|
f07ad6 |
{ return doneSize >= size; }
|
|
|
f07ad6 |
inline size_t remains() const
|
|
|
f07ad6 |
{ assert(size >= doneSize); return size - doneSize; }
|
|
|
f07ad6 |
inline void processed(size_t size) {
|
|
|
f07ad6 |
assert(size <= remains());
|
|
|
f07ad6 |
if (doneSize > size || size > remains())
|
|
|
f07ad6 |
doneSize = size; else doneSize += size;
|
|
|
f07ad6 |
}
|
|
|
f07ad6 |
inline Type* current() const
|
|
|
f07ad6 |
{ assert(size >= doneSize); return const_cast<char*>((const char*)data + doneSize); }</char*>
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
typedef TRWReq<void> ReadReq;</void>
|
|
|
f07ad6 |
typedef TRWReq<const void=""> WriteReq;</const>
|
|
|
f07ad6 |
typedef ReadReq::Queue ReadQueue;
|
|
|
f07ad6 |
typedef WriteReq::Queue WriteQueue;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
template<typename t=""></typename>
|
|
|
f07ad6 |
class TRWLock {
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
typedef TRWReq<t> ReqType;</t>
|
|
|
f07ad6 |
typedef TRWLock<t> LockType;</t>
|
|
|
f07ad6 |
|
|
|
f07ad6 |
Lock lock;
|
|
|
f07ad6 |
Connection &connection;
|
|
|
f07ad6 |
ReqType * const request;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
protected:
|
|
|
f07ad6 |
inline TRWLock(Connection &connection, typename ReqType::Queue &queue):
|
|
|
f07ad6 |
lock(connection.mutex), connection(connection), request(queue.empty() ? nullptr : &queue.front()) { }
|
|
|
f07ad6 |
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
inline operator bool() const
|
|
|
f07ad6 |
{ return request; }
|
|
|
f07ad6 |
inline bool success() const
|
|
|
f07ad6 |
{ return request && request->success(); }
|
|
|
f07ad6 |
inline ReqType& operator*() const
|
|
|
f07ad6 |
{ assert(request); return request; }
|
|
|
f07ad6 |
inline ReqType* operator->() const
|
|
|
f07ad6 |
{ assert(request); return request; }
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
class ReadLock: public TRWLock<void> {</void>
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
inline ReadLock(Connection &connection):
|
|
|
f07ad6 |
LockType(connection, connection.readQueue) { }
|
|
|
f07ad6 |
inline ~ReadLock()
|
|
|
f07ad6 |
{ if (success()) connection.onReadReady(*request); }
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
class WriteLock: public TRWLock<const void=""> {</const>
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
inline WriteLock(Connection &connection):
|
|
|
f07ad6 |
LockType(connection, connection.writeQueue) { }
|
|
|
f07ad6 |
inline ~WriteLock()
|
|
|
f07ad6 |
{ if (success()) connection.onWriteReady(*request); }
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
private:
|
|
|
f07ad6 |
Mutex mutex;
|
|
|
f07ad6 |
Socket *socket;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
ReqId lastId;
|
|
|
f07ad6 |
ReadQueue readQueue;
|
|
|
f07ad6 |
WriteQueue writeQueue;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
public:
|
|
|
f07ad6 |
Connection();
|
|
|
f07ad6 |
virtual ~Connection();
|
|
|
f07ad6 |
|
|
|
f07ad6 |
void open(Socket *socket);
|
|
|
f07ad6 |
ErrorCode open(Protocol &protocol, const Address &remoteAddress);
|
|
|
f07ad6 |
void close(ErrorCode errorCode = ERR_NONE);
|
|
|
f07ad6 |
|
|
|
f07ad6 |
ReqId writeReq(const void *data, size_t size, void *userData = nullptr);
|
|
|
f07ad6 |
ReqId readReq(void *data, size_t size, void *userData = nullptr);
|
|
|
f07ad6 |
|
|
|
f07ad6 |
protected:
|
|
|
f07ad6 |
Protocol& getProtocol() const;
|
|
|
f07ad6 |
const Address& getRemoteAddress() const;
|
|
|
f07ad6 |
Server* getServer() const;
|
|
|
f07ad6 |
|
|
|
f07ad6 |
virtual void onOpen();
|
|
|
f07ad6 |
virtual void onClose(ErrorCode errorCode);
|
|
|
f07ad6 |
virtual void onReadReady(const ReadReq &req);
|
|
|
f07ad6 |
virtual void onWriteReady(const WriteReq &req);
|
|
|
f07ad6 |
};
|
|
|
f07ad6 |
|
|
|
f07ad6 |
|
|
|
f07ad6 |
#endif
|