mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1069230 - Presentation API implementation. Part 8 - Data transport channel. r=jdm
This commit is contained in:
parent
905d6d07e3
commit
1efa4382a3
@ -11,15 +11,119 @@
|
|||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "nsIDocShell.h"
|
#include "nsIDocShell.h"
|
||||||
#include "nsIFrameLoader.h"
|
#include "nsIFrameLoader.h"
|
||||||
|
#include "nsIMutableArray.h"
|
||||||
|
#include "nsINetAddr.h"
|
||||||
|
#include "nsISocketTransport.h"
|
||||||
|
#include "nsISupportsPrimitives.h"
|
||||||
|
#include "nsNetCID.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "PresentationService.h"
|
#include "PresentationService.h"
|
||||||
#include "PresentationSessionInfo.h"
|
#include "PresentationSessionInfo.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_GONK
|
||||||
|
#include "nsINetworkInterface.h"
|
||||||
|
#include "nsINetworkManager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using namespace mozilla::services;
|
using namespace mozilla::services;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of PresentationChannelDescription
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
class PresentationChannelDescription final : public nsIPresentationChannelDescription
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIPRESENTATIONCHANNELDESCRIPTION
|
||||||
|
|
||||||
|
PresentationChannelDescription(nsACString& aAddress,
|
||||||
|
uint16_t aPort)
|
||||||
|
: mAddress(aAddress)
|
||||||
|
, mPort(aPort)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~PresentationChannelDescription() {}
|
||||||
|
|
||||||
|
nsCString mAddress;
|
||||||
|
uint16_t mPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(PresentationChannelDescription, nsIPresentationChannelDescription)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationChannelDescription::GetType(uint8_t* aRetVal)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(!aRetVal)) {
|
||||||
|
return NS_ERROR_INVALID_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// Only support TCP socket for now.
|
||||||
|
*aRetVal = nsIPresentationChannelDescription::TYPE_TCP;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(!aRetVal)) {
|
||||||
|
return NS_ERROR_INVALID_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!array)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// Ultimately we may use all the available addresses. DataChannel appears
|
||||||
|
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||||
|
// only exposed on Firefox OS where the first IP appears enough for most
|
||||||
|
// scenarios.
|
||||||
|
nsCOMPtr<nsISupportsCString> address = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!address)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
address->SetData(mAddress);
|
||||||
|
|
||||||
|
array->AppendElement(address, false);
|
||||||
|
array.forget(aRetVal);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(!aRetVal)) {
|
||||||
|
return NS_ERROR_INVALID_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aRetVal = mPort;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
|
||||||
|
{
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// Only support TCP socket for now.
|
||||||
|
aDataChannelSDP.Truncate();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation of PresentationSessionInfo
|
* Implementation of PresentationSessionInfo
|
||||||
*/
|
*/
|
||||||
@ -231,8 +335,42 @@ PresentationRequesterInfo::Init(nsIPresentationControlChannel* aControlChannel)
|
|||||||
{
|
{
|
||||||
PresentationSessionInfo::Init(aControlChannel);
|
PresentationSessionInfo::Init(aControlChannel);
|
||||||
|
|
||||||
// TODO Initialize |mServerSocket|, use |this| as the listener, and prepare to
|
// Initialize |mServerSocket| for bootstrapping the data transport channel and
|
||||||
// send offer.
|
// use |this| as the listener.
|
||||||
|
mServerSocket = do_CreateInstance(NS_SERVERSOCKET_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!mServerSocket)) {
|
||||||
|
return ReplyError(NS_ERROR_NOT_AVAILABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = mServerSocket->Init(-1, false, -1);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mServerSocket->AsyncListen(this);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare and send the offer.
|
||||||
|
int32_t port;
|
||||||
|
rv = mServerSocket->GetPort(&port);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString address;
|
||||||
|
rv = GetAddress(address);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<PresentationChannelDescription> description =
|
||||||
|
new PresentationChannelDescription(address, static_cast<uint16_t>(port));
|
||||||
|
rv = mControlChannel->SendOffer(description);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -249,6 +387,51 @@ PresentationRequesterInfo::Shutdown(nsresult aReason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PresentationRequesterInfo::GetAddress(nsACString& aAddress)
|
||||||
|
{
|
||||||
|
#ifdef MOZ_WIDGET_GONK
|
||||||
|
nsCOMPtr<nsINetworkManager> networkManager =
|
||||||
|
do_GetService("@mozilla.org/network/manager;1");
|
||||||
|
if (NS_WARN_IF(!networkManager)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsINetworkInfo> activeNetworkInfo;
|
||||||
|
networkManager->GetActiveNetworkInfo(getter_AddRefs(activeNetworkInfo));
|
||||||
|
if (NS_WARN_IF(!activeNetworkInfo)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
char16_t** ips = nullptr;
|
||||||
|
uint32_t* prefixes = nullptr;
|
||||||
|
uint32_t count = 0;
|
||||||
|
activeNetworkInfo->GetAddresses(&ips, &prefixes, &count);
|
||||||
|
if (NS_WARN_IF(!count)) {
|
||||||
|
NS_Free(prefixes);
|
||||||
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, ips);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// Ultimately we may use all the available addresses. DataChannel appears
|
||||||
|
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||||
|
// only exposed on Firefox OS where the first IP appears enough for most
|
||||||
|
// scenarios.
|
||||||
|
nsAutoString ip;
|
||||||
|
ip.Assign(ips[0]);
|
||||||
|
aAddress = NS_ConvertUTF16toUTF8(ip);
|
||||||
|
|
||||||
|
NS_Free(prefixes);
|
||||||
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, ips);
|
||||||
|
#else
|
||||||
|
// TODO Get host IP via other platforms.
|
||||||
|
aAddress.Truncate();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// nsIPresentationControlChannelListener
|
// nsIPresentationControlChannelListener
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
PresentationRequesterInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
|
PresentationRequesterInfo::OnOffer(nsIPresentationChannelDescription* aDescription)
|
||||||
@ -425,7 +608,29 @@ PresentationResponderInfo::InitTransportAndSendAnswer()
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Prepare and send the answer.
|
// Prepare and send the answer.
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// In the current implementation of |PresentationSessionTransport|,
|
||||||
|
// |GetSelfAddress| cannot return the real info when it's initialized via
|
||||||
|
// |InitWithChannelDescription|. Yet this deficiency only affects the channel
|
||||||
|
// description for the answer, which is not actually checked at requester side.
|
||||||
|
nsCOMPtr<nsINetAddr> selfAddr;
|
||||||
|
rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString address;
|
||||||
|
selfAddr->GetAddress(address);
|
||||||
|
uint16_t port;
|
||||||
|
selfAddr->GetPort(&port);
|
||||||
|
nsCOMPtr<nsIPresentationChannelDescription> description =
|
||||||
|
new PresentationChannelDescription(address, port);
|
||||||
|
|
||||||
|
rv = mControlChannel->SendAnswer(description);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,8 @@ private:
|
|||||||
|
|
||||||
void Shutdown(nsresult aReason) override;
|
void Shutdown(nsresult aReason) override;
|
||||||
|
|
||||||
|
nsresult GetAddress(nsACString& aAddress);
|
||||||
|
|
||||||
nsCOMPtr<nsIServerSocket> mServerSocket;
|
nsCOMPtr<nsIServerSocket> mServerSocket;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
484
dom/presentation/PresentationSessionTransport.cpp
Normal file
484
dom/presentation/PresentationSessionTransport.cpp
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsArrayUtils.h"
|
||||||
|
#include "nsIAsyncStreamCopier.h"
|
||||||
|
#include "nsIInputStreamPump.h"
|
||||||
|
#include "nsIMultiplexInputStream.h"
|
||||||
|
#include "nsIMutableArray.h"
|
||||||
|
#include "nsIOutputStream.h"
|
||||||
|
#include "nsIPresentationControlChannel.h"
|
||||||
|
#include "nsIScriptableInputStream.h"
|
||||||
|
#include "nsISocketTransport.h"
|
||||||
|
#include "nsISocketTransportService.h"
|
||||||
|
#include "nsISupportsPrimitives.h"
|
||||||
|
#include "nsNetUtil.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "nsStreamUtils.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
#include "PresentationSessionTransport.h"
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 65536
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::dom;
|
||||||
|
|
||||||
|
class CopierCallbacks final : public nsIRequestObserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CopierCallbacks(PresentationSessionTransport* aTransport)
|
||||||
|
: mOwner(aTransport)
|
||||||
|
{}
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIREQUESTOBSERVER
|
||||||
|
private:
|
||||||
|
~CopierCallbacks() {}
|
||||||
|
|
||||||
|
nsRefPtr<PresentationSessionTransport> mOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(CopierCallbacks, nsIRequestObserver)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
CopierCallbacks::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
CopierCallbacks::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
|
||||||
|
{
|
||||||
|
mOwner->NotifyCopyComplete(aStatus);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(PresentationSessionTransport,
|
||||||
|
nsIPresentationSessionTransport,
|
||||||
|
nsITransportEventSink,
|
||||||
|
nsIInputStreamCallback,
|
||||||
|
nsIStreamListener,
|
||||||
|
nsIRequestObserver)
|
||||||
|
|
||||||
|
PresentationSessionTransport::PresentationSessionTransport()
|
||||||
|
: mReadyState(CLOSED)
|
||||||
|
, mAsyncCopierActive(false)
|
||||||
|
, mCloseStatus(NS_OK)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PresentationSessionTransport::~PresentationSessionTransport()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::InitWithSocketTransport(nsISocketTransport* aTransport,
|
||||||
|
nsIPresentationSessionTransportCallback* aCallback)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(!aCallback)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
mCallback = aCallback;
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!aTransport)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
mTransport = aTransport;
|
||||||
|
|
||||||
|
nsresult rv = CreateStream();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetReadyState(OPEN);
|
||||||
|
|
||||||
|
rv = CreateInputStreamPump();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::InitWithChannelDescription(nsIPresentationChannelDescription* aDescription,
|
||||||
|
nsIPresentationSessionTransportCallback* aCallback)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(!aCallback)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
mCallback = aCallback;
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!aDescription)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t serverPort;
|
||||||
|
nsresult rv = aDescription->GetTcpPort(&serverPort);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIArray> serverHosts;
|
||||||
|
rv = aDescription->GetTcpAddress(getter_AddRefs(serverHosts));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
// Ultimately we may use all the available addresses. DataChannel appears
|
||||||
|
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||||
|
// only exposed on Firefox OS where the first IP appears enough for most
|
||||||
|
// scenarios.
|
||||||
|
nsCOMPtr<nsISupportsCString> supportStr = do_QueryElementAt(serverHosts, 0);
|
||||||
|
if (NS_WARN_IF(!supportStr)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoCString serverHost;
|
||||||
|
supportStr->GetData(serverHost);
|
||||||
|
if (serverHost.IsEmpty()) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetReadyState(CONNECTING);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISocketTransportService> sts =
|
||||||
|
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!sts)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
rv = sts->CreateTransport(nullptr, 0, serverHost, serverPort, nullptr,
|
||||||
|
getter_AddRefs(mTransport));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIThread> mainThread;
|
||||||
|
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||||
|
|
||||||
|
mTransport->SetEventSink(this, mainThread);
|
||||||
|
|
||||||
|
rv = CreateStream();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PresentationSessionTransport::CreateStream()
|
||||||
|
{
|
||||||
|
nsresult rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(mSocketInputStream));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv = mTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, getter_AddRefs(mSocketOutputStream));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the other side is not listening, we will get an |onInputStreamReady|
|
||||||
|
// callback where |available| raises to indicate the connection was refused.
|
||||||
|
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mSocketInputStream);
|
||||||
|
if (NS_WARN_IF(!asyncStream)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIThread> mainThread;
|
||||||
|
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||||
|
|
||||||
|
rv = asyncStream->AsyncWait(this, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, 0, mainThread);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mInputStreamScriptable = do_CreateInstance("@mozilla.org/scriptableinputstream;1", &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv = mInputStreamScriptable->Init(mSocketInputStream);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMultiplexStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMultiplexStreamCopier = do_CreateInstance("@mozilla.org/network/async-stream-copier;1", &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISocketTransportService> sts =
|
||||||
|
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
|
||||||
|
if (NS_WARN_IF(!sts)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIEventTarget> target = do_QueryInterface(sts);
|
||||||
|
rv = mMultiplexStreamCopier->Init(mMultiplexStream,
|
||||||
|
mSocketOutputStream,
|
||||||
|
target,
|
||||||
|
true, /* source buffered */
|
||||||
|
false, /* sink buffered */
|
||||||
|
BUFFER_SIZE,
|
||||||
|
false, /* close source */
|
||||||
|
false); /* close sink */
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PresentationSessionTransport::CreateInputStreamPump()
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
mInputStreamPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mInputStreamPump->AsyncRead(this, nullptr);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::GetCallback(nsIPresentationSessionTransportCallback** aCallback)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIPresentationSessionTransportCallback> callback = mCallback;
|
||||||
|
callback.forget(aCallback);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::SetCallback(nsIPresentationSessionTransportCallback* aCallback)
|
||||||
|
{
|
||||||
|
mCallback = aCallback;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::GetSelfAddress(nsINetAddr** aSelfAddress)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(mReadyState != OPEN)) {
|
||||||
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mTransport->GetScriptableSelfAddr(aSelfAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PresentationSessionTransport::EnsureCopying()
|
||||||
|
{
|
||||||
|
if (mAsyncCopierActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAsyncCopierActive = true;
|
||||||
|
nsRefPtr<CopierCallbacks> callbacks = new CopierCallbacks(this);
|
||||||
|
NS_WARN_IF(NS_FAILED(mMultiplexStreamCopier->AsyncCopy(callbacks, nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PresentationSessionTransport::NotifyCopyComplete(nsresult aStatus)
|
||||||
|
{
|
||||||
|
mAsyncCopierActive = false;
|
||||||
|
mMultiplexStream->RemoveStream(0);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(aStatus))) {
|
||||||
|
if (mReadyState != CLOSED) {
|
||||||
|
mCloseStatus = aStatus;
|
||||||
|
SetReadyState(CLOSED);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
nsresult rv = mMultiplexStream->GetCount(&count);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
EnsureCopying();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mReadyState == CLOSING) {
|
||||||
|
mSocketOutputStream->Close();
|
||||||
|
mCloseStatus = NS_OK;
|
||||||
|
SetReadyState(CLOSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::Send(nsIInputStream* aData)
|
||||||
|
{
|
||||||
|
if (NS_WARN_IF(mReadyState != OPEN)) {
|
||||||
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMultiplexStream->AppendStream(aData);
|
||||||
|
|
||||||
|
EnsureCopying();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::Close(nsresult aReason)
|
||||||
|
{
|
||||||
|
if (mReadyState == CLOSED || mReadyState == CLOSING) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCloseStatus = aReason;
|
||||||
|
SetReadyState(CLOSING);
|
||||||
|
|
||||||
|
uint32_t count = 0;
|
||||||
|
mMultiplexStream->GetCount(&count);
|
||||||
|
if (!count) {
|
||||||
|
mSocketOutputStream->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
mSocketInputStream->Close();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PresentationSessionTransport::SetReadyState(ReadyState aReadyState)
|
||||||
|
{
|
||||||
|
mReadyState = aReadyState;
|
||||||
|
|
||||||
|
if (mReadyState == OPEN && mCallback) {
|
||||||
|
// Notify the transport channel is ready.
|
||||||
|
NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportReady()));
|
||||||
|
} else if (mReadyState == CLOSED && mCallback) {
|
||||||
|
// Notify the transport channel has been shut down.
|
||||||
|
NS_WARN_IF(NS_FAILED(mCallback->NotifyTransportClosed(mCloseStatus)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsITransportEventSink
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::OnTransportStatus(nsITransport* aTransport,
|
||||||
|
nsresult aStatus,
|
||||||
|
int64_t aProgress,
|
||||||
|
int64_t aProgressMax)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (aStatus != NS_NET_STATUS_CONNECTED_TO) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetReadyState(OPEN);
|
||||||
|
|
||||||
|
nsresult rv = CreateInputStreamPump();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsIInputStreamCallback
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
// Only used for detecting if the connection was refused.
|
||||||
|
uint64_t dummy;
|
||||||
|
nsresult rv = aStream->Available(&dummy);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
if (mReadyState != CLOSED) {
|
||||||
|
mCloseStatus = NS_ERROR_CONNECTION_REFUSED;
|
||||||
|
SetReadyState(CLOSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsIRequestObserver
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::OnStartRequest(nsIRequest* aRequest,
|
||||||
|
nsISupports* aContext)
|
||||||
|
{
|
||||||
|
// Do nothing.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::OnStopRequest(nsIRequest* aRequest,
|
||||||
|
nsISupports* aContext,
|
||||||
|
nsresult aStatusCode)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
nsresult rv = mMultiplexStream->GetCount(&count);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mInputStreamPump = nullptr;
|
||||||
|
|
||||||
|
if (count != 0 && NS_SUCCEEDED(aStatusCode)) {
|
||||||
|
// If we have some buffered output still, and status is not an error, the
|
||||||
|
// other side has done a half-close, but we don't want to be in the close
|
||||||
|
// state until we are done sending everything that was buffered. We also
|
||||||
|
// don't want to call |NotifyTransportClosed| yet.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We call this even if there is no error.
|
||||||
|
if (mReadyState != CLOSED) {
|
||||||
|
mCloseStatus = aStatusCode;
|
||||||
|
SetReadyState(CLOSED);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsIStreamListener
|
||||||
|
NS_IMETHODIMP
|
||||||
|
PresentationSessionTransport::OnDataAvailable(nsIRequest* aRequest,
|
||||||
|
nsISupports* aContext,
|
||||||
|
nsIInputStream* aStream,
|
||||||
|
uint64_t aOffset,
|
||||||
|
uint32_t aCount)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!mCallback)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString data;
|
||||||
|
nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the incoming data to the listener.
|
||||||
|
return mCallback->NotifyData(data);
|
||||||
|
}
|
99
dom/presentation/PresentationSessionTransport.h
Normal file
99
dom/presentation/PresentationSessionTransport.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_dom_PresentationSessionTransport_h
|
||||||
|
#define mozilla_dom_PresentationSessionTransport_h
|
||||||
|
|
||||||
|
#include "mozilla/nsRefPtr.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsIAsyncInputStream.h"
|
||||||
|
#include "nsIPresentationSessionTransport.h"
|
||||||
|
#include "nsIStreamListener.h"
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
#include "nsITransport.h"
|
||||||
|
|
||||||
|
class nsISocketTransport;
|
||||||
|
class nsIInputStreamPump;
|
||||||
|
class nsIScriptableInputStream;
|
||||||
|
class nsIMultiplexInputStream;
|
||||||
|
class nsIAsyncStreamCopier;
|
||||||
|
class nsIInputStream;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* App-to-App transport channel for the presentation session. It's usually
|
||||||
|
* initialized with an |InitWithSocketTransport| call if at the presenting sender
|
||||||
|
* side; whereas it's initialized with an |InitWithChannelDescription| if at the
|
||||||
|
* presenting receiver side. The lifetime is managed in either
|
||||||
|
* |PresentationRequesterInfo| (sender side) or |PresentationResponderInfo|
|
||||||
|
* (receiver side) in PresentationSessionInfo.cpp.
|
||||||
|
*
|
||||||
|
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||||
|
* The implementation over the TCP channel is primarily used for the early stage
|
||||||
|
* of Presentation API (without SSL) and should be migrated to DataChannel with
|
||||||
|
* full support soon.
|
||||||
|
*/
|
||||||
|
class PresentationSessionTransport final : public nsIPresentationSessionTransport
|
||||||
|
, public nsITransportEventSink
|
||||||
|
, public nsIInputStreamCallback
|
||||||
|
, public nsIStreamListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSIPRESENTATIONSESSIONTRANSPORT
|
||||||
|
NS_DECL_NSITRANSPORTEVENTSINK
|
||||||
|
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||||
|
NS_DECL_NSIREQUESTOBSERVER
|
||||||
|
NS_DECL_NSISTREAMLISTENER
|
||||||
|
|
||||||
|
PresentationSessionTransport();
|
||||||
|
|
||||||
|
void NotifyCopyComplete(nsresult aStatus);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~PresentationSessionTransport();
|
||||||
|
|
||||||
|
nsresult CreateStream();
|
||||||
|
|
||||||
|
nsresult CreateInputStreamPump();
|
||||||
|
|
||||||
|
void EnsureCopying();
|
||||||
|
|
||||||
|
enum ReadyState {
|
||||||
|
CONNECTING,
|
||||||
|
OPEN,
|
||||||
|
CLOSING,
|
||||||
|
CLOSED
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetReadyState(ReadyState aReadyState);
|
||||||
|
|
||||||
|
ReadyState mReadyState;
|
||||||
|
bool mAsyncCopierActive;
|
||||||
|
nsresult mCloseStatus;
|
||||||
|
|
||||||
|
// Raw socket streams
|
||||||
|
nsCOMPtr<nsISocketTransport> mTransport;
|
||||||
|
nsCOMPtr<nsIInputStream> mSocketInputStream;
|
||||||
|
nsCOMPtr<nsIOutputStream> mSocketOutputStream;
|
||||||
|
|
||||||
|
// Input stream machinery
|
||||||
|
nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
|
||||||
|
nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
|
||||||
|
|
||||||
|
// Output stream machinery
|
||||||
|
nsCOMPtr<nsIMultiplexInputStream> mMultiplexStream;
|
||||||
|
nsCOMPtr<nsIAsyncStreamCopier> mMultiplexStreamCopier;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPresentationSessionTransportCallback> mCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dom
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_dom_PresentationSessionTransport_h
|
@ -10,9 +10,6 @@ interface nsIPresentationChannelDescription;
|
|||||||
interface nsISocketTransport;
|
interface nsISocketTransport;
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
#define PRESENTATION_SESSION_TRANSPORT_CID \
|
|
||||||
{ 0xc9d023f4, 0x6228, 0x4c07, \
|
|
||||||
{ 0x8b, 0x1d, 0x9c, 0x19, 0x57, 0x3f, 0xaa, 0x27 } }
|
|
||||||
#define PRESENTATION_SESSION_TRANSPORT_CONTRACTID \
|
#define PRESENTATION_SESSION_TRANSPORT_CONTRACTID \
|
||||||
"@mozilla.org/presentation/presentationsessiontransport;1"
|
"@mozilla.org/presentation/presentationsessiontransport;1"
|
||||||
%}
|
%}
|
||||||
|
@ -19,6 +19,7 @@ EXPORTS.mozilla.dom += [
|
|||||||
'PresentationService.h',
|
'PresentationService.h',
|
||||||
'PresentationSession.h',
|
'PresentationSession.h',
|
||||||
'PresentationSessionInfo.h',
|
'PresentationSessionInfo.h',
|
||||||
|
'PresentationSessionTransport.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
@ -32,6 +33,7 @@ UNIFIED_SOURCES += [
|
|||||||
'PresentationSession.cpp',
|
'PresentationSession.cpp',
|
||||||
'PresentationSessionInfo.cpp',
|
'PresentationSessionInfo.cpp',
|
||||||
'PresentationSessionRequest.cpp',
|
'PresentationSessionRequest.cpp',
|
||||||
|
'PresentationSessionTransport.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
EXTRA_COMPONENTS += [
|
EXTRA_COMPONENTS += [
|
||||||
|
@ -0,0 +1,171 @@
|
|||||||
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
|
||||||
|
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||||
|
"nsIServerSocket",
|
||||||
|
"init");
|
||||||
|
|
||||||
|
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||||
|
Cu.import('resource://gre/modules/Services.jsm');
|
||||||
|
|
||||||
|
var testServer = null;
|
||||||
|
var clientTransport = null;
|
||||||
|
var serverTransport = null;
|
||||||
|
|
||||||
|
const clientMessage = "Client Message";
|
||||||
|
const serverMessage = "Server Message";
|
||||||
|
|
||||||
|
const address = Cc["@mozilla.org/supports-cstring;1"]
|
||||||
|
.createInstance(Ci.nsISupportsCString);
|
||||||
|
address.data = "127.0.0.1";
|
||||||
|
const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||||
|
addresses.appendElement(address, false);
|
||||||
|
|
||||||
|
const serverChannelDescription = {
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
|
||||||
|
type: 1,
|
||||||
|
tcpAddress: addresses,
|
||||||
|
};
|
||||||
|
|
||||||
|
var isClientReady = false;
|
||||||
|
var isServerReady = false;
|
||||||
|
var isClientClosed = false;
|
||||||
|
var isServerClosed = false;
|
||||||
|
|
||||||
|
const clientCallback = {
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
|
||||||
|
notifyTransportReady: function () {
|
||||||
|
Assert.ok(true, "Client transport ready.");
|
||||||
|
|
||||||
|
isClientReady = true;
|
||||||
|
if (isClientReady && isServerReady) {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notifyTransportClosed: function (aReason) {
|
||||||
|
Assert.ok(true, "Client transport is closed.");
|
||||||
|
|
||||||
|
isClientClosed = true;
|
||||||
|
if (isClientClosed && isServerClosed) {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notifyData: function(aData) {
|
||||||
|
Assert.equal(aData, serverMessage, "Client transport receives data.");
|
||||||
|
run_next_test();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const serverCallback = {
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
|
||||||
|
notifyTransportReady: function () {
|
||||||
|
Assert.ok(true, "Server transport ready.");
|
||||||
|
|
||||||
|
isServerReady = true;
|
||||||
|
if (isClientReady && isServerReady) {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notifyTransportClosed: function (aReason) {
|
||||||
|
Assert.ok(true, "Server transport is closed.");
|
||||||
|
|
||||||
|
isServerClosed = true;
|
||||||
|
if (isClientClosed && isServerClosed) {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notifyData: function(aData) {
|
||||||
|
Assert.equal(aData, clientMessage, "Server transport receives data.");
|
||||||
|
run_next_test();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function TestServer() {
|
||||||
|
this.serverSocket = ServerSocket(-1, true, -1);
|
||||||
|
this.serverSocket.asyncListen(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
TestServer.prototype = {
|
||||||
|
onSocketAccepted: function(aSocket, aTransport) {
|
||||||
|
print("Test server gets a client connection.");
|
||||||
|
serverTransport = Cc["@mozilla.org/presentation/presentationsessiontransport;1"]
|
||||||
|
.createInstance(Ci.nsIPresentationSessionTransport);
|
||||||
|
serverTransport.initWithSocketTransport(aTransport, serverCallback);
|
||||||
|
},
|
||||||
|
onStopListening: function(aSocket) {
|
||||||
|
print("Test server stops listening.");
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
if (this.serverSocket) {
|
||||||
|
this.serverSocket.close();
|
||||||
|
this.serverSocket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the transport connection and ensure |notifyTransportReady| triggered
|
||||||
|
// at both sides.
|
||||||
|
function setup() {
|
||||||
|
clientTransport = Cc["@mozilla.org/presentation/presentationsessiontransport;1"]
|
||||||
|
.createInstance(Ci.nsIPresentationSessionTransport);
|
||||||
|
clientTransport.initWithChannelDescription(serverChannelDescription, clientCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test |selfAddress| attribute of |nsIPresentationSessionTransport|.
|
||||||
|
function selfAddress() {
|
||||||
|
var serverSelfAddress = serverTransport.selfAddress;
|
||||||
|
Assert.equal(serverSelfAddress.address, address.data, "The self address of server transport should be set.");
|
||||||
|
Assert.equal(serverSelfAddress.port, testServer.serverSocket.port, "The port of server transport should be set.");
|
||||||
|
|
||||||
|
var clientSelfAddress = clientTransport.selfAddress;
|
||||||
|
Assert.ok(clientSelfAddress.address, "The self address of client transport should be set.");
|
||||||
|
Assert.ok(clientSelfAddress.port, "The port of client transport should be set.");
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the client sends a message and then a corresponding notification gets
|
||||||
|
// triggered at the server side.
|
||||||
|
function clientSendMessage() {
|
||||||
|
var stream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||||
|
.createInstance(Ci.nsIStringInputStream);
|
||||||
|
stream.setData(clientMessage, clientMessage.length);
|
||||||
|
clientTransport.send(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the server sends a message an then a corresponding notification gets
|
||||||
|
// triggered at the client side.
|
||||||
|
function serverSendMessage() {
|
||||||
|
var stream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||||
|
.createInstance(Ci.nsIStringInputStream);
|
||||||
|
stream.setData(serverMessage, serverMessage.length);
|
||||||
|
serverTransport.send(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transportClose() {
|
||||||
|
clientTransport.close(Cr.NS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shutdown() {
|
||||||
|
testServer.close();
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_test(setup);
|
||||||
|
add_test(selfAddress);
|
||||||
|
add_test(clientSendMessage);
|
||||||
|
add_test(serverSendMessage);
|
||||||
|
add_test(transportClose);
|
||||||
|
add_test(shutdown);
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
testServer = new TestServer();
|
||||||
|
// Get the port of the test server.
|
||||||
|
serverChannelDescription.tcpPort = testServer.serverSocket.port;
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
}
|
@ -4,4 +4,5 @@ tail =
|
|||||||
|
|
||||||
[test_multicast_dns_device_provider.js]
|
[test_multicast_dns_device_provider.js]
|
||||||
[test_presentation_device_manager.js]
|
[test_presentation_device_manager.js]
|
||||||
|
[test_presentation_session_transport.js]
|
||||||
[test_tcp_control_channel.js]
|
[test_tcp_control_channel.js]
|
||||||
|
@ -262,6 +262,7 @@ static void Shutdown();
|
|||||||
#include "GMPService.h"
|
#include "GMPService.h"
|
||||||
|
|
||||||
#include "mozilla/dom/PresentationDeviceManager.h"
|
#include "mozilla/dom/PresentationDeviceManager.h"
|
||||||
|
#include "mozilla/dom/PresentationSessionTransport.h"
|
||||||
|
|
||||||
#include "mozilla/TextInputProcessor.h"
|
#include "mozilla/TextInputProcessor.h"
|
||||||
|
|
||||||
@ -294,6 +295,9 @@ using mozilla::gmp::GeckoMediaPluginService;
|
|||||||
#define PRESENTATION_DEVICE_MANAGER_CID \
|
#define PRESENTATION_DEVICE_MANAGER_CID \
|
||||||
{ 0xe1e79dec, 0x4085, 0x4994, { 0xac, 0x5b, 0x74, 0x4b, 0x01, 0x66, 0x97, 0xe6 } }
|
{ 0xe1e79dec, 0x4085, 0x4994, { 0xac, 0x5b, 0x74, 0x4b, 0x01, 0x66, 0x97, 0xe6 } }
|
||||||
|
|
||||||
|
#define PRESENTATION_SESSION_TRANSPORT_CID \
|
||||||
|
{ 0xc9d023f4, 0x6228, 0x4c07, { 0x8b, 0x1d, 0x9c, 0x19, 0x57, 0x3f, 0xaa, 0x27 } }
|
||||||
|
|
||||||
already_AddRefed<nsIPresentationService> NS_CreatePresentationService();
|
already_AddRefed<nsIPresentationService> NS_CreatePresentationService();
|
||||||
|
|
||||||
// Factory Constructor
|
// Factory Constructor
|
||||||
@ -406,6 +410,7 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(FakeInputPortService,
|
|||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(InputPortData)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(InputPortData)
|
||||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPresentationService,
|
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPresentationService,
|
||||||
NS_CreatePresentationService)
|
NS_CreatePresentationService)
|
||||||
|
NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationSessionTransport)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static bool gInitialized = false;
|
static bool gInitialized = false;
|
||||||
@ -864,6 +869,7 @@ NS_DEFINE_NAMED_CID(GECKO_MEDIA_PLUGIN_SERVICE_CID);
|
|||||||
|
|
||||||
NS_DEFINE_NAMED_CID(PRESENTATION_SERVICE_CID);
|
NS_DEFINE_NAMED_CID(PRESENTATION_SERVICE_CID);
|
||||||
NS_DEFINE_NAMED_CID(PRESENTATION_DEVICE_MANAGER_CID);
|
NS_DEFINE_NAMED_CID(PRESENTATION_DEVICE_MANAGER_CID);
|
||||||
|
NS_DEFINE_NAMED_CID(PRESENTATION_SESSION_TRANSPORT_CID);
|
||||||
|
|
||||||
NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
|
NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
|
||||||
|
|
||||||
@ -1163,6 +1169,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
|||||||
{ &kTV_PROGRAM_DATA_CID, false, nullptr, TVProgramDataConstructor },
|
{ &kTV_PROGRAM_DATA_CID, false, nullptr, TVProgramDataConstructor },
|
||||||
{ &kPRESENTATION_SERVICE_CID, false, nullptr, nsIPresentationServiceConstructor },
|
{ &kPRESENTATION_SERVICE_CID, false, nullptr, nsIPresentationServiceConstructor },
|
||||||
{ &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
|
{ &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
|
||||||
|
{ &kPRESENTATION_SESSION_TRANSPORT_CID, false, nullptr, PresentationSessionTransportConstructor },
|
||||||
{ &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor },
|
{ &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor },
|
||||||
{ &kFAKE_INPUTPORT_SERVICE_CID, false, nullptr, FakeInputPortServiceConstructor },
|
{ &kFAKE_INPUTPORT_SERVICE_CID, false, nullptr, FakeInputPortServiceConstructor },
|
||||||
{ &kINPUTPORT_DATA_CID, false, nullptr, InputPortDataConstructor },
|
{ &kINPUTPORT_DATA_CID, false, nullptr, InputPortDataConstructor },
|
||||||
@ -1333,6 +1340,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
|||||||
{ NS_VOICEMAIL_SERVICE_CONTRACTID, &kNS_VOICEMAIL_SERVICE_CID },
|
{ NS_VOICEMAIL_SERVICE_CONTRACTID, &kNS_VOICEMAIL_SERVICE_CID },
|
||||||
{ PRESENTATION_SERVICE_CONTRACTID, &kPRESENTATION_SERVICE_CID },
|
{ PRESENTATION_SERVICE_CONTRACTID, &kPRESENTATION_SERVICE_CID },
|
||||||
{ PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
|
{ PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
|
||||||
|
{ PRESENTATION_SESSION_TRANSPORT_CONTRACTID, &kPRESENTATION_SESSION_TRANSPORT_CID },
|
||||||
{ "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID },
|
{ "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID },
|
||||||
{ FAKE_INPUTPORT_SERVICE_CONTRACTID, &kFAKE_INPUTPORT_SERVICE_CID },
|
{ FAKE_INPUTPORT_SERVICE_CONTRACTID, &kFAKE_INPUTPORT_SERVICE_CID },
|
||||||
{ INPUTPORT_DATA_CONTRACTID, &kINPUTPORT_DATA_CID },
|
{ INPUTPORT_DATA_CONTRACTID, &kINPUTPORT_DATA_CID },
|
||||||
|
Loading…
Reference in New Issue
Block a user