Bug 890597 - Transport layer ping diagnostic tool. r=valentin.gosu

This commit is contained in:
Robert Bindar 2013-07-31 09:16:44 -04:00
parent 027842b84f
commit 5167e2015f
6 changed files with 229 additions and 2 deletions

View File

@ -16,6 +16,7 @@ interface DummyInterface {
void funcHttpConnDict(optional HttpConnDict arg);
void funcWebSocketDict(optional WebSocketDict arg);
void funcDNSCacheDict(optional DNSCacheDict arg);
void funcConnStatusDict(optional ConnStatusDict arg);
void frameRequestCallback(FrameRequestCallback arg);
void idbObjectStoreParams(optional IDBObjectStoreParameters arg);
void CameraPictureOptions(optional CameraPictureOptions arg);

View File

@ -49,3 +49,8 @@ dictionary DNSCacheDict {
sequence<DOMString> family;
sequence<double> expiration;
};
dictionary ConnStatusDict {
DOMString status;
};

View File

@ -35,6 +35,15 @@ interface nsIDashboard : nsISupports
/* Arrays: hostname, family, hostaddr, expiration */
void requestDNSInfo(in NetDashboardCallback cb);
/* aProtocol: a transport layer protocol:
* ex: "ssl", "tcp", default is "tcp".
* aHost: the host's name
* aPort: the port which the connection will open on
* aTimeout: the timespan before the connection will be timed out */
void requestConnection(in ACString aHost, in unsigned long aPort,
in string aProtocol, in unsigned long aTimeout,
in NetDashboardCallback cb);
/* When true, the service will log websocket events */
attribute boolean enableLogging;
};

View File

@ -13,7 +13,8 @@ using mozilla::AutoSafeJSContext;
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS2(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
NS_IMPL_ISUPPORTS4(Dashboard, nsIDashboard, nsIDashboardEventNotifier,
nsITransportEventSink, nsITimerCallback)
using mozilla::dom::Sequence;
Dashboard::Dashboard()
@ -495,4 +496,169 @@ HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
protocolVersion.Assign(NS_LITERAL_STRING("spdy/3"));
}
NS_IMETHODIMP
Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
const char *aProtocol, uint32_t aTimeout,
NetDashboardCallback* cb)
{
nsresult rv;
mConn.cb = cb;
mConn.thread = NS_GetCurrentThread();
rv = TestNewConnection(aHost, aPort, aProtocol, aTimeout);
if (NS_FAILED(rv)) {
ConnStatus status;
CopyASCIItoUTF16(GetErrorString(rv), status.creationSts);
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return rv;
}
return NS_OK;
}
nsresult
Dashboard::GetConnectionStatus(ConnStatus aStatus)
{
AutoSafeJSContext cx;
mozilla::dom::ConnStatusDict dict;
dict.mStatus.Construct();
nsString &status = dict.mStatus.Value();
status = aStatus.creationSts;
JS::RootedValue val(cx);
if (!dict.ToObject(cx, JS::NullPtr(), &val)) {
mConn.cb = nullptr;
return NS_ERROR_FAILURE;
}
mConn.cb->OnDashboardDataAvailable(val);
return NS_OK;
}
nsresult
Dashboard::TestNewConnection(const nsACString& aHost, uint32_t aPort,
const char *aProtocol, uint32_t aTimeout)
{
nsresult rv;
if (!aHost.Length() || !net_IsValidHostName(aHost))
return NS_ERROR_UNKNOWN_HOST;
if (aProtocol && NS_LITERAL_STRING("ssl").EqualsASCII(aProtocol))
rv = gSocketTransportService->CreateTransport(&aProtocol, 1, aHost,
aPort, nullptr,
getter_AddRefs(mConn.socket));
else
rv = gSocketTransportService->CreateTransport(nullptr, 0, aHost,
aPort, nullptr,
getter_AddRefs(mConn.socket));
if (NS_FAILED(rv))
return rv;
rv = mConn.socket->SetEventSink(this, NS_GetCurrentThread());
if (NS_FAILED(rv))
return rv;
rv = mConn.socket->OpenInputStream(nsITransport::OPEN_BLOCKING, 0, 0,
getter_AddRefs(mConn.streamIn));
if (NS_FAILED(rv))
return rv;
StartTimer(aTimeout);
return rv;
}
NS_IMETHODIMP
Dashboard::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
uint64_t aProgress, uint64_t aProgressMax)
{
if (aStatus == NS_NET_STATUS_CONNECTED_TO)
StopTimer();
ConnStatus status;
CopyASCIItoUTF16(GetErrorString(aStatus), status.creationSts);
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
}
NS_IMETHODIMP
Dashboard::Notify(nsITimer *timer)
{
if (mConn.socket) {
mConn.socket->Close(NS_ERROR_ABORT);
mConn.socket = nullptr;
mConn.streamIn = nullptr;
}
mConn.timer = nullptr;
ConnStatus status;
status.creationSts.Assign(NS_LITERAL_STRING("NS_ERROR_NET_TIMEOUT"));
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
}
void
Dashboard::StartTimer(uint32_t aTimeout)
{
if (!mConn.timer)
mConn.timer = do_CreateInstance("@mozilla.org/timer;1");
mConn.timer->InitWithCallback(this, aTimeout * 1000, nsITimer::TYPE_ONE_SHOT);
}
void
Dashboard::StopTimer()
{
if (mConn.timer) {
mConn.timer->Cancel();
mConn.timer = nullptr;
}
}
typedef struct
{
nsresult key;
const char *error;
} ErrorEntry;
#undef ERROR
#define ERROR(key, val) {key, #key}
ErrorEntry errors[] = {
#include "ErrorList.h"
};
ErrorEntry socketTransportStatuses[] = {
ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
};
#undef ERROR
const char *
Dashboard::GetErrorString(nsresult rv)
{
int length = sizeof(socketTransportStatuses) / sizeof(ErrorEntry);
for (int i = 0;i < length;i++)
if (socketTransportStatuses[i].key == rv)
return socketTransportStatuses[i].error;
length = sizeof(errors) / sizeof(ErrorEntry);
for (int i = 0;i < length;i++)
if (errors[i].key == rv)
return errors[i].error;
return NULL;
}
} } // namespace mozilla::net

View File

@ -15,32 +15,45 @@
#include "nsSocketTransport2.h"
#include "mozilla/net/DashboardTypes.h"
#include "nsHttp.h"
#include "nsITransport.h"
#include "nsITimer.h"
namespace mozilla {
namespace net {
class Dashboard:
public nsIDashboard,
public nsIDashboardEventNotifier
public nsIDashboardEventNotifier,
public nsITransportEventSink,
public nsITimerCallback
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDASHBOARD
NS_DECL_NSIDASHBOARDEVENTNOTIFIER
NS_DECL_NSITRANSPORTEVENTSINK
NS_DECL_NSITIMERCALLBACK
Dashboard();
friend class DashConnStatusRunnable;
static const char *GetErrorString(nsresult rv);
private:
virtual ~Dashboard();
void GetSocketsDispatch();
void GetHttpDispatch();
void GetDnsInfoDispatch();
void StartTimer(uint32_t aTimeout);
void StopTimer();
nsresult TestNewConnection(const nsACString& aHost, uint32_t aPort,
const char *aProtocol, uint32_t aTimeout);
/* Helper methods that pass the JSON to the callback function. */
nsresult GetSockets();
nsresult GetHttpConnections();
nsresult GetWebSocketConnections();
nsresult GetDNSCacheEntries();
nsresult GetConnectionStatus(struct ConnStatus aStatus);
private:
struct SocketData
@ -106,13 +119,41 @@ private:
nsIThread* thread;
};
struct ConnectionData
{
nsCOMPtr<nsISocketTransport> socket;
nsCOMPtr<nsIInputStream> streamIn;
nsCOMPtr<nsITimer> timer;
nsCOMPtr<NetDashboardCallback> cb;
nsIThread* thread;
};
bool mEnableLogging;
struct SocketData mSock;
struct HttpData mHttp;
struct WebSocketData mWs;
struct DnsData mDns;
struct ConnectionData mConn;
};
class DashConnStatusRunnable: public nsRunnable
{
public:
DashConnStatusRunnable(Dashboard * aDashboard, ConnStatus aStatus)
: mDashboard(aDashboard)
{
mStatus.creationSts = aStatus.creationSts;
}
NS_IMETHODIMP Run()
{
return mDashboard->GetConnectionStatus(mStatus);
}
private:
ConnStatus mStatus;
Dashboard * mDashboard;
};
} } // namespace mozilla::net

View File

@ -57,6 +57,11 @@ struct HttpRetParams
bool ssl;
};
struct ConnStatus
{
nsString creationSts;
};
} }
#endif // mozilla_net_DashboardTypes_h_