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: #include "logging.h" michael@0: #include "nspr.h" michael@0: #include "prlock.h" michael@0: michael@0: #include "nsNetCID.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsIEventTarget.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsISocketTransportService.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: #include "transportflow.h" michael@0: #include "transportlayerloopback.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: MOZ_MTLOG_MODULE("mtransport") michael@0: michael@0: nsresult TransportLayerLoopback::Init() { michael@0: timer_ = do_CreateInstance(NS_TIMER_CONTRACTID); michael@0: MOZ_ASSERT(timer_); michael@0: if (!timer_) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsresult rv; michael@0: target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); michael@0: MOZ_ASSERT(NS_SUCCEEDED(rv)); michael@0: if (!NS_SUCCEEDED(rv)) michael@0: return rv; michael@0: michael@0: timer_->SetTarget(target_); michael@0: michael@0: packets_lock_ = PR_NewLock(); michael@0: MOZ_ASSERT(packets_lock_); michael@0: if (!packets_lock_) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: deliverer_ = new Deliverer(this); michael@0: michael@0: timer_->InitWithCallback(deliverer_, 100, nsITimer::TYPE_REPEATING_SLACK); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Connect to the other side michael@0: void TransportLayerLoopback::Connect(TransportLayerLoopback* peer) { michael@0: peer_ = peer; michael@0: michael@0: TL_SET_STATE(TS_OPEN); michael@0: } michael@0: michael@0: TransportResult michael@0: TransportLayerLoopback::SendPacket(const unsigned char *data, size_t len) { michael@0: MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "SendPacket(" << len << ")"); michael@0: michael@0: if (!peer_) { michael@0: MOZ_MTLOG(ML_ERROR, "Discarding packet because peer not attached"); michael@0: return TE_ERROR; michael@0: } michael@0: michael@0: nsresult res = peer_->QueuePacket(data, len); michael@0: if (!NS_SUCCEEDED(res)) michael@0: return TE_ERROR; michael@0: michael@0: return static_cast(len); michael@0: } michael@0: michael@0: nsresult TransportLayerLoopback::QueuePacket(const unsigned char *data, michael@0: size_t len) { michael@0: MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Enqueuing packet of length " << len); michael@0: MOZ_ASSERT(packets_lock_); michael@0: michael@0: PR_Lock(packets_lock_); michael@0: michael@0: packets_.push(new QueuedPacket()); michael@0: packets_.back()->Assign(data, len); michael@0: michael@0: PRStatus r = PR_Unlock(packets_lock_); michael@0: MOZ_ASSERT(r == PR_SUCCESS); michael@0: if (r != PR_SUCCESS) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: void TransportLayerLoopback::DeliverPackets() { michael@0: while (!packets_.empty()) { michael@0: QueuedPacket *packet = packets_.front(); michael@0: packets_.pop(); michael@0: michael@0: MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Delivering packet of length " << michael@0: packet->len()); michael@0: SignalPacketReceived(this, packet->data(), packet->len()); michael@0: michael@0: delete packet; michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(TransportLayerLoopback::Deliverer, nsITimerCallback) michael@0: michael@0: NS_IMETHODIMP TransportLayerLoopback::Deliverer::Notify(nsITimer *timer) { michael@0: if (!layer_) michael@0: return NS_OK; michael@0: michael@0: layer_->DeliverPackets(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: } // close namespace