/***************************************************************************** $Id$ File: ed.h Date: 06Apr06 Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. Gmail: blackhedd This program is free software; you can redistribute it and/or modify it under the terms of either: 1) the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version; or 2) Ruby's License. See the file COPYING for complete licensing information. *****************************************************************************/ #ifndef __EventableDescriptor__H_ #define __EventableDescriptor__H_ class EventMachine_t; // forward reference #ifdef WITH_SSL class SslBox_t; // forward reference #endif bool SetSocketNonblocking (SOCKET); bool SetFdCloexec (int); /************************* class EventableDescriptor *************************/ class EventableDescriptor: public Bindable_t { public: EventableDescriptor (SOCKET, EventMachine_t*); virtual ~EventableDescriptor() NO_EXCEPT_FALSE; SOCKET GetSocket() {return MySocket;} void SetSocketInvalid() { MySocket = INVALID_SOCKET; } void Close(); virtual void Read() = 0; virtual void Write() = 0; virtual void Heartbeat() = 0; // These methods tell us whether the descriptor // should be selected or polled for read/write. virtual bool SelectForRead() = 0; virtual bool SelectForWrite() = 0; // are we scheduled for a close, or in an error state, or already closed? bool ShouldDelete(); // Do we have any data to write? This is used by ShouldDelete. virtual int GetOutboundDataSize() {return 0;} virtual bool IsWatchOnly(){ return bWatchOnly; } virtual void ScheduleClose (bool after_writing); bool IsCloseScheduled(); virtual void HandleError(){ ScheduleClose (false); } void SetEventCallback (EMCallback); virtual bool GetPeername (struct sockaddr*, socklen_t*) = 0; virtual bool GetSockname (struct sockaddr*, socklen_t*) = 0; virtual bool GetSubprocessPid (pid_t*) {return false;} virtual void StartTls() {} virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int) {} #ifdef WITH_SSL virtual X509 *GetPeerCert() {return NULL;} virtual int GetCipherBits() {return -1;} virtual const char *GetCipherName() {return NULL;} virtual const char *GetCipherProtocol() {return NULL;} virtual const char *GetSNIHostname() {return NULL;} #endif virtual uint64_t GetCommInactivityTimeout() {return 0;} virtual int SetCommInactivityTimeout (uint64_t) {return 0;} uint64_t GetPendingConnectTimeout(); int SetPendingConnectTimeout (uint64_t value); uint64_t GetLastActivity() { return LastActivity; } #ifdef HAVE_EPOLL struct epoll_event *GetEpollEvent() { return &EpollEvent; } #endif #ifdef HAVE_KQUEUE bool GetKqueueArmWrite() { return bKqueueArmWrite; } #endif virtual void StartProxy(const uintptr_t, const unsigned long, const unsigned long); virtual void StopProxy(); virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; }; virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long); virtual int SendOutboundData(const char*,unsigned long){ return -1; } virtual bool IsPaused(){ return bPaused; } virtual bool Pause(){ bPaused = true; return bPaused; } virtual bool Resume(){ bPaused = false; return bPaused; } void SetUnbindReasonCode(int code){ UnbindReasonCode = code; } virtual int ReportErrorStatus(){ return 0; } virtual bool IsConnectPending(){ return false; } virtual uint64_t GetNextHeartbeat(); private: bool bCloseNow; bool bCloseAfterWriting; protected: SOCKET MySocket; bool bAttached; bool bWatchOnly; EMCallback EventCallback; void _GenericInboundDispatch (const char *buffer, unsigned long size); bool _GenericGetPeername (struct sockaddr*, socklen_t*); bool _GenericGetSockname (struct sockaddr*, socklen_t*); uint64_t CreatedAt; bool bCallbackUnbind; int UnbindReasonCode; unsigned long BytesToProxy; EventableDescriptor *ProxyTarget; EventableDescriptor *ProxiedFrom; unsigned long ProxiedBytes; unsigned long MaxOutboundBufSize; #ifdef HAVE_EPOLL struct epoll_event EpollEvent; #endif #ifdef HAVE_KQUEUE bool bKqueueArmWrite; #endif EventMachine_t *MyEventMachine; uint64_t PendingConnectTimeout; uint64_t InactivityTimeout; uint64_t LastActivity; uint64_t NextHeartbeat; bool bPaused; }; /************************* class LoopbreakDescriptor *************************/ class LoopbreakDescriptor: public EventableDescriptor { public: LoopbreakDescriptor (SOCKET, EventMachine_t*); virtual ~LoopbreakDescriptor() {} virtual void Read(); virtual void Write(); virtual void Heartbeat() {} virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } }; /************************** class ConnectionDescriptor **************************/ class ConnectionDescriptor: public EventableDescriptor { public: ConnectionDescriptor (SOCKET, EventMachine_t*); virtual ~ConnectionDescriptor(); int SendOutboundData (const char*, unsigned long); void SetConnectPending (bool f); virtual void ScheduleClose (bool after_writing); virtual void HandleError(); void SetNotifyReadable (bool); void SetNotifyWritable (bool); void SetAttached (bool); void SetWatchOnly (bool); bool Pause(); bool Resume(); bool IsNotifyReadable(){ return bNotifyReadable; } bool IsNotifyWritable(){ return bNotifyWritable; } virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead(); virtual bool SelectForWrite(); // Do we have any data to write? This is used by ShouldDelete. virtual int GetOutboundDataSize() {return OutboundDataSize;} virtual void StartTls(); virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int); #ifdef WITH_SSL virtual X509 *GetPeerCert(); virtual int GetCipherBits(); virtual const char *GetCipherName(); virtual const char *GetCipherProtocol(); virtual const char *GetSNIHostname(); virtual bool VerifySslPeer(const char*); virtual void AcceptSslPeer(); #endif void SetServerMode() {bIsServer = true;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } virtual uint64_t GetCommInactivityTimeout(); virtual int SetCommInactivityTimeout (uint64_t value); virtual int ReportErrorStatus(); virtual bool IsConnectPending(){ return bConnectPending; } protected: struct OutboundPage { OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {} void Free() {if (Buffer) free (const_cast(Buffer)); } const char *Buffer; int Length; int Offset; }; protected: bool bConnectPending; bool bNotifyReadable; bool bNotifyWritable; bool bReadAttemptedAfterClose; bool bWriteAttemptedAfterClose; std::deque OutboundPages; int OutboundDataSize; #ifdef WITH_SSL SslBox_t *SslBox; std::string CertChainFilename; std::string PrivateKeyFilename; std::string CipherList; std::string EcdhCurve; std::string DhParam; int Protocols; bool bHandshakeSignaled; bool bSslVerifyPeer; bool bSslFailIfNoPeerCert; std::string SniHostName; bool bSslPeerAccepted; #endif #ifdef HAVE_KQUEUE bool bGotExtraKqueueEvent; #endif bool bIsServer; private: void _UpdateEvents(); void _UpdateEvents(bool, bool); void _WriteOutboundData(); void _DispatchInboundData (const char *buffer, unsigned long size); void _DispatchCiphertext(); int _SendRawOutboundData (const char *buffer, unsigned long size); void _CheckHandshakeStatus(); }; /************************ class DatagramDescriptor ************************/ class DatagramDescriptor: public EventableDescriptor { public: DatagramDescriptor (SOCKET, EventMachine_t*); virtual ~DatagramDescriptor(); virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead() {return true;} virtual bool SelectForWrite(); int SendOutboundData (const char*, unsigned long); int SendOutboundDatagram (const char*, unsigned long, const char*, int); // Do we have any data to write? This is used by ShouldDelete. virtual int GetOutboundDataSize() {return OutboundDataSize;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len); virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); }; virtual uint64_t GetCommInactivityTimeout(); virtual int SetCommInactivityTimeout (uint64_t value); protected: struct OutboundPage { OutboundPage (const char *b, int l, struct sockaddr_in6 f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {} void Free() {if (Buffer) free (const_cast(Buffer)); } const char *Buffer; int Length; int Offset; struct sockaddr_in6 From; }; std::deque OutboundPages; int OutboundDataSize; struct sockaddr_in6 ReturnAddress; }; /************************ class AcceptorDescriptor ************************/ class AcceptorDescriptor: public EventableDescriptor { public: AcceptorDescriptor (SOCKET, EventMachine_t*); virtual ~AcceptorDescriptor(); virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); }; static void StopAcceptor (const uintptr_t binding); }; /******************** class PipeDescriptor ********************/ #ifdef OS_UNIX class PipeDescriptor: public EventableDescriptor { public: PipeDescriptor (SOCKET, pid_t, EventMachine_t*); virtual ~PipeDescriptor() NO_EXCEPT_FALSE; virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead(); virtual bool SelectForWrite(); int SendOutboundData (const char*, unsigned long); virtual int GetOutboundDataSize() {return OutboundDataSize;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } virtual bool GetSubprocessPid (pid_t*); protected: struct OutboundPage { OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {} void Free() {if (Buffer) free (const_cast(Buffer)); } const char *Buffer; int Length; int Offset; }; protected: bool bReadAttemptedAfterClose; std::deque OutboundPages; int OutboundDataSize; pid_t SubprocessPid; private: void _DispatchInboundData (const char *buffer, int size); }; #endif // OS_UNIX /************************ class KeyboardDescriptor ************************/ class KeyboardDescriptor: public EventableDescriptor { public: KeyboardDescriptor (EventMachine_t*); virtual ~KeyboardDescriptor(); virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return _GenericGetPeername (s, len); } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return _GenericGetSockname (s, len); } protected: bool bReadAttemptedAfterClose; private: void _DispatchInboundData (const char *buffer, int size); }; /*********************** class InotifyDescriptor ************************/ class InotifyDescriptor: public EventableDescriptor { public: InotifyDescriptor (EventMachine_t*); virtual ~InotifyDescriptor(); void Read(); void Write(); virtual void Heartbeat() {} virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} virtual bool GetPeername (struct sockaddr* s, socklen_t* len) { return false; } virtual bool GetSockname (struct sockaddr* s, socklen_t* len) { return false; } }; #endif // __EventableDescriptor__H_