michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: michael@0: #ifndef transportlayer_h__ michael@0: #define transportlayer_h__ michael@0: michael@0: #include "sigslot.h" michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIEventTarget.h" michael@0: michael@0: #include "m_cpp_utils.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: class TransportFlow; michael@0: michael@0: typedef int TransportResult; michael@0: michael@0: enum { michael@0: TE_WOULDBLOCK = -1, TE_ERROR = -2, TE_INTERNAL = -3 michael@0: }; michael@0: michael@0: #define TRANSPORT_LAYER_ID(name) \ michael@0: virtual const std::string id() { return name; } \ michael@0: static std::string ID() { return name; } michael@0: michael@0: // Abstract base class for network transport layers. michael@0: class TransportLayer : public sigslot::has_slots<> { michael@0: public: michael@0: // The state of the transport flow michael@0: // We can't use "ERROR" because Windows has a macro named "ERROR" michael@0: enum State { TS_NONE, TS_INIT, TS_CONNECTING, TS_OPEN, TS_CLOSED, TS_ERROR }; michael@0: enum Mode { STREAM, DGRAM }; michael@0: michael@0: // Is this a stream or datagram flow michael@0: TransportLayer(Mode mode = STREAM) : michael@0: mode_(mode), michael@0: state_(TS_NONE), michael@0: flow_id_(), michael@0: downward_(nullptr) {} michael@0: michael@0: virtual ~TransportLayer() {} michael@0: michael@0: // Called to initialize michael@0: nsresult Init(); // Called by Insert() to set up -- do not override michael@0: virtual nsresult InitInternal() { return NS_OK; } // Called by Init michael@0: michael@0: // Called when inserted into a flow michael@0: virtual void Inserted(TransportFlow *flow, TransportLayer *downward); michael@0: michael@0: // Downward interface michael@0: TransportLayer *downward() { return downward_; } michael@0: michael@0: // Dispatch a call onto our thread (or run on the same thread if michael@0: // thread is not set). This is always synchronous. michael@0: nsresult RunOnThread(nsIRunnable *event); michael@0: michael@0: // Get the state michael@0: State state() const { return state_; } michael@0: // Must be implemented by derived classes michael@0: virtual TransportResult SendPacket(const unsigned char *data, size_t len) = 0; michael@0: michael@0: // Get the thread. michael@0: const nsCOMPtr GetThread() const { michael@0: return target_; michael@0: } michael@0: michael@0: // Event definitions that one can register for michael@0: // State has changed michael@0: sigslot::signal2 SignalStateChange; michael@0: // Data received on the flow michael@0: sigslot::signal3 michael@0: SignalPacketReceived; michael@0: michael@0: // Return the layer id for this layer michael@0: virtual const std::string id() = 0; michael@0: michael@0: // The id of the flow michael@0: const std::string& flow_id() { michael@0: return flow_id_; michael@0: } michael@0: michael@0: protected: michael@0: virtual void WasInserted() {} michael@0: virtual void SetState(State state, const char *file, unsigned line); michael@0: // Check if we are on the right thread michael@0: void CheckThread() { michael@0: NS_ABORT_IF_FALSE(CheckThreadInt(), "Wrong thread"); michael@0: } michael@0: michael@0: Mode mode_; michael@0: State state_; michael@0: std::string flow_id_; michael@0: TransportLayer *downward_; // The next layer in the stack michael@0: nsCOMPtr target_; michael@0: michael@0: private: michael@0: DISALLOW_COPY_ASSIGN(TransportLayer); michael@0: michael@0: bool CheckThreadInt() { michael@0: bool on; michael@0: michael@0: if (!target_) // OK if no thread set. michael@0: return true; michael@0: michael@0: NS_ENSURE_SUCCESS(target_->IsOnCurrentThread(&on), false); michael@0: NS_ENSURE_TRUE(on, false); michael@0: michael@0: return true; michael@0: } michael@0: }; michael@0: michael@0: #define LAYER_INFO "Flow[" << flow_id() << "(none)" << "]; Layer[" << id() << "]: " michael@0: #define TL_SET_STATE(x) SetState((x), __FILE__, __LINE__) michael@0: michael@0: } // close namespace michael@0: #endif