/***************************************************************************** $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); /************************* class EventableDescriptor *************************/ class EventableDescriptor: public Bindable_t { public: EventableDescriptor (int, EventMachine_t*, bool = true); virtual ~EventableDescriptor(); int 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_storage*, socklen_t *len) {return false;} virtual bool GetSockname (struct sockaddr_storage*, socklen_t *len) {return false;} virtual bool GetSubprocessPid (pid_t*) {return false;} virtual void StartTls() {} virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer, bool use_tls) {} #ifdef WITH_SSL virtual X509 *GetPeerCert() {return NULL;} #endif virtual uint64_t GetCommInactivityTimeout() {return 0;} virtual int SetCommInactivityTimeout (uint64_t value) {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 virtual void StartProxy(const unsigned long, 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*,int){ 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 bAutoClose; bool bCloseNow; bool bCloseAfterWriting; protected: int MySocket; bool bAttached; bool bWatchOnly; EMCallback EventCallback; void _GenericInboundDispatch(const char*, int); 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 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 (int, EventMachine_t*); virtual ~LoopbreakDescriptor() {} virtual void Read(); virtual void Write(); virtual void Heartbeat() {} virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} }; /************************** class ConnectionDescriptor **************************/ class ConnectionDescriptor: public EventableDescriptor { public: ConnectionDescriptor (int, EventMachine_t*); virtual ~ConnectionDescriptor(); int SendOutboundData (const char*, int); 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 *privkey_filename, const char *certchain_filename, bool verify_peer, bool use_tls); #ifdef WITH_SSL virtual X509 *GetPeerCert(); virtual bool VerifySslPeer(const char*); virtual void AcceptSslPeer(); #endif void SetServerMode() {bIsServer = true;} virtual bool GetPeername (struct sockaddr_storage*, socklen_t *len); virtual bool GetSockname (struct sockaddr_storage*, socklen_t *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 ((char*)Buffer); } const char *Buffer; int Length; int Offset; }; protected: bool bConnectPending; bool bNotifyReadable; bool bNotifyWritable; bool bReadAttemptedAfterClose; bool bWriteAttemptedAfterClose; deque OutboundPages; int OutboundDataSize; #ifdef WITH_SSL SslBox_t *SslBox; std::string CertChainFilename; std::string PrivateKeyFilename; bool bHandshakeSignaled; bool bSslVerifyPeer; bool bSslUseTls; 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, int size); void _DispatchCiphertext(); int _SendRawOutboundData (const char*, int); void _CheckHandshakeStatus(); }; /************************ class DatagramDescriptor ************************/ class DatagramDescriptor: public EventableDescriptor { public: DatagramDescriptor (int, 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*, int); int SendOutboundDatagram (const char*, int, 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_storage*, socklen_t *len); virtual bool GetSockname (struct sockaddr_storage*, socklen_t *len); virtual uint64_t GetCommInactivityTimeout(); virtual int SetCommInactivityTimeout (uint64_t value); enum ERRORHANDLINGTYPE {ERRORHANDLING_KILL = 0, ERRORHANDLING_IGNORE = 1, ERRORHANDLING_REPORT = 2} SendErrorHandling; protected: struct OutboundPage { OutboundPage (const char *b, int l, struct sockaddr_storage &f, int o=0): Buffer(b), Length(l), Offset(o), From(*(struct sockaddr_in6*)&f) {} void Free() {if (Buffer) free ((char*)Buffer); } const char *Buffer; int Length; int Offset; // struct sockaddr_storage From; This would be *right*, but it is larger and thus slower than needed struct sockaddr_in6 From; }; deque OutboundPages; int OutboundDataSize; struct sockaddr_storage ReturnAddress; }; /************************ class AcceptorDescriptor ************************/ class AcceptorDescriptor: public EventableDescriptor { public: AcceptorDescriptor (int, EventMachine_t*, bool = true); virtual ~AcceptorDescriptor(); virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead() {return true;} virtual bool SelectForWrite() {return false;} virtual bool GetSockname (struct sockaddr_storage*, socklen_t *len); static void StopAcceptor (const unsigned long binding); }; /******************** class PipeDescriptor ********************/ #ifdef OS_UNIX class PipeDescriptor: public EventableDescriptor { public: PipeDescriptor (int, pid_t, EventMachine_t*); virtual ~PipeDescriptor(); virtual void Read(); virtual void Write(); virtual void Heartbeat(); virtual bool SelectForRead(); virtual bool SelectForWrite(); int SendOutboundData (const char*, int); virtual int GetOutboundDataSize() {return OutboundDataSize;} 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 ((char*)Buffer); } const char *Buffer; int Length; int Offset; }; protected: bool bReadAttemptedAfterClose; 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;} 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;} }; #endif // __EventableDescriptor__H_