Merge b2g-inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-06-03 15:50:54 -04:00
commit f5d8dbcd9f
67 changed files with 3824 additions and 561 deletions

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -19,8 +19,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>

View File

@ -17,8 +17,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -19,8 +19,8 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "477b5672811ed970a7476fe6f67dba546a302dce",
"git_revision": "45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "5bab67b888d1491d1718cf1a7349bcef3114cbab",
"revision": "936633804b786ab99d2afc97311dc5cedeade648",
"repo_path": "integration/gaia-central"
}

View File

@ -17,8 +17,8 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>

View File

@ -15,9 +15,9 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="477b5672811ed970a7476fe6f67dba546a302dce"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="45dc6306cf502a4f00ae9f8bd8293a8a3a37c07b"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>

View File

@ -281,6 +281,7 @@
@RESPATH@/components/necko_file.xpt
@RESPATH@/components/necko_ftp.xpt
@RESPATH@/components/necko_http.xpt
@RESPATH@/components/necko_mdns.xpt
@RESPATH@/components/necko_res.xpt
@RESPATH@/components/necko_socket.xpt
@RESPATH@/components/necko_strconv.xpt

View File

@ -286,6 +286,7 @@
@RESPATH@/components/necko_file.xpt
@RESPATH@/components/necko_ftp.xpt
@RESPATH@/components/necko_http.xpt
@RESPATH@/components/necko_mdns.xpt
@RESPATH@/components/necko_res.xpt
@RESPATH@/components/necko_socket.xpt
@RESPATH@/components/necko_strconv.xpt

View File

@ -395,6 +395,9 @@ DiskInit.h
dlfcn.h
dlgs.h
dl.h
#ifdef MOZ_WIDGET_GONK
dns_sd.h
#endif
docobj.h
dos/dosextens.h
dos.h

View File

@ -227,7 +227,7 @@ if test -n "$gonkdir" ; then
MOZ_SECUREELEMENT=1
;;
17|18)
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include -I$gonkdir/external/mdnsresponder/mDNSShared"
if test -d "$gonkdir/external/bluetooth/bluez"; then
GONK_INCLUDES="$GONK_INCLUDES -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib"
MOZ_B2G_BT=1
@ -252,7 +252,7 @@ if test -n "$gonkdir" ; then
MOZ_SECUREELEMENT=1
;;
19)
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include -I$gonkdir/external/mdnsresponder/mDNSShared"
MOZ_B2G_CAMERA=1
MOZ_B2G_BT=1
MOZ_B2G_BT_BLUEDROID=1
@ -271,7 +271,7 @@ if test -n "$gonkdir" ; then
MOZ_FMP4=1
;;
21|22)
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include -I$gonkdir/external/mdnsresponder/mDNSShared"
MOZ_AUDIO_OFFLOAD=1
MOZ_OMX_DECODER=1
MOZ_OMX_ENCODER=1

View File

@ -479,7 +479,10 @@ BluetoothGattManager::UnregisterClient(int aClientIf,
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
ClientIfComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
client->mUnregisterClientRunnable = aRunnable;
@ -580,7 +583,7 @@ BluetoothGattManager::StartLeScan(const nsTArray<nsString>& aServiceUuids,
size_t index = sClients->IndexOf(appUuidStr, 0 /* Start */, UuidComparator());
// Reject the startLeScan request if the clientIf is being used.
if (index != sClients->NoIndex) {
if (NS_WARN_IF(index != sClients->NoIndex)) {
DispatchReplyError(aRunnable,
NS_LITERAL_STRING("start LE scan failed"));
return;
@ -738,7 +741,10 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid,
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
client->mDisconnectRunnable = aRunnable;
@ -782,7 +788,10 @@ BluetoothGattManager::Discover(const nsAString& aAppUuid,
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
MOZ_ASSERT(client->mConnId > 0);
@ -851,7 +860,10 @@ BluetoothGattManager::ReadRemoteRssi(int aClientIf,
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
ClientIfComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
client->mReadRemoteRssiRunnable = aRunnable;
@ -915,7 +927,10 @@ BluetoothGattManager::RegisterNotifications(
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@ -988,7 +1003,10 @@ BluetoothGattManager::DeregisterNotifications(
ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
MOZ_ASSERT(index != sClients->NoIndex);
if (NS_WARN_IF(index == sClients->NoIndex)) {
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@ -1049,9 +1067,7 @@ BluetoothGattManager::ReadCharacteristicValue(
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
if (NS_WARN_IF(index == sClients->NoIndex)) {
// Reject the read characteristic value request
DispatchReplyError(aRunnable,
NS_LITERAL_STRING("ReadCharacteristicValue failed"));
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
@ -1131,9 +1147,7 @@ BluetoothGattManager::WriteCharacteristicValue(
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
if (NS_WARN_IF(index == sClients->NoIndex)) {
// Reject the write characteristic value request
DispatchReplyError(aRunnable,
NS_LITERAL_STRING("WriteCharacteristicValue failed"));
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
@ -1214,9 +1228,7 @@ BluetoothGattManager::ReadDescriptorValue(
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
if (NS_WARN_IF(index == sClients->NoIndex)) {
// Reject the read descriptor value request
DispatchReplyError(aRunnable,
NS_LITERAL_STRING("ReadDescriptorValue failed"));
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
@ -1297,9 +1309,7 @@ BluetoothGattManager::WriteDescriptorValue(
size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
if (NS_WARN_IF(index == sClients->NoIndex)) {
// Reject the write descriptor value request
DispatchReplyError(aRunnable,
NS_LITERAL_STRING("WriteDescriptorValue failed"));
DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
return;
}
@ -1352,7 +1362,8 @@ BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus,
UuidToString(aAppUuid, uuid);
size_t index = sClients->IndexOf(uuid, 0 /* Start */, UuidComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
BluetoothService* bs = BluetoothService::Get();
@ -1447,7 +1458,8 @@ BluetoothGattManager::ConnectNotification(int aConnId,
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
ClientIfComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
if (aStatus != GATT_STATUS_SUCCESS) {
@ -1499,7 +1511,8 @@ BluetoothGattManager::DisconnectNotification(int aConnId,
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
ClientIfComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
if (aStatus != GATT_STATUS_SUCCESS) {
@ -1545,7 +1558,7 @@ BluetoothGattManager::SearchCompleteNotification(int aConnId,
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
ConnIdComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
MOZ_ASSERT(client->mDiscoverRunnable);
@ -1582,7 +1595,7 @@ BluetoothGattManager::SearchResultNotification(
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
ConnIdComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
// Save to mServices for distributing to application and discovering
// included services, characteristics of this service later
@ -1603,7 +1616,7 @@ BluetoothGattManager::GetCharacteristicNotification(
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
ConnIdComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
MOZ_ASSERT(client->mDiscoverRunnable);
@ -1655,7 +1668,7 @@ BluetoothGattManager::GetDescriptorNotification(
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
ConnIdComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
MOZ_ASSERT(client->mDiscoverRunnable);
@ -1699,7 +1712,7 @@ BluetoothGattManager::GetIncludedServiceNotification(
size_t index = sClients->IndexOf(aConnId, 0 /* Start */,
ConnIdComparator());
MOZ_ASSERT(index != sClients->NoIndex);
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
MOZ_ASSERT(client->mDiscoverRunnable);
@ -2018,6 +2031,7 @@ BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf,
size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
ClientIfComparator());
NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
if (aStatus != GATT_STATUS_SUCCESS) { // operation failed

View File

@ -385,16 +385,20 @@ BluetoothDevice::UpdatePropertiesFromAdvData(const nsTArray<uint8_t>& aAdvData)
char uuidStr[36];
if (type == GAP_INCOMPLETE_UUID16 || type == GAP_COMPLETE_UUID16) {
// Convert 16-bits UUID into string.
sprintf(uuidStr, "0000%04x-0000-1000-8000-00805f9b34fb", uuid[0]);
} else if (type == GAP_INCOMPLETE_UUID32 || type == GAP_COMPLETE_UUID32) {
snprintf(uuidStr, sizeof(uuidStr),
"0000%04x-0000-1000-8000-00805f9b34fb", uuid[0]);
} else if (type == GAP_INCOMPLETE_UUID32 ||
type == GAP_COMPLETE_UUID32) {
// Convert 32-bits UUID into string.
sprintf(uuidStr, "%04x%04x-0000-1000-8000-00805f9b34fb",
uuid[1], uuid[0]);
} else if (type == GAP_INCOMPLETE_UUID128 || type == GAP_COMPLETE_UUID128) {
snprintf(uuidStr, sizeof(uuidStr),
"%04x%04x-0000-1000-8000-00805f9b34fb", uuid[1], uuid[0]);
} else if (type == GAP_INCOMPLETE_UUID128 ||
type == GAP_COMPLETE_UUID128) {
// Convert 128-bits UUID into string.
sprintf(uuidStr, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
uuid[7], uuid[6], uuid[5], uuid[4],
uuid[3], uuid[2], uuid[1], uuid[0]);
snprintf(uuidStr, sizeof(uuidStr),
"%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
uuid[7], uuid[6], uuid[5], uuid[4],
uuid[3], uuid[2], uuid[1], uuid[0]);
}
nsString uuidNsString;
uuidNsString.AssignLiteral(uuidStr);

View File

@ -326,6 +326,9 @@ int
GonkCameraHardware::AutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->autoFocus();
}
@ -333,6 +336,9 @@ int
GonkCameraHardware::CancelAutoFocus()
{
DOM_CAMERA_LOGI("%s\n", __func__);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->cancelAutoFocus();
}
@ -340,8 +346,11 @@ int
GonkCameraHardware::StartFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
int rv = INVALID_OPERATION;
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, CAMERA_FACE_DETECTION_HW, 0);
#endif
@ -356,8 +365,11 @@ int
GonkCameraHardware::StopFaceDetection()
{
DOM_CAMERA_LOGI("%s\n", __func__);
int rv = INVALID_OPERATION;
if (mClosing) {
return DEAD_OBJECT;
}
int rv = INVALID_OPERATION;
#if ANDROID_VERSION >= 15
rv = mCamera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0);
#endif
@ -371,6 +383,9 @@ GonkCameraHardware::StopFaceDetection()
int
GonkCameraHardware::TakePicture()
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE);
}
@ -383,6 +398,9 @@ GonkCameraHardware::CancelTakePicture()
int
GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
const String8 s = aParams.Flatten();
return mCamera->setParameters(s);
}
@ -390,6 +408,9 @@ GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
nsresult
GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return NS_ERROR_NOT_AVAILABLE;
}
const String8 s = mCamera->getParameters();
return aParams.Unflatten(s);
}
@ -398,6 +419,9 @@ GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
int
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
String8 s = aParams.flatten();
return mCamera->setParameters(s);
}
@ -405,8 +429,10 @@ GonkCameraHardware::PushParameters(const CameraParameters& aParams)
void
GonkCameraHardware::PullParameters(CameraParameters& aParams)
{
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
if (!NS_WARN_IF(mClosing)) {
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
}
}
#endif
@ -414,6 +440,9 @@ int
GonkCameraHardware::StartPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->startPreview();
}
@ -421,16 +450,20 @@ void
GonkCameraHardware::StopPreview()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
mCamera->stopPreview();
if (!mClosing) {
mCamera->stopPreview();
}
}
int
GonkCameraHardware::StartRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
int rv = OK;
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
rv = mCamera->startRecording();
int rv = mCamera->startRecording();
if (rv != OK) {
DOM_CAMERA_LOGE("mHardware->startRecording() failed with status %d", rv);
}
@ -441,6 +474,9 @@ int
GonkCameraHardware::StopRecording()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
if (mClosing) {
return DEAD_OBJECT;
}
mCamera->stopRecording();
return OK;
}
@ -456,12 +492,17 @@ GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
void
GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame)
{
mCamera->releaseRecordingFrame(aFrame);
if (!NS_WARN_IF(mClosing)) {
mCamera->releaseRecordingFrame(aFrame);
}
}
#endif
int
GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
{
if (NS_WARN_IF(mClosing)) {
return DEAD_OBJECT;
}
return mCamera->storeMetaDataInBuffers(aEnabled);
}

View File

@ -218,10 +218,9 @@ NfcContentHelper.prototype = {
});
},
notifyUserAcceptedP2P: function notifyUserAcceptedP2P(appId, tabId) {
notifyUserAcceptedP2P: function notifyUserAcceptedP2P(appId) {
cpmm.sendAsyncMessage("NFC:NotifyUserAcceptedP2P", {
appId: appId,
tabId: tabId
appId: appId
});
},

View File

@ -292,7 +292,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
message.target.sendAsyncMessage(message.name + "Response", respMsg);
},
notifyUserAcceptedP2P: function notifyUserAcceptedP2P(appId, tabId) {
notifyUserAcceptedP2P: function notifyUserAcceptedP2P(appId) {
let target = this.peerTargets[appId];
let sessionToken = SessionHelper.getCurrentP2PToken();
let isValid = (sessionToken != null) && (target != null);
@ -301,7 +301,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
return;
}
this.notifyDOMEvent(target, {tabId: tabId,
this.notifyDOMEvent(target, {tabId: this.focusApp,
event: NFC.PEER_EVENT_READY,
sessionToken: sessionToken});
},
@ -408,7 +408,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
this.checkP2PRegistration(message);
return null;
case "NFC:NotifyUserAcceptedP2P":
this.notifyUserAcceptedP2P(message.data.appId, message.data.tabId);
this.notifyUserAcceptedP2P(message.data.appId);
return null;
case "NFC:NotifySendFileStatus":
// Upon receiving the status of sendFile operation, send the response

View File

@ -124,7 +124,7 @@ interface nsINfcBrowserAPI : nsISupports
in boolean isFocus);
};
[scriptable, uuid(f0ed35c5-3f59-4806-b6bb-e77b879887af)]
[scriptable, uuid(75f0c8c0-2e5a-491f-a75d-4f3849c4feec)]
interface nsINfcContentHelper : nsISupports
{
/**
@ -277,10 +277,8 @@ interface nsINfcContentHelper : nsISupports
*
* @param appId
* Application ID that is capable of handling NFC_EVENT_PEER_READY event
* @param tabId
* Tab Id of the window calling this interface.
*/
void notifyUserAcceptedP2P(in unsigned long appId, in uint64_t tabId);
void notifyUserAcceptedP2P(in unsigned long appId);
/**
* Notify the status of sendFile operation to parent process

View File

@ -420,7 +420,7 @@ MozNFCImpl.prototype = {
notifyUserAcceptedP2P: function notifyUserAcceptedP2P(manifestUrl) {
let appID = appsService.getAppLocalIdByManifestURL(manifestUrl);
// Notify chrome process of user's acknowledgement
this._nfcContentHelper.notifyUserAcceptedP2P(appID, this._tabId);
this._nfcContentHelper.notifyUserAcceptedP2P(appID);
},
notifySendFileStatus: function notifySendFileStatus(status, requestId) {

View File

@ -22,7 +22,8 @@ NS_IMPL_ISUPPORTS(PresentationDeviceManager,
nsIPresentationDeviceManager,
nsIPresentationDeviceListener,
nsIPresentationDeviceEventListener,
nsIObserver)
nsIObserver,
nsISupportsWeakReference)
PresentationDeviceManager::PresentationDeviceManager()
{

View File

@ -12,6 +12,7 @@
#include "nsIPresentationDeviceManager.h"
#include "nsIPresentationDeviceProvider.h"
#include "nsCOMArray.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace dom {
@ -20,6 +21,7 @@ class PresentationDeviceManager final : public nsIPresentationDeviceManager
, public nsIPresentationDeviceListener
, public nsIPresentationDeviceEventListener
, public nsIObserver
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS

View File

@ -0,0 +1,493 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "MulticastDNSDeviceProvider.h"
#include "mozilla/Logging.h"
#include "nsAutoPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIPresentationDevice.h"
#include "nsServiceManagerUtils.h"
inline static PRLogModuleInfo*
GetProviderLog()
{
static PRLogModuleInfo* log = PR_NewLogModule("MulticastDNSDeviceProvider");
return log;
}
#undef LOG_I
#define LOG_I(...) PR_LOG(GetProviderLog(), PR_LOG_NOTICE, (__VA_ARGS__))
#undef LOG_E
#define LOG_E(...) PR_LOG(GetProviderLog(), PR_LOG_ERROR, (__VA_ARGS__))
#define SERVICE_TYPE "_mozilla_papi._tcp."
namespace mozilla {
namespace dom {
namespace presentation {
/**
* This wrapper is used to break circular-reference problem.
*/
class DNSServiceWrappedListener final
: public nsIDNSServiceDiscoveryListener
, public nsIDNSRegistrationListener
, public nsIDNSServiceResolveListener
, public nsITCPPresentationServerListener
{
public:
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIDNSSERVICEDISCOVERYLISTENER(mListener)
NS_FORWARD_SAFE_NSIDNSREGISTRATIONLISTENER(mListener)
NS_FORWARD_SAFE_NSIDNSSERVICERESOLVELISTENER(mListener)
NS_FORWARD_SAFE_NSITCPPRESENTATIONSERVERLISTENER(mListener)
explicit DNSServiceWrappedListener() = default;
nsresult SetListener(MulticastDNSDeviceProvider* aListener)
{
mListener = aListener;
return NS_OK;
}
private:
virtual ~DNSServiceWrappedListener() = default;
MulticastDNSDeviceProvider* mListener = nullptr;
};
NS_IMPL_ISUPPORTS(DNSServiceWrappedListener,
nsIDNSServiceDiscoveryListener,
nsIDNSRegistrationListener,
nsIDNSServiceResolveListener,
nsITCPPresentationServerListener)
NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider,
nsIPresentationDeviceProvider,
nsIDNSServiceDiscoveryListener,
nsIDNSRegistrationListener,
nsIDNSServiceResolveListener,
nsITCPPresentationServerListener)
MulticastDNSDeviceProvider::~MulticastDNSDeviceProvider()
{
Uninit();
}
nsresult
MulticastDNSDeviceProvider::Init()
{
if (mInitialized) {
return NS_OK;
}
nsresult rv;
mMulticastDNS = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mWrappedListener = new DNSServiceWrappedListener();
if (NS_WARN_IF(!mWrappedListener)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (NS_WARN_IF(NS_FAILED(rv = mWrappedListener->SetListener(this)))) {
return rv;
}
mPresentationServer = do_CreateInstance("@mozilla.org/presentation-device/tcp-presentation-server;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(mPresentationServer->SetListener(mWrappedListener)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->Init(EmptyCString(), 0)))) {
return rv;
}
uint16_t port = 0;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
return rv;
}
mInitialized = true;
return NS_OK;
}
nsresult
MulticastDNSDeviceProvider::Uninit()
{
if (!mInitialized) {
return NS_OK;
}
if (mPresentationServer) {
mPresentationServer->Close();
mPresentationServer = nullptr;
}
if (mDiscoveryRequest) {
mDiscoveryRequest->Cancel(NS_OK);
mDiscoveryRequest = nullptr;
}
if (mRegisterRequest) {
mRegisterRequest->Cancel(NS_OK);
mRegisterRequest = nullptr;
}
mMulticastDNS = nullptr;
if (mWrappedListener) {
mWrappedListener->SetListener(nullptr);
mWrappedListener = nullptr;
}
mInitialized = false;
return NS_OK;
}
nsresult
MulticastDNSDeviceProvider::RegisterService(uint32_t aPort)
{
LOG_I("RegisterService: %d", aPort);
nsresult rv;
nsCOMPtr<nsIDNSServiceInfo> serviceInfo = do_CreateInstance(DNSSERVICEINFO_CONTRACT_ID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetServiceType(NS_LITERAL_CSTRING(SERVICE_TYPE))))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetPort(aPort)))) {
return rv;
}
if (mRegisterRequest) {
mRegisterRequest->Cancel(NS_OK);
mRegisterRequest = nullptr;
}
return mMulticastDNS->RegisterService(serviceInfo, mWrappedListener, getter_AddRefs(mRegisterRequest));
}
// nsIPresentationDeviceProvider
NS_IMETHODIMP
MulticastDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
{
if (NS_WARN_IF(!aListener)) {
return NS_ERROR_INVALID_POINTER;
}
nsCOMPtr<nsIPresentationDeviceListener> listener = do_QueryReferent(mDeviceListener);
listener.forget(aListener);
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
{
mDeviceListener = do_GetWeakReference(aListener);
nsresult rv;
if (mDeviceListener) {
if (NS_WARN_IF(NS_FAILED(rv = Init()))) {
return rv;
}
} else {
if (NS_WARN_IF(NS_FAILED(rv = Uninit()))) {
return rv;
}
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::ForceDiscovery()
{
LOG_I("ForceDiscovery");
MOZ_ASSERT(mInitialized);
MOZ_ASSERT(mMulticastDNS);
nsresult rv;
if (mDiscoveryRequest) {
mDiscoveryRequest->Cancel(NS_OK);
mDiscoveryRequest = nullptr;
}
if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->StartDiscovery(
NS_LITERAL_CSTRING(SERVICE_TYPE),
mWrappedListener,
getter_AddRefs(mDiscoveryRequest))))) {
return rv;
}
return NS_OK;
}
// nsIDNSServiceDiscoveryListener
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnDiscoveryStarted(const nsACString& aServiceType)
{
LOG_I("OnDiscoveryStarted");
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnDiscoveryStopped(const nsACString& aServiceType)
{
LOG_I("OnDiscoveryStopped");
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
{
if (NS_WARN_IF(!aServiceInfo)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv ;
nsAutoCString serviceName;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
return rv;
}
LOG_I("OnServiceFound: %s", serviceName.get());
if (mRegisteredName == serviceName) {
LOG_I("ignore self");
return NS_OK;
}
nsCOMPtr<nsIPresentationDevice> device;
if (NS_SUCCEEDED(mPresentationServer->GetTCPDevice(serviceName,
getter_AddRefs(device)))) {
LOG_I("device exists");
return NS_OK;
}
if (mMulticastDNS) {
if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->ResolveService(aServiceInfo, mWrappedListener)))) {
return rv;
}
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
{
if (NS_WARN_IF(!aServiceInfo)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsAutoCString serviceName;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
return rv;
}
LOG_I("OnServiceLost: %s", serviceName.get());
nsCOMPtr<nsIPresentationDevice> device;
if (NS_FAILED(mPresentationServer->GetTCPDevice(serviceName, getter_AddRefs(device)))) {
return NS_OK; // ignore non-existing device;
}
NS_WARN_IF(NS_FAILED(mPresentationServer->RemoveTCPDevice(serviceName)));
nsCOMPtr<nsIPresentationDeviceListener> listener;
GetListener(getter_AddRefs(listener));
if (listener) {
listener->RemoveDevice(device);
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
{
LOG_E("OnStartDiscoveryFailed: %d", aErrorCode);
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
{
LOG_E("OnStopDiscoveryFailed: %d", aErrorCode);
return NS_OK;
}
// nsIDNSRegistrationListener
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
{
if (NS_WARN_IF(!aServiceInfo)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsAutoCString name;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(name)))) {
return rv;
}
LOG_I("OnServiceRegistered (%s)", name.get());
mRegisteredName = name;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->SetId(name)))) {
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
{
LOG_I("OnServiceUnregistered");
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
{
LOG_E("OnRegistrationFailed: %d", aErrorCode);
nsresult rv;
if (aErrorCode == nsIDNSRegistrationListener::ERROR_SERVICE_NOT_RUNNING) {
uint16_t port = 0;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
return rv;
}
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
{
LOG_E("OnUnregistrationFailed: %d", aErrorCode);
return NS_OK;
}
// nsIDNSServiceResolveListener
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
{
if (NS_WARN_IF(!aServiceInfo)) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsAutoCString serviceName;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
return rv;
}
LOG_I("OnServiceResolved: %s", serviceName.get());
nsCOMPtr<nsIPresentationDevice> device;
nsCOMPtr<nsIPresentationDeviceListener> listener;
GetListener(getter_AddRefs(listener));
if (NS_SUCCEEDED(mPresentationServer->GetTCPDevice(serviceName,
getter_AddRefs(device)))) {
NS_WARN_IF(NS_FAILED(mPresentationServer->RemoveTCPDevice(serviceName)));
if (listener) {
NS_WARN_IF(NS_FAILED(listener->RemoveDevice(device)));
}
}
nsAutoCString host;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
return rv;
}
uint16_t port;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetPort(&port)))) {
return rv;
}
nsAutoCString serviceType;
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceType(serviceType)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->CreateTCPDevice(serviceName,
serviceName,
serviceType,
host,
port,
getter_AddRefs(device))))) {
return rv;
}
if (listener) {
listener->AddDevice(device);
}
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
{
LOG_E("OnResolveFailed: %d", aErrorCode);
return NS_OK;
}
// nsITCPPresentationServerListener
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnClose(nsresult aReason)
{
LOG_I("OnClose: %x", aReason);
if (mRegisterRequest) {
mRegisterRequest->Cancel(aReason);
mRegisterRequest = nullptr;
}
nsresult rv;
if (NS_FAILED(aReason)) {
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->Init(EmptyCString(), 0)))) {
return rv;
}
uint16_t port = 0;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
return rv;
}
}
return NS_OK;
}
} // namespace presentation
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_presentation_provider_MulticastDNSDeviceProvider_h
#define mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
#include "nsCOMPtr.h"
#include "nsICancelable.h"
#include "nsIDNSServiceDiscovery.h"
#include "nsIPresentationDeviceProvider.h"
#include "nsITCPPresentationServer.h"
#include "nsRefPtr.h"
#include "nsString.h"
#include "nsWeakPtr.h"
namespace mozilla {
namespace dom {
namespace presentation {
class DNSServiceWrappedListener;
class MulticastDNSService;
class MulticastDNSDeviceProvider final
: public nsIPresentationDeviceProvider
, public nsIDNSServiceDiscoveryListener
, public nsIDNSRegistrationListener
, public nsIDNSServiceResolveListener
, public nsITCPPresentationServerListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
NS_DECL_NSIDNSREGISTRATIONLISTENER
NS_DECL_NSIDNSSERVICERESOLVELISTENER
NS_DECL_NSITCPPRESENTATIONSERVERLISTENER
explicit MulticastDNSDeviceProvider() = default;
nsresult Init();
nsresult Uninit();
private:
virtual ~MulticastDNSDeviceProvider();
nsresult RegisterService(uint32_t aPort);
bool mInitialized = false;
nsWeakPtr mDeviceListener;
nsCOMPtr<nsITCPPresentationServer> mPresentationServer;
nsCOMPtr<nsIDNSServiceDiscovery> mMulticastDNS;
nsRefPtr<DNSServiceWrappedListener> mWrappedListener;
nsCOMPtr<nsICancelable> mDiscoveryRequest;
nsCOMPtr<nsICancelable> mRegisterRequest;
nsCString mRegisteredName;
};
} // namespace presentation
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h

View File

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "MulticastDNSDeviceProvider.h"
#include "mozilla/ModuleUtils.h"
#define MULTICAST_DNS_PROVIDER_CID \
{0x814f947a, 0x52f7, 0x41c9, \
{ 0x94, 0xa1, 0x36, 0x84, 0x79, 0x72, 0x84, 0xac }}
#define MULTICAST_DNS_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/multicastdns-provider;1"
using mozilla::dom::presentation::MulticastDNSDeviceProvider;
NS_GENERIC_FACTORY_CONSTRUCTOR(MulticastDNSDeviceProvider)
NS_DEFINE_NAMED_CID(MULTICAST_DNS_PROVIDER_CID);
static const mozilla::Module::CIDEntry kPresentationDeviceProviderCIDs[] = {
{ &kMULTICAST_DNS_PROVIDER_CID, false, nullptr, MulticastDNSDeviceProviderConstructor },
{ nullptr }
};
static const mozilla::Module::ContractIDEntry kPresentationDeviceProviderContracts[] = {
{ MULTICAST_DNS_PROVIDER_CONTRACT_ID, &kMULTICAST_DNS_PROVIDER_CID },
{ nullptr }
};
static const mozilla::Module::CategoryEntry kPresentationDeviceProviderCategories[] = {
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16
{ PRESENTATION_DEVICE_PROVIDER_CATEGORY, "MulticastDNSDeviceProvider", MULTICAST_DNS_PROVIDER_CONTRACT_ID},
#endif
{ nullptr }
};
static const mozilla::Module kPresentationDeviceProviderModule = {
mozilla::Module::kVersion,
kPresentationDeviceProviderCIDs,
kPresentationDeviceProviderContracts,
kPresentationDeviceProviderCategories
};
NSMODULE_DEFN(PresentationDeviceProviderModule) = &kPresentationDeviceProviderModule;

View File

@ -8,3 +8,13 @@ EXTRA_COMPONENTS += [
'BuiltinProviders.manifest',
'TCPPresentationServer.js'
]
UNIFIED_SOURCES += [
'MulticastDNSDeviceProvider.cpp',
'PresentationDeviceProviderModule.cpp',
]
FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,255 @@
/* -*- 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, manager: Cm, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const INFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
const PROVIDER_CONTRACT_ID = "@mozilla.org/presentation-device/multicastdns-provider;1";
const SD_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
const UUID_CONTRACT_ID = "@mozilla.org/uuid-generator;1";
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
function MockFactory(aClass) {
this._cls = aClass;
}
MockFactory.prototype = {
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
switch(typeof(this._cls)) {
case "function":
return new this._cls().QueryInterface(aIID);
case "object":
return this._cls.QueryInterface(aIID);
default:
return null;
}
},
lockFactory: function(aLock) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
};
function ContractHook(aContractID, aClass) {
this._contractID = aContractID;
this.classID = Cc[UUID_CONTRACT_ID].getService(Ci.nsIUUIDGenerator).generateUUID();
this._newFactory = new MockFactory(aClass);
if (!this.hookedMap.has(this._contractID)) {
this.hookedMap.set(this._contractID, new Array());
}
this.init();
}
ContractHook.prototype = {
hookedMap: new Map(), // remember only the most original factory.
init: function() {
this.reset();
let oldContract = this.unregister();
this.hookedMap.get(this._contractID).push(oldContract);
registrar.registerFactory(this.classID, "", this._contractID, this._newFactory);
do_register_cleanup(() => { this.cleanup.apply(this); });
},
reset: function() {},
cleanup: function() {
this.reset();
this.unregister();
let prevContract = this.hookedMap.get(this._contractID).pop();
if (prevContract.factory) {
registrar.registerFactory(prevContract.classID, "", this._contractID, prevContract.factory);
}
},
unregister: function() {
var classID, factory;
try {
classID = registrar.contractIDToCID(this._contractID);
factory = Cm.getClassObject(Cc[this._contractID], Ci.nsIFactory);
} catch (ex) {
classID = "";
factory = null;
}
if (factory) {
registrar.unregisterFactory(classID, factory);
}
return { classID: classID, factory: factory };
}
};
function MockDNSServiceInfo() {}
MockDNSServiceInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceInfo]),
set host(aHost) {
this._host = aHost;
},
get host() {
return this._host;
},
set port(aPort) {
this._port = aPort;
},
get port() {
return this._port;
},
set serviceName(aServiceName) {
this._serviceName = aServiceName;
},
get serviceName() {
return this._serviceName;
},
set serviceType(aServiceType) {
this._serviceType = aServiceType;
},
get serviceType() {
return this._serviceType;
},
set domainName(aDomainName) {
this._domainName = aDomainName;
},
get domainName() {
return this._domainName;
},
set attributes(aAttributes) {
this._attributes = aAttributes;
},
get attributes() {
return this._attributes;
}
};
function TestPresentationDeviceListener() {}
TestPresentationDeviceListener.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener]),
addDevice: function(device) {},
removeDevice: function(device) {},
updateDevice: function(device) {}
};
function createDevice(host, port, serviceName, serviceType, domainName, attributes) {
let device = new MockDNSServiceInfo();
device.host = host || "";
device.port = port || 0;
device.serviceName = serviceName || "";
device.serviceType = serviceType || "";
device.domainName = domainName || "";
device.attributes = attributes || null;
return device;
}
function registerService() {
let mockObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {},
registerService: function(serviceInfo, listener) {
this.serviceRegistered++;
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
cancel: function() {
this.serviceUnregistered++;
}.bind(this)
}
},
resolveService: function(serviceInfo, listener) {},
serviceRegistered: 0,
serviceUnregistered: 0
};
let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
Assert.equal(mockObj.serviceRegistered, 0);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
Assert.equal(mockObj.serviceRegistered, 0);
provider.listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, Ci.nsISupportsWeakReference]),
addDevice: function(device) {},
removeDevice: function(device) {},
updateDevice: function(device) {},
};
Assert.equal(mockObj.serviceRegistered, 1);
Assert.equal(mockObj.serviceUnregistered, 0);
provider.listener = null;
Assert.equal(mockObj.serviceUnregistered, 1);
run_next_test();
}
function addDevice() {
let mockDevice = createDevice("device.local", 12345, "service.name", "_mozilla_papi._tcp");
let mockObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {
listener.onDiscoveryStarted(serviceType);
listener.onServiceFound(createDevice("", 0, mockDevice.serviceName, mockDevice.serviceType));
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
cancel: function() {}
}
},
registerService: function(serviceInfo, listener) {},
resolveService: function(serviceInfo, listener) {
Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
listener.onServiceResolved(createDevice(mockDevice.host, mockDevice.port, mockDevice.serviceName, mockDevice.serviceType));
}
};
let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, Ci.nsISupportsWeakReference]),
addDevice: function(device) { this.devices.push(device); },
removeDevice: function(device) {},
updateDevice: function(device) {},
devices: []
};
provider.listener = listener;
Assert.equal(listener.devices.length, 0);
provider.forceDiscovery();
Assert.equal(listener.devices.length, 1);
provider.listener = null;
run_next_test();
}
function run_test() {
let infoHook = new ContractHook(INFO_CONTRACT_ID, MockDNSServiceInfo);
add_test(registerService);
add_test(addDevice);
run_next_test();
}

View File

@ -2,5 +2,6 @@
head =
tail =
[test_multicast_dns_device_provider.js]
[test_presentation_device_manager.js]
[test_tcp_control_channel.js]

View File

@ -368,7 +368,7 @@ nsVolumeService::FindVolumeByMountLockName(const nsAString& aMountLockName)
}
already_AddRefed<nsVolume>
nsVolumeService::FindVolumeByName(const nsAString& aName)
nsVolumeService::FindVolumeByName(const nsAString& aName, nsVolume::Array::index_type* aIndex)
{
mArrayMonitor.AssertCurrentThreadOwns();
@ -377,52 +377,34 @@ nsVolumeService::FindVolumeByName(const nsAString& aName)
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
if (vol->Name().Equals(aName)) {
if (aIndex) {
*aIndex = volIndex;
}
return vol.forget();
}
}
return nullptr;
}
//static
already_AddRefed<nsVolume>
nsVolumeService::CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake /*= false*/)
{
MonitorAutoLock autoLock(mArrayMonitor);
nsRefPtr<nsVolume> vol;
vol = FindVolumeByName(aName);
if (vol) {
return vol.forget();
}
// Volume not found - add a new one
vol = new nsVolume(aName);
vol->SetIsFake(aIsFake);
mVolumeArray.AppendElement(vol);
return vol.forget();
}
void
nsVolumeService::UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers)
nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers)
{
MOZ_ASSERT(NS_IsMainThread());
nsString volName;
aVolume->GetName(volName);
bool aIsFake;
aVolume->GetIsFake(&aIsFake);
nsRefPtr<nsVolume> vol = CreateOrFindVolumeByName(volName, aIsFake);
if (vol->Equals(aVolume)) {
// Nothing has really changed. Don't bother telling anybody.
return;
{
MonitorAutoLock autoLock(mArrayMonitor);
nsVolume::Array::index_type volIndex;
nsRefPtr<nsVolume> vol = FindVolumeByName(aVolume->Name(), &volIndex);
if (!vol) {
mVolumeArray.AppendElement(aVolume);
} else if (vol->Equals(aVolume) || (!vol->IsFake() && aVolume->IsFake())) {
// Ignore if nothing changed or if a fake tries to override a real volume.
return;
} else {
mVolumeArray.ReplaceElementAt(volIndex, aVolume);
}
}
if (!vol->IsFake() && aIsFake) {
// Prevent an incoming fake volume from overriding an existing real volume.
return;
}
vol->Set(aVolume);
if (!aNotifyObservers) {
return;
}
@ -431,8 +413,8 @@ nsVolumeService::UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers)
if (!obs) {
return;
}
NS_ConvertUTF8toUTF16 stateStr(vol->StateStr());
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
NS_ConvertUTF8toUTF16 stateStr(aVolume->StateStr());
obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get());
}
NS_IMETHODIMP
@ -471,9 +453,7 @@ nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state)
return NS_ERROR_NOT_AVAILABLE;
}
// UpdateVolume expects the volume passed in to NOT be the
// same pointer as what CreateOrFindVolumeByName would return,
// which is why we allocate a temporary volume here.
// Clone the existing volume so we can replace it
nsRefPtr<nsVolume> volume = new nsVolume(name);
volume->Set(vol);
volume->SetState(state);
@ -502,15 +482,15 @@ nsVolumeService::RemoveFakeVolume(const nsAString& name)
void
nsVolumeService::RemoveVolumeByName(const nsAString& aName)
{
nsRefPtr<nsVolume> vol;
{
MonitorAutoLock autoLock(mArrayMonitor);
vol = FindVolumeByName(aName);
nsVolume::Array::index_type volIndex;
nsRefPtr<nsVolume> vol = FindVolumeByName(aName, &volIndex);
if (!vol) {
return;
}
mVolumeArray.RemoveElementAt(volIndex);
}
if (!vol) {
return;
}
mVolumeArray.RemoveElement(vol);
if (XRE_GetProcessType() == GeckoProcessType_Default) {
nsCOMPtr<nsIObserverService> obs = GetObserverService();

View File

@ -47,7 +47,7 @@ public:
void DumpNoLock(const char* aLabel);
// To use this function, you have to create a new volume and pass it in.
void UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers = true);
void UpdateVolume(nsVolume* aVolume, bool aNotifyObservers = true);
void UpdateVolumeIOThread(const Volume* aVolume);
void RecvVolumesFromParent(const nsTArray<dom::VolumeInfo>& aVolumes);
@ -61,8 +61,9 @@ private:
void CheckMountLock(const nsAString& aMountLockName,
const nsAString& aMountLockState);
already_AddRefed<nsVolume> FindVolumeByMountLockName(const nsAString& aMountLockName);
already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName);
already_AddRefed<nsVolume> CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake = false);
already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName,
nsVolume::Array::index_type* aIndex = nullptr);
Monitor mArrayMonitor;
nsVolume::Array mVolumeArray;

View File

@ -0,0 +1,110 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["TelephonyUtils"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
/* global TelephonyService */
XPCOMUtils.defineLazyServiceGetter(this,
"TelephonyService",
"@mozilla.org/telephony/telephonyservice;1",
"nsITelephonyService");
function getCurrentCalls(aFilter) {
if (aFilter === undefined) {
aFilter = call => true;
}
let calls = [];
// nsITelephonyService.enumerateCalls is synchronous.
TelephonyService.enumerateCalls({
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]),
enumerateCallStateComplete: function() {},
enumerateCallState: function(call) {
if (aFilter(call)) {
calls.push(call);
}
},
});
return calls;
}
this.TelephonyUtils = {
/**
* Check whether there are any calls.
*
* @param aClientId [optional] If provided, only check on aClientId
* @return boolean
*/
hasAnyCalls: function(aClientId) {
let calls = getCurrentCalls(call => {
if (aClientId !== undefined && call.clientId !== aClientId) {
return false;
}
return true;
});
return calls.length !== 0;
},
/**
* Check whether there are any connected calls.
*
* @param aClientId [optional] If provided, only check on aClientId
* @return boolean
*/
hasConnectedCalls: function(aClientId) {
let calls = getCurrentCalls(call => {
if (aClientId !== undefined && call.clientId !== aClientId) {
return false;
}
return call.callState === Ci.nsITelephonyService.CALL_STATE_CONNECTED;
});
return calls.length !== 0;
},
/**
* Return a promise which will be resolved when there are no calls.
*
* @param aClientId [optional] only check on aClientId if provided
* @return Promise
*/
waitForNoCalls: function(aClientId) {
if (!this.hasAnyCalls(aClientId)) {
return Promise.resolve();
}
let self = this;
return new Promise(resolve => {
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]),
enumerateCallStateComplete: function() {},
enumerateCallState: function() {},
callStateChanged: function() {
if (!self.hasAnyCalls(aClientId)) {
TelephonyService.unregisterListener(this);
resolve();
}
},
conferenceCallStateChanged: function() {},
supplementaryServiceNotification: function() {},
notifyError: function() {},
notifyCdmaCallWaiting: function() {},
notifyConferenceError: function() {}
};
TelephonyService.registerListener(listener);
});
}
};

View File

@ -72,7 +72,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
'gonk/TelephonyService.manifest',
]
EXTRA_JS_MODULES += [
'gonk/DialNumberUtils.jsm'
'gonk/DialNumberUtils.jsm',
'gonk/TelephonyUtils.jsm',
]
FAIL_ON_WARNINGS = True

View File

@ -1107,12 +1107,19 @@ let emulator = (function() {
let promises = [];
let promise = gWaitForEvent(connection, "radiostatechange", event => {
promises.push(gWaitForEvent(connection, "radiostatechange", event => {
let state = connection.radioState;
log("current radioState: " + state);
return state == desiredRadioState;
});
promises.push(promise);
}));
// Wait for icc status to finish updating. Please see bug 1169504 for the
// reason why we need this.
promises.push(gWaitForEvent(connection, "iccchange", event => {
let iccId = connection.iccId;
log("current iccId: " + iccId);
return !!iccId === enabled;
}));
promises.push(connection.setRadioEnabled(enabled));

View File

@ -54,4 +54,5 @@ qemu = true
[test_redundant_operations.js]
[test_swap_held_and_active.js]
[test_system_message_telephony_call_ended.js]
[test_TelephonyUtils.js]
[test_temporary_clir.js]

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_CONTEXT = "chrome";
MARIONETTE_HEAD_JS = 'head.js';
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyServiceGetter(this,
"TelephonyService",
"@mozilla.org/telephony/telephonyservice;1",
"nsIGonkTelephonyService");
XPCOMUtils.defineLazyModuleGetter(this, "TelephonyUtils",
"resource://gre/modules/TelephonyUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let ns = {};
Cu.import("resource://gre/modules/ril_consts.js", ns);
return ns;
});
const number = "0912345678";
function dial() {
return new Promise(resolve => {
TelephonyService.dial(0, number, false, {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyDialCallback]),
notifyDialCallSuccess: function() { resolve(); }
});
});
}
function waitForStateChanged() {
return new Promise(resolve => {
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]),
callStateChanged: function(length, allInfo) {
resolve(allInfo);
TelephonyService.unregisterListener(listener);
},
conferenceCallStateChanged: function() {},
supplementaryServiceNotification: function() {},
notifyError: function() {},
notifyCdmaCallWaiting: function() {},
notifyConferenceError: function() {}
};
TelephonyService.registerListener(listener);
});
}
function test_noCall() {
log("== test_noCall ==");
is(TelephonyUtils.hasAnyCalls(), false, "hasAnyCalls");
is(TelephonyUtils.hasConnectedCalls(), false, "hasConnectedCalls");
return TelephonyUtils.waitForNoCalls();
}
function test_oneCall() {
log("== test_oneCall ==");
return dial()
.then(() => {
is(TelephonyUtils.hasAnyCalls(), true, "hasAnyCalls");
is(TelephonyUtils.hasConnectedCalls(), false, "hasConnectedCalls");
})
.then(() => {
let p = waitForStateChanged();
emulator.runCmd("gsm accept " + number);
return p;
})
.then(allInfo => {
is(allInfo[0].callState, Ci.nsITelephonyService.CALL_STATE_CONNECTED);
is(TelephonyUtils.hasAnyCalls(), true, "hasAnyCalls");
is(TelephonyUtils.hasConnectedCalls(), true, "hasConnectedCalls");
})
.then(() => {
let p = TelephonyUtils.waitForNoCalls();
emulator.runCmd("gsm cancel " + number);
return p;
});
}
test_noCall()
.then(test_oneCall)
.catch(error => ok(false, "Promise reject: " + error))
.then(finish);

View File

@ -416,7 +416,7 @@ var WifiManager = (function() {
let currentNetwork = Object.create(null);
currentNetwork.netId = manager.connectionInfo.id;
manager.getNetworkConfiguration(currentNetwork, function (){
manager.getNetworkConfiguration(currentNetwork, function () {
curNetworkKey = getNetworkKey(currentNetwork);
// Add additional information to static ip configuration
@ -435,15 +435,19 @@ var WifiManager = (function() {
// If the ssid of current connection is the same as configured ssid
// It means we need update current connection to use static IP address.
if (setNetworkKey == curNetworkKey) {
// Use configureInterface directly doesn't work, the network iterface
// Use configureInterface directly doesn't work, the network interface
// and routing table is changed but still cannot connect to network
// so the workaround here is disable interface the enable again to
// trigger network reconnect with static ip.
gNetworkService.disableInterface(manager.ifname, function (ok) {
gNetworkService.enableInterface(manager.ifname, function (ok) {
callback(ok);
});
});
return;
}
callback(true);
});
}
@ -3494,7 +3498,7 @@ WifiWorker.prototype = {
},
setStaticIpMode: function(msg) {
const message = "WifiManager:setStaticMode:Return";
const message = "WifiManager:setStaticIpMode:Return";
let self = this;
let network = msg.data.network;
let info = msg.data.info;

View File

@ -433,6 +433,23 @@ let gTestSuite = (function() {
.then(event => event.target.result);
}
/**
* Set the given network to static ip mode.
*
* Resolve when we set static ip mode successfully; reject when any error
* occurs.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @return A deferred promise.
*/
function setStaticIpMode(aNetwork, aConfig) {
let request = wifiManager.setStaticIpMode(aNetwork, aConfig);
return wrapDomRequestAsPromise(request)
.then(event => event.target.result);
}
/**
* Issue a request to scan all wifi available networks.
*
@ -1025,6 +1042,117 @@ let gTestSuite = (function() {
});
}
/**
* Execute 'netcfg' shell and parse the result.
*
* Resolve when the executing is successful and reject otherwise.
*
* Fulfill params: Command result object, each key of which is the interface
* name and value is { ip(string), prefix(string) }.
* Reject params: String that indicates the reason of rejection.
*
* @return A deferred promise.
*/
function exeAndParseNetcfg() {
return runEmulatorShellSafe(['netcfg'])
.then(function (aLines) {
// Sample output:
//
// lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00
// eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56
// rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:58
// rmnet2 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59
// rmnet3 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:5a
// wlan0 UP 192.168.1.1/24 0x00001043 52:54:00:12:34:5b
// sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00
// rmnet0 UP 10.0.2.100/24 0x00001043 52:54:00:12:34:57
//
let netcfgResult = {};
aLines.forEach(function (aLine) {
let tokens = aLine.split(/\s+/);
if (tokens.length < 5) {
return;
}
let ifname = tokens[0];
let [ip, prefix] = tokens[2].split('/');
netcfgResult[ifname] = { ip: ip, prefix: prefix };
});
log("netcfg result:" + JSON.stringify(netcfgResult));
return netcfgResult;
});
}
/**
* Execute 'ip route' and parse the result.
*
* Resolve when the executing is successful and reject otherwise.
*
* Fulfill params: Command result object, each key of which is the interface
* name and value is { src(string), gateway(string),
* default(boolean) }.
* Reject params: String that indicates the reason of rejection.
*
* @return A deferred promise.
*/
function exeAndParseIpRoute() {
return runEmulatorShellSafe(['ip', 'route'])
.then(function (aLines) {
// Sample output:
//
// 10.0.2.4 via 10.0.2.2 dev rmnet0
// 10.0.2.3 via 10.0.2.2 dev rmnet0
// 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.1
// 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
// 10.0.2.0/24 dev rmnet0 proto kernel scope link src 10.0.2.100
// default via 10.0.2.2 dev rmnet0
// default via 10.0.2.2 dev eth0 metric 2
//
let ipRouteResult = {};
// Parse source ip for each interface.
aLines.forEach(function (aLine) {
let tokens = aLine.trim().split(/\s+/);
let srcIndex = tokens.indexOf('src');
if (srcIndex < 0 || srcIndex + 1 >= tokens.length) {
return;
}
let ifname = tokens[2];
let src = tokens[srcIndex + 1];
ipRouteResult[ifname] = { src: src, default: false, gateway: null };
});
// Parse default interfaces.
aLines.forEach(function (aLine) {
let tokens = aLine.split(/\s+/);
if (tokens.length < 2) {
return;
}
if ('default' === tokens[0]) {
let ifnameIndex = tokens.indexOf('dev');
if (ifnameIndex < 0 || ifnameIndex + 1 >= tokens.length) {
return;
}
let ifname = tokens[ifnameIndex + 1];
if (!ipRouteResult[ifname]) {
return;
}
ipRouteResult[ifname].default = true;
let gwIndex = tokens.indexOf('via');
if (gwIndex < 0 || gwIndex + 1 >= tokens.length) {
return;
}
ipRouteResult[ifname].gateway = tokens[gwIndex + 1];
return;
}
});
log("ip route result:" + JSON.stringify(ipRouteResult));
return ipRouteResult;
});
}
/**
* Verify everything about routing when the wifi tethering is either on or off.
*
@ -1044,87 +1172,8 @@ let gTestSuite = (function() {
* @return A deferred promise.
*/
function verifyTetheringRouting(aEnabled) {
let netcfgResult = {};
let ipRouteResult = {};
// Execute 'netcfg' and parse to |netcfgResult|, each key of which is the
// interface name and value is { ip(string) }.
function exeAndParseNetcfg() {
return runEmulatorShellSafe(['netcfg'])
.then(function (aLines) {
// Sample output:
//
// lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00
// eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56
// rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:58
// rmnet2 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59
// rmnet3 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:5a
// wlan0 UP 192.168.1.1/24 0x00001043 52:54:00:12:34:5b
// sit0 DOWN 0.0.0.0/0 0x00000080 00:00:00:00:00:00
// rmnet0 UP 10.0.2.100/24 0x00001043 52:54:00:12:34:57
//
aLines.forEach(function (aLine) {
let tokens = aLine.split(/\s+/);
if (tokens.length < 5) {
return;
}
let ifname = tokens[0];
let ip = (tokens[2].split('/'))[0];
netcfgResult[ifname] = { ip: ip };
});
});
}
// Execute 'ip route' and parse to |ipRouteResult|, each key of which is the
// interface name and value is { src(string), default(boolean) }.
function exeAndParseIpRoute() {
return runEmulatorShellSafe(['ip', 'route'])
.then(function (aLines) {
// Sample output:
//
// 10.0.2.4 via 10.0.2.2 dev rmnet0
// 10.0.2.3 via 10.0.2.2 dev rmnet0
// 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.1
// 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
// 10.0.2.0/24 dev rmnet0 proto kernel scope link src 10.0.2.100
// default via 10.0.2.2 dev rmnet0
// default via 10.0.2.2 dev eth0 metric 2
//
// Parse source ip for each interface.
aLines.forEach(function (aLine) {
let tokens = aLine.trim().split(/\s+/);
let srcIndex = tokens.indexOf('src');
if (srcIndex < 0 || srcIndex + 1 >= tokens.length) {
return;
}
let ifname = tokens[2];
let src = tokens[srcIndex + 1];
ipRouteResult[ifname] = { src: src, default: false };
});
// Parse default interfaces.
aLines.forEach(function (aLine) {
let tokens = aLine.split(/\s+/);
if (tokens.length < 2) {
return;
}
if ('default' === tokens[0]) {
let ifnameIndex = tokens.indexOf('dev');
if (ifnameIndex < 0 || ifnameIndex + 1 >= tokens.length) {
return;
}
let ifname = tokens[ifnameIndex + 1];
if (ipRouteResult[ifname]) {
ipRouteResult[ifname].default = true;
}
return;
}
});
});
}
let netcfgResult;
let ipRouteResult;
// Find MASQUERADE in POSTROUTING section. 'MASQUERADE' should be found
// when tethering is enabled. 'MASQUERADE' shouldn't be found when tethering
@ -1158,9 +1207,6 @@ let gTestSuite = (function() {
}
function verifyDefaultRouteAndIp(aExpectedWifiTetheringIp) {
log(JSON.stringify(ipRouteResult));
log(JSON.stringify(netcfgResult));
if (aEnabled) {
isOrThrow(ipRouteResult['rmnet0'].src, netcfgResult['rmnet0'].ip, 'rmnet0.ip');
isOrThrow(ipRouteResult['rmnet0'].default, true, 'rmnet0.default');
@ -1173,7 +1219,9 @@ let gTestSuite = (function() {
return verifyIptables()
.then(exeAndParseNetcfg)
.then((aResult) => { netcfgResult = aResult; })
.then(exeAndParseIpRoute)
.then((aResult) => { ipRouteResult = aResult; })
.then(() => getSettings(SETTINGS_TETHERING_WIFI_IP))
.then(ip => verifyDefaultRouteAndIp(ip));
}
@ -1244,6 +1292,7 @@ let gTestSuite = (function() {
suite.getFirstIndexBySsid = getFirstIndexBySsid;
suite.testAssociate = testAssociate;
suite.getKnownNetworks = getKnownNetworks;
suite.setStaticIpMode = setStaticIpMode;
suite.requestWifiScan = requestWifiScan;
suite.waitForConnected = waitForConnected;
suite.forgetNetwork = forgetNetwork;
@ -1254,6 +1303,8 @@ let gTestSuite = (function() {
suite.getImportedCerts = getImportedCerts;
suite.deleteCert = deleteCert;
suite.writeFile = writeFile;
suite.exeAndParseNetcfg = exeAndParseNetcfg;
suite.exeAndParseIpRoute = exeAndParseIpRoute;
/**
* Common test routine.

View File

@ -8,6 +8,7 @@ qemu = true
[test_wifi_associate.js]
[test_wifi_associate_wo_connect.js]
[test_wifi_auto_connect.js]
[test_wifi_static_ip.js]
[test_wifi_tethering_wifi_disabled.js]
[test_wifi_tethering_wifi_inactive.js]
[test_wifi_tethering_wifi_active.js]

View File

@ -0,0 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const STATIC_IP_CONFIG = {
enabled: true,
ipaddr: "192.168.111.222",
proxy: "",
maskLength: 24,
gateway: "192.168.111.1",
dns1: "8.8.8.8",
dns2: "8.8.4.4",
};
function testAssociateWithStaticIp(aNetwork, aStaticIpConfig) {
return gTestSuite.setStaticIpMode(aNetwork, aStaticIpConfig)
.then(() => gTestSuite.testAssociate(aNetwork))
// Check ip address and prefix.
.then(() => gTestSuite.exeAndParseNetcfg())
.then((aResult) => {
is(aResult["wlan0"].ip, aStaticIpConfig.ipaddr, "Check ip address");
is(aResult["wlan0"].prefix, aStaticIpConfig.maskLength, "Check prefix");
})
// Check routing.
.then(() => gTestSuite.exeAndParseIpRoute())
.then((aResult) => {
is(aResult["wlan0"].src, aStaticIpConfig.ipaddr, "Check ip address");
is(aResult["wlan0"].default, true, "Check default route");
is(aResult["wlan0"].gateway, aStaticIpConfig.gateway, "Check gateway");
});
}
// Start test.
gTestSuite.doTest(function() {
return gTestSuite.ensureWifiEnabled(true)
.then(() => gTestSuite.requestWifiScan())
.then((aNetworks) => testAssociateWithStaticIp(aNetworks[0],
STATIC_IP_CONFIG));
});

View File

@ -12,8 +12,6 @@
#include <unistd.h>
#include "mozilla/ipc/BluetoothDaemonConnectionConsumer.h"
#include "mozilla/ipc/DataSocket.h"
#include "mozilla/ipc/UnixSocketConnector.h"
#include "mozilla/ipc/UnixSocketWatcher.h"
#include "nsTArray.h"
#include "nsXULAppAPI.h"
@ -201,35 +199,16 @@ BluetoothDaemonPDUConsumer::~BluetoothDaemonPDUConsumer()
// BluetoothDaemonConnectionIO
//
class BluetoothDaemonConnectionIO final
: public UnixSocketWatcher
, public ConnectionOrientedSocketIO
class BluetoothDaemonConnectionIO final : public ConnectionOrientedSocketIO
{
public:
BluetoothDaemonConnectionIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector,
BluetoothDaemonConnection* aConnection,
BluetoothDaemonPDUConsumer* aConsumer);
// Task callback methods
//
void Send(UnixSocketIOBuffer* aBuffer);
void OnSocketCanReceiveWithoutBlocking() override;
void OnSocketCanSendWithoutBlocking() override;
void OnConnected() override;
void OnError(const char* aFunction, int aErrno) override;
// Methods for |ConnectionOrientedSocketIO|
//
nsresult Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength) override;
// Methods for |DataSocketIO|
//
@ -260,10 +239,14 @@ BluetoothDaemonConnectionIO::BluetoothDaemonConnectionIO(
MessageLoop* aIOLoop,
int aFd,
ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector,
BluetoothDaemonConnection* aConnection,
BluetoothDaemonPDUConsumer* aConsumer)
: UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, ConnectionOrientedSocketIO(aConsumerThread)
: ConnectionOrientedSocketIO(aConsumerThread,
aIOLoop,
aFd,
aConnectionStatus,
aConnector)
, mConnection(aConnection)
, mConsumer(aConsumer)
, mShuttingDownOnIOThread(false)
@ -272,98 +255,6 @@ BluetoothDaemonConnectionIO::BluetoothDaemonConnectionIO(
MOZ_ASSERT(mConsumer);
}
void
BluetoothDaemonConnectionIO::Send(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(aBuffer);
EnqueueData(aBuffer);
AddWatchers(WRITE_WATCHER, false);
}
void
BluetoothDaemonConnectionIO::OnSocketCanReceiveWithoutBlocking()
{
ssize_t res = ReceiveData(GetFd());
if (res < 0) {
/* I/O error */
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
} else if (!res) {
/* EOF or peer shutdown */
RemoveWatchers(READ_WATCHER);
}
}
void
BluetoothDaemonConnectionIO::OnSocketCanSendWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
MOZ_ASSERT(!IsShutdownOnIOThread());
if (NS_WARN_IF(NS_FAILED(SendPendingData(GetFd())))) {
RemoveWatchers(WRITE_WATCHER);
}
}
void
BluetoothDaemonConnectionIO::OnConnected()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
BluetoothDaemonConnectionIO::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
UnixFdWatcher::OnError(aFunction, aErrno);
// Clean up watchers, status, fd
Close();
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
}
// |ConnectionOrientedSocketIO|
nsresult
BluetoothDaemonConnectionIO::Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTING);
// File-descriptor setup
if (TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, O_NONBLOCK)) < 0) {
OnError("fcntl", errno);
ScopedClose cleanupFd(aFd);
return NS_ERROR_FAILURE;
}
SetSocket(aFd, SOCKET_IS_CONNECTED);
// Signal success
OnConnected();
return NS_OK;
}
// |DataSocketIO|
nsresult
@ -464,16 +355,11 @@ BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector,
{
MOZ_ASSERT(!mIO);
// |BluetoothDaemonConnection| now owns the connector, but doesn't
// actually use it. So the connector is stored in an auto pointer
// to be deleted at the end of the method.
nsAutoPtr<UnixSocketConnector> connector(aConnector);
SetConnectionStatus(SOCKET_CONNECTING);
mIO = new BluetoothDaemonConnectionIO(
aConsumerThread, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING,
this, mPDUConsumer);
aConnector, this, mPDUConsumer);
aIO = mIO;
return NS_OK;

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ConnectionOrientedSocket.h"
#include "UnixSocketConnector.h"
namespace mozilla {
namespace ipc {
@ -14,13 +15,172 @@ namespace ipc {
//
ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
nsIThread* aConsumerThread)
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
int aFd,
ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector)
: DataSocketIO(aConsumerThread)
{ }
, UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, mConnector(aConnector)
, mPeerAddressLength(0)
{
MOZ_ASSERT(mConnector);
}
ConnectionOrientedSocketIO::ConnectionOrientedSocketIO(
nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
UnixSocketConnector* aConnector)
: DataSocketIO(aConsumerThread)
, UnixSocketWatcher(aIOLoop)
, mConnector(aConnector)
, mPeerAddressLength(0)
{
MOZ_ASSERT(mConnector);
}
ConnectionOrientedSocketIO::~ConnectionOrientedSocketIO()
{ }
nsresult
ConnectionOrientedSocketIO::Accept(int aFd,
const struct sockaddr* aPeerAddress,
socklen_t aPeerAddressLength)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTING);
SetSocket(aFd, SOCKET_IS_CONNECTED);
// Address setup
mPeerAddressLength = aPeerAddressLength;
memcpy(&mPeerAddress, aPeerAddress, mPeerAddressLength);
// Signal success and start data transfer
OnConnected();
return NS_OK;
}
nsresult
ConnectionOrientedSocketIO::Connect()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(!IsOpen());
struct sockaddr* peerAddress =
reinterpret_cast<struct sockaddr*>(&mPeerAddress);
mPeerAddressLength = sizeof(mPeerAddress);
int fd;
nsresult rv = mConnector->CreateStreamSocket(peerAddress,
&mPeerAddressLength,
fd);
if (NS_FAILED(rv)) {
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
return NS_ERROR_FAILURE;
}
SetFd(fd);
// calls OnConnected() on success, or OnError() otherwise
rv = UnixSocketWatcher::Connect(peerAddress, mPeerAddressLength);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
void
ConnectionOrientedSocketIO::Send(UnixSocketIOBuffer* aBuffer)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
EnqueueData(aBuffer);
AddWatchers(WRITE_WATCHER, false);
}
// |UnixSocketWatcher|
void
ConnectionOrientedSocketIO::OnSocketCanReceiveWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
ssize_t res = ReceiveData(GetFd());
if (res < 0) {
/* I/O error */
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
} else if (!res) {
/* EOF or peer shutdown */
RemoveWatchers(READ_WATCHER);
}
}
void
ConnectionOrientedSocketIO::OnSocketCanSendWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
MOZ_ASSERT(!IsShutdownOnIOThread());
nsresult rv = SendPendingData(GetFd());
if (NS_FAILED(rv)) {
return;
}
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
ConnectionOrientedSocketIO::OnConnected()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
ConnectionOrientedSocketIO::OnListening()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
NS_NOTREACHED("Invalid call to |ConnectionOrientedSocketIO::OnListening|");
}
void
ConnectionOrientedSocketIO::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
UnixFdWatcher::OnError(aFunction, aErrno);
// Clean up watchers, status, fd
Close();
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
}
//
// ConnectionOrientedSocket
//

View File

@ -9,6 +9,7 @@
#include <sys/socket.h>
#include "DataSocket.h"
#include "mozilla/ipc/UnixSocketWatcher.h"
class MessageLoop;
@ -23,15 +24,72 @@ class UnixSocketConnector;
* |ListenSocket| uses these classes to handle accepted sockets.
*/
class ConnectionOrientedSocketIO : public DataSocketIO
class ConnectionOrientedSocketIO
: public DataSocketIO
, public UnixSocketWatcher
{
public:
ConnectionOrientedSocketIO(nsIThread* aConsumerThread);
virtual ~ConnectionOrientedSocketIO();
virtual nsresult Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength) = 0;
nsresult Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength);
nsresult Connect();
void Send(UnixSocketIOBuffer* aBuffer);
// Methods for |UnixSocketWatcher|
//
void OnSocketCanReceiveWithoutBlocking() final;
void OnSocketCanSendWithoutBlocking() final;
void OnListening() final;
void OnConnected() final;
void OnError(const char* aFunction, int aErrno) final;
protected:
/**
* Constructs an instance of |ConnectionOrientedSocketIO|
*
* @param aConsumerThread The socket's consumer thread.
* @param aIOLoop The socket's I/O loop.
* @param aFd The socket file descriptor.
* @param aConnectionStatus The connection status for |aFd|.
* @param aConnector Connector object for socket-type-specific methods.
*/
ConnectionOrientedSocketIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
int aFd, ConnectionStatus aConnectionStatus,
UnixSocketConnector* aConnector);
/**
* Constructs an instance of |ConnectionOrientedSocketIO|
*
* @param aConsumerThread The socket's consumer thread.
* @param aIOLoop The socket's I/O loop.
* @param aConnector Connector object for socket-type-specific methods.
*/
ConnectionOrientedSocketIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
UnixSocketConnector* aConnector);
private:
/**
* Connector object used to create the connection we are currently using.
*/
nsAutoPtr<UnixSocketConnector> mConnector;
/**
* Number of valid bytes in |mPeerAddress|.
*/
socklen_t mPeerAddressLength;
/**
* Address of the socket's current peer.
*/
struct sockaddr_storage mPeerAddress;
};
class ConnectionOrientedSocket : public DataSocket

View File

@ -20,9 +20,7 @@ namespace ipc {
// StreamSocketIO
//
class StreamSocketIO final
: public UnixSocketWatcher
, public ConnectionOrientedSocketIO
class StreamSocketIO final : public ConnectionOrientedSocketIO
{
public:
class ConnectTask;
@ -50,32 +48,6 @@ public:
void ClearDelayedConnectTask();
void CancelDelayedConnectTask();
// Task callback methods
//
/**
* Connect to a socket
*/
void Connect();
void Send(UnixSocketIOBuffer* aBuffer);
// I/O callback methods
//
void OnConnected() override;
void OnError(const char* aFunction, int aErrno) override;
void OnListening() override;
void OnSocketCanReceiveWithoutBlocking() override;
void OnSocketCanSendWithoutBlocking() override;
// Methods for |ConnectionOrientedSocketIO|
//
nsresult Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength) override;
// Methods for |DataSocket|
//
@ -95,8 +67,6 @@ public:
void ShutdownOnIOThread() override;
private:
void FireSocketError();
/**
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
* directly from consumer thread. All non-consumer-thread accesses should
@ -104,26 +74,11 @@ private:
*/
RefPtr<StreamSocket> mStreamSocket;
/**
* Connector object used to create the connection we are currently using.
*/
nsAutoPtr<UnixSocketConnector> mConnector;
/**
* If true, do not requeue whatever task we're running
*/
bool mShuttingDownOnIOThread;
/**
* Number of valid bytes in |mAddress|
*/
socklen_t mAddressLength;
/**
* Address structure of the socket currently in use
*/
struct sockaddr_storage mAddress;
/**
* Task member for delayed connect task. Should only be access on consumer
* thread.
@ -140,16 +95,12 @@ StreamSocketIO::StreamSocketIO(nsIThread* aConsumerThread,
MessageLoop* aIOLoop,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector)
: UnixSocketWatcher(aIOLoop)
, ConnectionOrientedSocketIO(aConsumerThread)
: ConnectionOrientedSocketIO(aConsumerThread, aIOLoop, aConnector)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddressLength(0)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_ASSERT(mConnector);
}
StreamSocketIO::StreamSocketIO(nsIThread* aConsumerThread,
@ -157,16 +108,16 @@ StreamSocketIO::StreamSocketIO(nsIThread* aConsumerThread,
int aFd, ConnectionStatus aConnectionStatus,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector)
: UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus)
, ConnectionOrientedSocketIO(aConsumerThread)
: ConnectionOrientedSocketIO(aConsumerThread,
aIOLoop,
aFd,
aConnectionStatus,
aConnector)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddressLength(0)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_ASSERT(mConnector);
}
StreamSocketIO::~StreamSocketIO()
@ -216,145 +167,6 @@ StreamSocketIO::CancelDelayedConnectTask()
ClearDelayedConnectTask();
}
void
StreamSocketIO::Connect()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(mConnector);
MOZ_ASSERT(!IsOpen());
struct sockaddr* address = reinterpret_cast<struct sockaddr*>(&mAddress);
mAddressLength = sizeof(mAddress);
int fd;
nsresult rv = mConnector->CreateStreamSocket(address, &mAddressLength, fd);
if (NS_FAILED(rv)) {
FireSocketError();
return;
}
SetFd(fd);
// calls OnConnected() on success, or OnError() otherwise
rv = UnixSocketWatcher::Connect(address, mAddressLength);
NS_WARN_IF(NS_FAILED(rv));
}
void
StreamSocketIO::Send(UnixSocketIOBuffer* aData)
{
EnqueueData(aData);
AddWatchers(WRITE_WATCHER, false);
}
void
StreamSocketIO::OnConnected()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
StreamSocketIO::OnListening()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
NS_NOTREACHED("Invalid call to |StreamSocketIO::OnListening|");
}
void
StreamSocketIO::OnError(const char* aFunction, int aErrno)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
UnixFdWatcher::OnError(aFunction, aErrno);
FireSocketError();
}
void
StreamSocketIO::OnSocketCanReceiveWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
ssize_t res = ReceiveData(GetFd());
if (res < 0) {
/* I/O error */
RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
} else if (!res) {
/* EOF or peer shutdown */
RemoveWatchers(READ_WATCHER);
}
}
void
StreamSocketIO::OnSocketCanSendWithoutBlocking()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); // see bug 990984
nsresult rv = SendPendingData(GetFd());
if (NS_FAILED(rv)) {
return;
}
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
}
void
StreamSocketIO::FireSocketError()
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
// Clean up watchers, statuses, fds
Close();
// Tell the consumer thread we've errored
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR),
NS_DISPATCH_NORMAL);
}
// |ConnectionOrientedSocketIO|
nsresult
StreamSocketIO::Accept(int aFd,
const struct sockaddr* aAddress,
socklen_t aAddressLength)
{
MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTING);
SetSocket(aFd, SOCKET_IS_CONNECTED);
// Address setup
mAddressLength = aAddressLength;
memcpy(&mAddress, aAddress, mAddressLength);
// Signal success
GetConsumerThread()->Dispatch(
new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS),
NS_DISPATCH_NORMAL);
AddWatchers(READ_WATCHER, true);
if (HasPendingData()) {
AddWatchers(WRITE_WATCHER, false);
}
return NS_OK;
}
// |DataSocketIO|
nsresult

View File

@ -213,6 +213,7 @@
@BINPATH@/components/necko_file.xpt
@BINPATH@/components/necko_ftp.xpt
@BINPATH@/components/necko_http.xpt
@BINPATH@/components/necko_mdns.xpt
@BINPATH@/components/necko_res.xpt
@BINPATH@/components/necko_socket.xpt
@BINPATH@/components/necko_strconv.xpt

View File

@ -0,0 +1,665 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "MDNSResponderOperator.h"
#include "MDNSResponderReply.h"
#include "mozilla/Endian.h"
#include "mozilla/Logging.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsDNSServiceInfo.h"
#include "nsHashPropertyBag.h"
#include "nsIProperty.h"
#include "nsISimpleEnumerator.h"
#include "nsIVariant.h"
#include "nsServiceManagerUtils.h"
#include "nsNetCID.h"
#include "nsSocketTransportService2.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCID.h"
#include "private/pprio.h"
#include "nsASocketHandler.h"
inline PRLogModuleInfo*
GetOperatorLog()
{
static PRLogModuleInfo* log = PR_NewLogModule("MDNSResponderOperator");
return log;
}
#undef LOG_I
#define LOG_I(...) PR_LOG(GetOperatorLog(), PR_LOG_NOTICE, (__VA_ARGS__))
#undef LOG_E
#define LOG_E(...) PR_LOG(GetOperatorLog(), PR_LOG_ERROR, (__VA_ARGS__))
namespace mozilla {
namespace net {
class MDNSResponderOperator::ServiceWatcher final
: public nsASocketHandler
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
// nsASocketHandler methods
virtual void OnSocketReady(PRFileDesc* fd, int16_t outFlags) override
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(fd == mFD);
if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL)) {
LOG_E("error polling on listening socket (%p)", fd);
mCondition = NS_ERROR_UNEXPECTED;
}
if (!(outFlags & PR_POLL_READ)) {
return;
}
DNSServiceProcessResult(mService);
}
virtual void OnSocketDetached(PRFileDesc *fd) override
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(fd == mFD);
if (!mFD) {
return;
}
PR_Close(mFD);
mFD = nullptr;
}
virtual void IsLocal(bool *aIsLocal) override { *aIsLocal = true; }
virtual void KeepWhenOffline(bool *aKeepWhenOffline) override
{
*aKeepWhenOffline = true;
}
virtual uint64_t ByteCountSent() override { return 0; }
virtual uint64_t ByteCountReceived() override { return 0; }
explicit ServiceWatcher(DNSServiceRef aService)
: mSts(nullptr)
, mService(aService)
, mFD(nullptr)
, mAttached(false)
{
if (!gSocketTransportService)
{
nsCOMPtr<nsISocketTransportService> sts =
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
}
}
nsresult Init()
{
MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread);
if (!mService) {
return NS_OK;
}
if (!gSocketTransportService) {
return NS_ERROR_FAILURE;
}
mSts = gSocketTransportService;
int osfd = DNSServiceRefSockFD(mService);
if (osfd == -1) {
return NS_ERROR_FAILURE;
}
mFD = PR_ImportFile(osfd);
return PostEvent(&ServiceWatcher::OnMsgAttach);
}
void Close()
{
MOZ_ASSERT(PR_GetCurrentThread() != gSocketThread);
if (mService) {
DNSServiceRefDeallocate(mService);
mService = nullptr;
}
if (!gSocketTransportService) {
return;
}
PostEvent(&ServiceWatcher::OnMsgClose);
}
private:
~ServiceWatcher() = default;
nsresult PostEvent(void(ServiceWatcher::*func)(void))
{
nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, func);
return gSocketTransportService->Dispatch(ev, NS_DISPATCH_NORMAL);
}
void OnMsgClose()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (NS_FAILED(mCondition)) {
return;
}
// tear down socket. this signals the STS to detach our socket handler.
mCondition = NS_BINDING_ABORTED;
// if we are attached, then socket transport service will call our
// OnSocketDetached method automatically. Otherwise, we have to call it
// (and thus close the socket) manually.
if (!mAttached) {
OnSocketDetached(mFD);
}
}
void OnMsgAttach()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (NS_FAILED(mCondition)) {
return;
}
mCondition = TryAttach();
// if we hit an error while trying to attach then bail...
if (NS_FAILED(mCondition)) {
NS_ASSERTION(!mAttached, "should not be attached already");
OnSocketDetached(mFD);
}
}
nsresult TryAttach()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsresult rv;
if (!gSocketTransportService) {
return NS_ERROR_FAILURE;
}
//
// find out if it is going to be ok to attach another socket to the STS.
// if not then we have to wait for the STS to tell us that it is ok.
// the notification is asynchronous, which means that when we could be
// in a race to call AttachSocket once notified. for this reason, when
// we get notified, we just re-enter this function. as a result, we are
// sure to ask again before calling AttachSocket. in this way we deal
// with the race condition. though it isn't the most elegant solution,
// it is far simpler than trying to build a system that would guarantee
// FIFO ordering (which wouldn't even be that valuable IMO). see bug
// 194402 for more info.
//
if (!gSocketTransportService->CanAttachSocket()) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach);
nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event);
if (NS_FAILED(rv)) {
return rv;
}
}
//
// ok, we can now attach our socket to the STS for polling
//
rv = gSocketTransportService->AttachSocket(mFD, this);
if (NS_FAILED(rv)) {
return rv;
}
mAttached = true;
//
// now, configure our poll flags for listening...
//
mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
return NS_OK;
}
nsRefPtr<nsSocketTransportService> mSts;
DNSServiceRef mService;
PRFileDesc* mFD;
bool mAttached;
};
NS_IMPL_ISUPPORTS(MDNSResponderOperator::ServiceWatcher, nsISupports)
MDNSResponderOperator::MDNSResponderOperator()
: mService(nullptr)
, mWatcher(nullptr)
, mThread(NS_GetCurrentThread())
, mIsCancelled(false)
{
}
MDNSResponderOperator::~MDNSResponderOperator()
{
Stop();
}
nsresult
MDNSResponderOperator::Start()
{
if (mIsCancelled) {
return NS_OK;
}
if (IsServing()) {
Stop();
}
return NS_OK;
}
nsresult
MDNSResponderOperator::Stop()
{
mThread = nullptr;
return ResetService(nullptr);
}
nsresult
MDNSResponderOperator::ResetService(DNSServiceRef aService)
{
nsresult rv;
if (aService != mService) {
if (mWatcher) {
mWatcher->Close();
mWatcher = nullptr;
}
if (aService) {
nsRefPtr<ServiceWatcher> watcher = new ServiceWatcher(aService);
if (NS_WARN_IF(NS_FAILED(watcher->Init()))) {
return rv;
}
mWatcher = watcher;
}
mService = aService;
}
return NS_OK;
}
BrowseOperator::BrowseOperator(const nsACString& aServiceType,
nsIDNSServiceDiscoveryListener* aListener)
: MDNSResponderOperator()
, mServiceType(aServiceType)
, mListener(aListener)
{
}
nsresult
BrowseOperator::Start()
{
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) {
return rv;
}
DNSServiceRef service = nullptr;
DNSServiceErrorType err = DNSServiceBrowse(&service,
0,
kDNSServiceInterfaceIndexAny,
mServiceType.get(),
nullptr,
&BrowseReplyRunnable::Reply,
this);
NS_WARN_IF(kDNSServiceErr_NoError != err);
if (mListener) {
if (kDNSServiceErr_NoError == err) {
mListener->OnDiscoveryStarted(mServiceType);
} else {
mListener->OnStartDiscoveryFailed(mServiceType, err);
}
}
if (NS_WARN_IF(kDNSServiceErr_NoError != err)) {
return NS_ERROR_FAILURE;
}
return ResetService(service);
}
nsresult
BrowseOperator::Stop()
{
bool isServing = IsServing();
nsresult rv = MDNSResponderOperator::Stop();
if (isServing && mListener) {
if (NS_SUCCEEDED(rv)) {
mListener->OnDiscoveryStopped(mServiceType);
} else {
mListener->OnStopDiscoveryFailed(mServiceType,
static_cast<uint32_t>(rv));
}
}
return rv;
}
void
BrowseOperator::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aServiceName,
const nsACString& aRegType,
const nsACString& aReplyDomain)
{
MOZ_ASSERT(GetThread() == NS_GetCurrentThread());
if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) {
LOG_E("BrowseOperator::Reply (%d)", aErrorCode);
if (mListener) {
mListener->OnStartDiscoveryFailed(mServiceType, aErrorCode);
}
return;
}
if (!mListener) { return; }
nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo();
if (NS_WARN_IF(!info)) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aServiceName)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aReplyDomain)))) { return; }
if (aFlags & kDNSServiceFlagsAdd) {
mListener->OnServiceFound(info);
} else {
mListener->OnServiceLost(info);
}
}
RegisterOperator::RegisterOperator(nsIDNSServiceInfo* aServiceInfo,
nsIDNSRegistrationListener* aListener)
: MDNSResponderOperator()
, mServiceInfo(aServiceInfo)
, mListener(aListener)
{
}
nsresult
RegisterOperator::Start()
{
nsresult rv;
rv = MDNSResponderOperator::Start();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
uint16_t port;
if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetPort(&port)))) {
return rv;
}
nsAutoCString type;
if (NS_WARN_IF(NS_FAILED(rv = mServiceInfo->GetServiceType(type)))) {
return rv;
}
TXTRecordRef txtRecord;
char buf[TXT_BUFFER_SIZE] = { 0 };
TXTRecordCreate(&txtRecord, TXT_BUFFER_SIZE, buf);
nsCOMPtr<nsIPropertyBag2> attributes;
if (NS_FAILED(rv = mServiceInfo->GetAttributes(getter_AddRefs(attributes)))) {
LOG_I("register: no attributes");
} else {
nsCOMPtr<nsISimpleEnumerator> enumerator;
if (NS_WARN_IF(NS_FAILED(rv =
attributes->GetEnumerator(getter_AddRefs(enumerator))))) {
return rv;
}
bool hasMoreElements;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
hasMoreElements) {
nsCOMPtr<nsISupports> element;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(element))));
nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
MOZ_ASSERT(property);
nsAutoString name;
nsCOMPtr<nsIVariant> value;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(property->GetName(name)));
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(property->GetValue(getter_AddRefs(value))));
nsAutoCString str;
if (NS_WARN_IF(NS_FAILED(value->GetAsACString(str)))) {
continue;
}
TXTRecordSetValue(&txtRecord,
/* it's safe because key name is ASCII only. */
NS_LossyConvertUTF16toASCII(name).get(),
str.Length(),
str.get());
}
}
nsAutoCString host;
nsAutoCString name;
nsAutoCString domain;
DNSServiceRef service = nullptr;
DNSServiceErrorType err =
DNSServiceRegister(&service,
0,
0,
NS_SUCCEEDED(mServiceInfo->GetServiceName(name)) ?
name.get() : nullptr,
type.get(),
NS_SUCCEEDED(mServiceInfo->GetDomainName(domain)) ?
domain.get() : nullptr,
NS_SUCCEEDED(mServiceInfo->GetHost(host)) ?
host.get() : nullptr,
NativeEndian::swapToNetworkOrder(port),
TXTRecordGetLength(&txtRecord),
TXTRecordGetBytesPtr(&txtRecord),
&RegisterReplyRunnable::Reply,
this);
NS_WARN_IF(kDNSServiceErr_NoError != err);
TXTRecordDeallocate(&txtRecord);
if (NS_WARN_IF(kDNSServiceErr_NoError != err)) {
if (mListener) {
mListener->OnRegistrationFailed(mServiceInfo, err);
}
return NS_ERROR_FAILURE;
}
return ResetService(service);
}
nsresult
RegisterOperator::Stop()
{
bool isServing = IsServing();
nsresult rv = MDNSResponderOperator::Stop();
if (isServing && mListener) {
if (NS_SUCCEEDED(rv)) {
mListener->OnServiceUnregistered(mServiceInfo);
} else {
mListener->OnUnregistrationFailed(mServiceInfo,
static_cast<uint32_t>(rv));
}
}
return rv;
}
void
RegisterOperator::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const nsACString& aName,
const nsACString& aRegType,
const nsACString& aDomain)
{
MOZ_ASSERT(GetThread() == NS_GetCurrentThread());
if (kDNSServiceErr_NoError != aErrorCode) {
LOG_E("RegisterOperator::Reply (%d)", aErrorCode);
}
if (!mListener) { return; }
nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo);
if (NS_WARN_IF(NS_FAILED(info->SetServiceName(aName)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetServiceType(aRegType)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetDomainName(aDomain)))) { return; }
if (kDNSServiceErr_NoError == aErrorCode) {
mListener->OnServiceRegistered(info);
} else {
mListener->OnRegistrationFailed(info, aErrorCode);
}
}
ResolveOperator::ResolveOperator(nsIDNSServiceInfo* aServiceInfo,
nsIDNSServiceResolveListener* aListener)
: MDNSResponderOperator()
, mServiceInfo(aServiceInfo)
, mListener(aListener)
, mDeleteProtector()
{
}
nsresult
ResolveOperator::Start()
{
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = MDNSResponderOperator::Start()))) {
return rv;
}
nsAutoCString name;
mServiceInfo->GetServiceName(name);
nsAutoCString type;
mServiceInfo->GetServiceType(type);
nsAutoCString domain;
mServiceInfo->GetDomainName(domain);
LOG_I("Resolve: (%s), (%s), (%s)", name.get(), type.get(), domain.get());
DNSServiceRef service = nullptr;
DNSServiceErrorType err =
DNSServiceResolve(&service,
0,
kDNSServiceInterfaceIndexAny,
name.get(),
type.get(),
domain.get(),
(DNSServiceResolveReply)&ResolveReplyRunnable::Reply,
this);
if (NS_WARN_IF(kDNSServiceErr_NoError != err)) {
if (mListener) {
mListener->OnResolveFailed(mServiceInfo, err);
}
return NS_ERROR_FAILURE;
}
mDeleteProtector = this;
return ResetService(service);
}
nsresult
ResolveOperator::Stop()
{
nsresult rv = MDNSResponderOperator::Stop();
return rv;
}
void
ResolveOperator::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aFullName,
const nsACString& aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord)
{
MOZ_ASSERT(GetThread() == NS_GetCurrentThread());
mDeleteProtector = nullptr;
if (NS_WARN_IF(kDNSServiceErr_NoError != aErrorCode)) {
LOG_E("ResolveOperator::Reply (%d)", aErrorCode);
return;
}
// Resolve TXT record
int count = TXTRecordGetCount(aTxtLen, aTxtRecord);
LOG_I("resolve: txt count = %d, len = %d", count, aTxtLen);
nsCOMPtr<nsIWritablePropertyBag2> attributes = nullptr;
if (count) {
attributes = new nsHashPropertyBag();
if (NS_WARN_IF(!attributes)) { return; }
for (int i = 0; i < count; ++i) {
char key[TXT_BUFFER_SIZE] = { '\0' };
uint8_t vSize = 0;
const void* value = nullptr;
if (kDNSServiceErr_NoError !=
TXTRecordGetItemAtIndex(aTxtLen,
aTxtRecord,
i,
TXT_BUFFER_SIZE,
key,
&vSize,
&value)) {
break;
}
nsAutoCString str(reinterpret_cast<const char*>(value), vSize);
LOG_I("resolve TXT: (%d) %s=%s", vSize, key, str.get());
if (NS_WARN_IF(NS_FAILED(attributes->SetPropertyAsACString(
/* it's safe to convert because key name is ASCII only. */
NS_ConvertASCIItoUTF16(key),
str)))) {
break;
}
}
}
if (!mListener) { return; }
nsCOMPtr<nsIDNSServiceInfo> info = new nsDNSServiceInfo(mServiceInfo);
if (NS_WARN_IF(NS_FAILED(info->SetHost(aHostTarget)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetPort(aPort)))) { return; }
if (NS_WARN_IF(NS_FAILED(info->SetAttributes(attributes)))) { return; }
if (kDNSServiceErr_NoError == aErrorCode) {
mListener->OnServiceResolved(info);
} else {
mListener->OnResolveFailed(info, aErrorCode);
}
NS_WARN_IF(NS_FAILED(Stop()));
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,139 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h
#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h
#include "dns_sd.h"
#include "mozilla/Atomics.h"
#include "nsCOMPtr.h"
#include "nsIDNSServiceDiscovery.h"
#include "nsIThread.h"
#include "nsRefPtr.h"
#include "nsString.h"
namespace mozilla {
namespace net {
class MDNSResponderOperator
{
public:
MDNSResponderOperator();
virtual nsresult Start();
virtual nsresult Stop();
void Cancel() { mIsCancelled = true; }
nsIThread* GetThread() const { return mThread; }
protected:
virtual ~MDNSResponderOperator();
bool IsServing() const { return mService; }
nsresult ResetService(DNSServiceRef aService);
private:
class ServiceWatcher;
DNSServiceRef mService;
nsRefPtr<ServiceWatcher> mWatcher;
nsCOMPtr<nsIThread> mThread; // remember caller thread for callback
Atomic<bool> mIsCancelled;
};
class BrowseOperator final : private MDNSResponderOperator
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BrowseOperator)
BrowseOperator(const nsACString& aServiceType,
nsIDNSServiceDiscoveryListener* aListener);
nsresult Start() override;
nsresult Stop() override;
using MDNSResponderOperator::Cancel;
using MDNSResponderOperator::GetThread;
void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aServiceName,
const nsACString& aRegType,
const nsACString& aReplyDomain);
private:
~BrowseOperator() = default;
nsCString mServiceType;
nsCOMPtr<nsIDNSServiceDiscoveryListener> mListener;
};
class RegisterOperator final : private MDNSResponderOperator
{
enum { TXT_BUFFER_SIZE = 256 };
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RegisterOperator)
RegisterOperator(nsIDNSServiceInfo* aServiceInfo,
nsIDNSRegistrationListener* aListener);
nsresult Start() override;
nsresult Stop() override;
using MDNSResponderOperator::Cancel;
using MDNSResponderOperator::GetThread;
void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const nsACString& aName,
const nsACString& aRegType,
const nsACString& aDomain);
private:
~RegisterOperator() = default;
nsCOMPtr<nsIDNSServiceInfo> mServiceInfo;
nsCOMPtr<nsIDNSRegistrationListener> mListener;
};
class ResolveOperator final : private MDNSResponderOperator
{
enum { TXT_BUFFER_SIZE = 256 };
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ResolveOperator)
ResolveOperator(nsIDNSServiceInfo* aServiceInfo,
nsIDNSServiceResolveListener* aListener);
nsresult Start() override;
nsresult Stop() override;
using MDNSResponderOperator::GetThread;
void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aFullName,
const nsACString& aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord);
private:
~ResolveOperator() = default;
nsCOMPtr<nsIDNSServiceInfo> mServiceInfo;
nsCOMPtr<nsIDNSServiceResolveListener> mListener;
// hold self until callback is made.
nsRefPtr<ResolveOperator> mDeleteProtector;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderOperator_h

View File

@ -0,0 +1,225 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "MDNSResponderReply.h"
#include "mozilla/Endian.h"
#include "private/pprio.h"
namespace mozilla {
namespace net {
BrowseReplyRunnable::BrowseReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aServiceName,
const nsACString& aRegType,
const nsACString& aReplyDomain,
BrowseOperator* aContext)
: mSdRef(aSdRef)
, mFlags(aFlags)
, mInterfaceIndex(aInterfaceIndex)
, mErrorCode(aErrorCode)
, mServiceName(aServiceName)
, mRegType(aRegType)
, mReplyDomain(aReplyDomain)
, mContext(aContext)
{
}
NS_IMETHODIMP
BrowseReplyRunnable::Run()
{
MOZ_ASSERT(mContext);
mContext->Reply(mSdRef,
mFlags,
mInterfaceIndex,
mErrorCode,
mServiceName,
mRegType,
mReplyDomain);
return NS_OK;
}
void
BrowseReplyRunnable::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const char* aServiceName,
const char* aRegType,
const char* aReplyDomain,
void* aContext)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
BrowseOperator* obj(reinterpret_cast<BrowseOperator*>(aContext));
if (!obj) {
return;
}
nsCOMPtr<nsIThread> thread(obj->GetThread());
if (!thread) {
return;
}
thread->Dispatch(new BrowseReplyRunnable(aSdRef,
aFlags,
aInterfaceIndex,
aErrorCode,
nsCString(aServiceName),
nsCString(aRegType),
nsCString(aReplyDomain),
obj),
NS_DISPATCH_NORMAL);
}
RegisterReplyRunnable::RegisterReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const nsACString& aName,
const nsACString& aRegType,
const nsACString& domain,
RegisterOperator* aContext)
: mSdRef(aSdRef)
, mFlags(aFlags)
, mErrorCode(aErrorCode)
, mName(aName)
, mRegType(aRegType)
, mDomain(domain)
, mContext(aContext)
{
}
NS_IMETHODIMP
RegisterReplyRunnable::Run()
{
MOZ_ASSERT(mContext);
mContext->Reply(mSdRef,
mFlags,
mErrorCode,
mName,
mRegType,
mDomain);
return NS_OK;
}
void
RegisterReplyRunnable::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const char* aName,
const char* aRegType,
const char* domain,
void* aContext)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
RegisterOperator* obj(reinterpret_cast<RegisterOperator*>(aContext));
if (!obj) {
return;
}
nsCOMPtr<nsIThread> thread(obj->GetThread());
if (!thread) {
return;
}
thread->Dispatch(new RegisterReplyRunnable(aSdRef,
aFlags,
aErrorCode,
nsCString(aName),
nsCString(aRegType),
nsCString(domain),
obj),
NS_DISPATCH_NORMAL);
}
ResolveReplyRunnable::ResolveReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aFullName,
const nsACString& aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord,
ResolveOperator* aContext)
: mSdRef(aSdRef)
, mFlags(aFlags)
, mInterfaceIndex(aInterfaceIndex)
, mErrorCode(aErrorCode)
, mFullname(aFullName)
, mHosttarget(aHostTarget)
, mPort(aPort)
, mTxtLen(aTxtLen)
, mTxtRecord(new unsigned char[aTxtLen])
, mContext(aContext)
{
if (mTxtRecord) {
memcpy(mTxtRecord.get(), aTxtRecord, aTxtLen);
}
}
ResolveReplyRunnable::~ResolveReplyRunnable()
{
}
NS_IMETHODIMP
ResolveReplyRunnable::Run()
{
MOZ_ASSERT(mContext);
mContext->Reply(mSdRef,
mFlags,
mInterfaceIndex,
mErrorCode,
mFullname,
mHosttarget,
mPort,
mTxtLen,
mTxtRecord.get());
return NS_OK;
}
void
ResolveReplyRunnable::Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const char* aFullName,
const char* aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord,
void* aContext)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
ResolveOperator* obj(reinterpret_cast<ResolveOperator*>(aContext));
if (!obj) {
return;
}
nsCOMPtr<nsIThread> thread(obj->GetThread());
if (!thread) {
return;
}
thread->Dispatch(new ResolveReplyRunnable(aSdRef,
aFlags,
aInterfaceIndex,
aErrorCode,
nsCString(aFullName),
nsCString(aHostTarget),
NativeEndian::swapFromNetworkOrder(aPort),
aTxtLen,
aTxtRecord,
obj),
NS_DISPATCH_NORMAL);
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,128 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_netwerk_dns_mdns_libmdns_MDNSResponderReply_h
#define mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h
#include "dns_sd.h"
#include "MDNSResponderOperator.h"
#include "mozilla/UniquePtr.h"
#include "nsIThread.h"
#include "nsRefPtr.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace net {
class BrowseReplyRunnable final : public nsRunnable
{
public:
BrowseReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aServiceName,
const nsACString& aRegType,
const nsACString& aReplyDomain,
BrowseOperator* aContext);
NS_IMETHODIMP Run() override;
static void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const char* aServiceName,
const char* aRegType,
const char* aReplyDomain,
void* aContext);
private:
DNSServiceRef mSdRef;
DNSServiceFlags mFlags;
uint32_t mInterfaceIndex;
DNSServiceErrorType mErrorCode;
nsCString mServiceName;
nsCString mRegType;
nsCString mReplyDomain;
BrowseOperator* mContext;
};
class RegisterReplyRunnable final : public nsRunnable
{
public:
RegisterReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const nsACString& aName,
const nsACString& aRegType,
const nsACString& aDomain,
RegisterOperator* aContext);
NS_IMETHODIMP Run() override;
static void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
DNSServiceErrorType aErrorCode,
const char* aName,
const char* aRegType,
const char* aDomain,
void* aContext);
private:
DNSServiceRef mSdRef;
DNSServiceFlags mFlags;
DNSServiceErrorType mErrorCode;
nsCString mName;
nsCString mRegType;
nsCString mDomain;
RegisterOperator* mContext;
};
class ResolveReplyRunnable final : public nsRunnable
{
public:
ResolveReplyRunnable(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const nsACString& aFullName,
const nsACString& aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord,
ResolveOperator* aContext);
~ResolveReplyRunnable();
NS_IMETHODIMP Run() override;
static void Reply(DNSServiceRef aSdRef,
DNSServiceFlags aFlags,
uint32_t aInterfaceIndex,
DNSServiceErrorType aErrorCode,
const char* aFullName,
const char* aHostTarget,
uint16_t aPort,
uint16_t aTxtLen,
const unsigned char* aTxtRecord,
void* aContext);
private:
DNSServiceRef mSdRef;
DNSServiceFlags mFlags;
uint32_t mInterfaceIndex;
DNSServiceErrorType mErrorCode;
nsCString mFullname;
nsCString mHosttarget;
uint16_t mPort;
uint16_t mTxtLen;
UniquePtr<unsigned char> mTxtRecord;
nsRefPtr<ResolveOperator> mContext;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_netwerk_dns_mdns_libmdns_MDNSResponderReply_h

View File

@ -0,0 +1,33 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] >= '16':
UNIFIED_SOURCES += [
'MDNSResponderOperator.cpp',
'MDNSResponderReply.cpp',
'nsDNSServiceDiscovery.cpp',
]
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'external/mdnsresponder/mDNSShared',
]
]
LOCAL_INCLUDES += [
'/netwerk/base',
]
UNIFIED_SOURCES += [
'nsDNSServiceInfo.cpp',
'nsMulticastDNSModule.cpp',
]
FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,230 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsDNSServiceDiscovery.h"
#include <cutils/properties.h>
#include "MDNSResponderOperator.h"
#include "nsICancelable.h"
#include "private/pprio.h"
namespace mozilla {
namespace net {
namespace {
void
StartService()
{
char value[PROPERTY_VALUE_MAX] = { '\0' };
property_get("init.svc.mdnsd", value, "");
if (strcmp(value, "running") == 0) {
return;
}
property_set("ctl.start", "mdnsd");
}
void
StopService()
{
char value[PROPERTY_VALUE_MAX] = { '\0' };
property_get("init.svc.mdnsd", value, "");
if (strcmp(value, "stopped") == 0) {
return;
}
property_set("ctl.stop", "mdnsd");
}
class DiscoveryRequest final : public nsICancelable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICANCELABLE
explicit DiscoveryRequest(nsDNSServiceDiscovery* aService,
nsIDNSServiceDiscoveryListener* aListener);
private:
virtual ~DiscoveryRequest() { Cancel(NS_OK); }
nsRefPtr<nsDNSServiceDiscovery> mService;
nsIDNSServiceDiscoveryListener* mListener;
};
NS_IMPL_ISUPPORTS(DiscoveryRequest, nsICancelable)
DiscoveryRequest::DiscoveryRequest(nsDNSServiceDiscovery* aService,
nsIDNSServiceDiscoveryListener* aListener)
: mService(aService)
, mListener(aListener)
{
}
NS_IMETHODIMP
DiscoveryRequest::Cancel(nsresult aReason)
{
if (mService) {
mService->StopDiscovery(mListener);
}
mService = nullptr;
return NS_OK;
}
class RegisterRequest final : public nsICancelable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICANCELABLE
explicit RegisterRequest(nsDNSServiceDiscovery* aService,
nsIDNSRegistrationListener* aListener);
private:
virtual ~RegisterRequest() { Cancel(NS_OK); }
nsRefPtr<nsDNSServiceDiscovery> mService;
nsIDNSRegistrationListener* mListener;
};
NS_IMPL_ISUPPORTS(RegisterRequest, nsICancelable)
RegisterRequest::RegisterRequest(nsDNSServiceDiscovery* aService,
nsIDNSRegistrationListener* aListener)
: mService(aService)
, mListener(aListener)
{
}
NS_IMETHODIMP
RegisterRequest::Cancel(nsresult aReason)
{
if (mService) {
mService->UnregisterService(mListener);
}
mService = nullptr;
return NS_OK;
}
} // namespace anonymous
NS_IMPL_ISUPPORTS(nsDNSServiceDiscovery, nsIDNSServiceDiscovery)
nsresult
nsDNSServiceDiscovery::Init()
{
StartService();
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceDiscovery::StartDiscovery(const nsACString& aServiceType,
nsIDNSServiceDiscoveryListener* aListener,
nsICancelable** aRetVal)
{
MOZ_ASSERT(aRetVal);
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = StopDiscovery(aListener)))) {
return rv;
}
nsRefPtr<BrowseOperator> browserOp = new BrowseOperator(aServiceType,
aListener);
if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) {
return rv;
}
mDiscoveryMap.Put(aListener, browserOp);
nsCOMPtr<nsICancelable> req = new DiscoveryRequest(this, aListener);
req.forget(aRetVal);
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener)
{
nsresult rv;
nsRefPtr<BrowseOperator> browserOp;
if (!mDiscoveryMap.Get(aListener, getter_AddRefs(browserOp))) {
return NS_OK;
}
browserOp->Cancel(); // cancel non-started operation
if (NS_WARN_IF(NS_FAILED(rv = browserOp->Stop()))) {
return rv;
}
mDiscoveryMap.Remove(aListener);
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceDiscovery::RegisterService(nsIDNSServiceInfo* aServiceInfo,
nsIDNSRegistrationListener* aListener,
nsICancelable** aRetVal)
{
MOZ_ASSERT(aRetVal);
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) {
return rv;
}
nsRefPtr<RegisterOperator> registerOp = new RegisterOperator(aServiceInfo,
aListener);
if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) {
return rv;
}
mRegisterMap.Put(aListener, registerOp);
nsCOMPtr<nsICancelable> req = new RegisterRequest(this, aListener);
req.forget(aRetVal);
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener)
{
nsresult rv;
nsRefPtr<RegisterOperator> registerOp;
if (!mRegisterMap.Get(aListener, getter_AddRefs(registerOp))) {
return NS_OK;
}
registerOp->Cancel(); // cancel non-started operation
if (NS_WARN_IF(NS_FAILED(rv = registerOp->Stop()))) {
return rv;
}
mRegisterMap.Remove(aListener);
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo,
nsIDNSServiceResolveListener* aListener)
{
nsresult rv;
nsRefPtr<ResolveOperator> resolveOp = new ResolveOperator(aServiceInfo,
aListener);
if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) {
return rv;
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h
#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h
#include "nsIDNSServiceDiscovery.h"
#include "nsCOMPtr.h"
#include "nsRefPtr.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace net {
class BrowseOperator;
class RegisterOperator;
class nsDNSServiceDiscovery final : public nsIDNSServiceDiscovery
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSSERVICEDISCOVERY
explicit nsDNSServiceDiscovery() = default;
/*
** The mDNS service is started in this function. However, the function returns
** without waiting. Therefore, all operations before service started will fail
** and get error code |kDNSServiceErr_ServiceNotRunning| defined in dns_sd.h.
**/
nsresult Init();
nsresult StopDiscovery(nsIDNSServiceDiscoveryListener* aListener);
nsresult UnregisterService(nsIDNSRegistrationListener* aListener);
private:
virtual ~nsDNSServiceDiscovery() = default;
nsRefPtrHashtable<nsISupportsHashKey, BrowseOperator> mDiscoveryMap;
nsRefPtrHashtable<nsISupportsHashKey, RegisterOperator> mRegisterMap;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceDiscovery_h

View File

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsDNSServiceInfo.h"
#include "nsHashPropertyBag.h"
#include "nsIProperty.h"
#include "nsISimpleEnumerator.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(nsDNSServiceInfo, nsIDNSServiceInfo)
nsDNSServiceInfo::nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo)
{
if (NS_WARN_IF(!aServiceInfo)) {
return;
}
nsAutoCString str;
uint16_t value;
if (NS_SUCCEEDED(aServiceInfo->GetHost(str))) {
NS_WARN_IF(NS_FAILED(SetHost(str)));
}
if (NS_SUCCEEDED(aServiceInfo->GetPort(&value))) {
NS_WARN_IF(NS_FAILED(SetPort(value)));
}
if (NS_SUCCEEDED(aServiceInfo->GetServiceName(str))) {
NS_WARN_IF(NS_FAILED(SetServiceName(str)));
}
if (NS_SUCCEEDED(aServiceInfo->GetServiceType(str))) {
NS_WARN_IF(NS_FAILED(SetServiceType(str)));
}
if (NS_SUCCEEDED(aServiceInfo->GetDomainName(str))) {
NS_WARN_IF(NS_FAILED(SetDomainName(str)));
}
nsCOMPtr<nsIPropertyBag2> attributes; // deep copy
if (NS_SUCCEEDED(aServiceInfo->GetAttributes(getter_AddRefs(attributes)))) {
nsCOMPtr<nsISimpleEnumerator> enumerator;
if (NS_WARN_IF(NS_FAILED(attributes->GetEnumerator(getter_AddRefs(enumerator))))) {
return;
}
nsCOMPtr<nsIWritablePropertyBag2> newAttributes = new nsHashPropertyBag();
bool hasMoreElements;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
hasMoreElements) {
nsCOMPtr<nsISupports> element;
NS_WARN_IF(NS_FAILED(enumerator->GetNext(getter_AddRefs(element))));
nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
MOZ_ASSERT(property);
nsAutoString name;
nsCOMPtr<nsIVariant> value;
NS_WARN_IF(NS_FAILED(property->GetName(name)));
NS_WARN_IF(NS_FAILED(property->GetValue(getter_AddRefs(value))));
NS_WARN_IF(NS_FAILED(newAttributes->SetPropertyAsInterface(name, value)));
}
NS_WARN_IF(NS_FAILED(SetAttributes(newAttributes)));
}
}
NS_IMETHODIMP
nsDNSServiceInfo::GetHost(nsACString& aHost)
{
if (!mIsHostSet) {
return NS_ERROR_NOT_INITIALIZED;
}
aHost = mHost;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetHost(const nsACString& aHost)
{
mHost = aHost;
mIsHostSet = true;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::GetPort(uint16_t* aPort)
{
if (NS_WARN_IF(!aPort)) {
return NS_ERROR_INVALID_ARG;
}
if (!mIsPortSet) {
return NS_ERROR_NOT_INITIALIZED;
}
*aPort = mPort;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetPort(uint16_t aPort)
{
mPort = aPort;
mIsPortSet = true;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::GetServiceName(nsACString& aServiceName)
{
if (!mIsServiceNameSet) {
return NS_ERROR_NOT_INITIALIZED;
}
aServiceName = mServiceName;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetServiceName(const nsACString& aServiceName)
{
mServiceName = aServiceName;
mIsServiceNameSet = true;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::GetServiceType(nsACString& aServiceType)
{
if (!mIsServiceTypeSet) {
return NS_ERROR_NOT_INITIALIZED;
}
aServiceType = mServiceType;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetServiceType(const nsACString& aServiceType)
{
mServiceType = aServiceType;
mIsServiceTypeSet = true;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::GetDomainName(nsACString& aDomainName)
{
if (!mIsDomainNameSet) {
return NS_ERROR_NOT_INITIALIZED;
}
aDomainName = mDomainName;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetDomainName(const nsACString& aDomainName)
{
mDomainName = aDomainName;
mIsDomainNameSet = true;
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::GetAttributes(nsIPropertyBag2** aAttributes)
{
if (!mIsAttributesSet) {
return NS_ERROR_NOT_INITIALIZED;
}
nsCOMPtr<nsIPropertyBag2> attributes(mAttributes);
attributes.forget(aAttributes);
return NS_OK;
}
NS_IMETHODIMP
nsDNSServiceInfo::SetAttributes(nsIPropertyBag2* aAttributes)
{
mAttributes = aAttributes;
mIsAttributesSet = true;
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h
#define mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h
#include "nsCOMPtr.h"
#include "nsIDNSServiceDiscovery.h"
#include "nsIPropertyBag2.h"
#include "nsString.h"
namespace mozilla {
namespace net {
class nsDNSServiceInfo final : public nsIDNSServiceInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDNSSERVICEINFO
explicit nsDNSServiceInfo() = default;
explicit nsDNSServiceInfo(nsIDNSServiceInfo* aServiceInfo);
private:
virtual ~nsDNSServiceInfo() = default;
private:
nsCString mHost;
uint16_t mPort = 0;
nsCString mServiceName;
nsCString mServiceType;
nsCString mDomainName;
nsCOMPtr<nsIPropertyBag2> mAttributes;
bool mIsHostSet = false;
bool mIsPortSet = false;
bool mIsServiceNameSet = false;
bool mIsServiceTypeSet = false;
bool mIsDomainNameSet = false;
bool mIsAttributesSet = false;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_netwerk_dns_mdns_libmdns_nsDNSServiceInfo_h

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16
#define ENABLE_DNS_SERVICE_DISCOVERY
#endif
#include "mozilla/ModuleUtils.h"
#ifdef ENABLE_DNS_SERVICE_DISCOVERY
#include "nsDNSServiceDiscovery.h"
#endif
#include "nsDNSServiceInfo.h"
#ifdef ENABLE_DNS_SERVICE_DISCOVERY
using mozilla::net::nsDNSServiceDiscovery;
#define DNSSERVICEDISCOVERY_CID \
{0x8df43d23, 0xd3f9, 0x4dd5, \
{ 0xb9, 0x65, 0xde, 0x2c, 0xa3, 0xf6, 0xa4, 0x2c }}
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDNSServiceDiscovery, Init)
NS_DEFINE_NAMED_CID(DNSSERVICEDISCOVERY_CID);
#endif // ENABLE_DNS_SERVICE_DISCOVERY
using mozilla::net::nsDNSServiceInfo;
#define DNSSERVICEINFO_CID \
{0x14a50f2b, 0x7ff6, 0x48a5, \
{ 0x88, 0xe3, 0x61, 0x5f, 0xd1, 0x11, 0xf5, 0xd3 }}
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDNSServiceInfo)
NS_DEFINE_NAMED_CID(DNSSERVICEINFO_CID);
static const mozilla::Module::CIDEntry knsDNSServiceDiscoveryCIDs[] = {
#ifdef ENABLE_DNS_SERVICE_DISCOVERY
{ &kDNSSERVICEDISCOVERY_CID, false, nullptr, nsDNSServiceDiscoveryConstructor },
#endif
{ &kDNSSERVICEINFO_CID, false, nullptr, nsDNSServiceInfoConstructor },
{ nullptr }
};
static const mozilla::Module::ContractIDEntry knsDNSServiceDiscoveryContracts[] = {
#ifdef ENABLE_DNS_SERVICE_DISCOVERY
{ DNSSERVICEDISCOVERY_CONTRACT_ID, &kDNSSERVICEDISCOVERY_CID },
#endif
{ DNSSERVICEINFO_CONTRACT_ID, &kDNSSERVICEINFO_CID },
{ nullptr }
};
static const mozilla::Module::CategoryEntry knsDNSServiceDiscoveryCategories[] = {
{ nullptr }
};
static const mozilla::Module knsDNSServiceDiscoveryModule = {
mozilla::Module::kVersion,
knsDNSServiceDiscoveryCIDs,
knsDNSServiceDiscoveryContracts,
knsDNSServiceDiscoveryCategories
};
NSMODULE_DEFN(nsDNSServiceDiscoveryModule) = &knsDNSServiceDiscoveryModule;

View File

@ -0,0 +1,13 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['libmdns']
XPIDL_SOURCES += [
'nsIDNSServiceDiscovery.idl',
]
XPIDL_MODULE = 'necko_mdns'

View File

@ -0,0 +1,213 @@
/* 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 "nsISupports.idl"
interface nsICancelable;
interface nsIPropertyBag2;
/**
* Service information
*/
[scriptable, uuid(112bfa89-1b57-4acf-8287-48e5466c1b39)]
interface nsIDNSServiceInfo : nsISupports
{
/**
* The host name of the service. (E.g. "Android.local.")
* @throws NS_ERROR_NOT_INITIALIZED when getting unset value.
*/
attribute AUTF8String host;
/**
* The port number of the service. (E.g. 80)
* @throws NS_ERROR_NOT_INITIALIZED when getting unset value.
*/
attribute unsigned short port;
/**
* The service name of the service for display. (E.g. "My TV")
* @throws NS_ERROR_NOT_INITIALIZED when getting unset value.
*/
attribute AUTF8String serviceName;
/**
* The type of the service. (E.g. "_http._tcp")
* @throws NS_ERROR_NOT_INITIALIZED when getting unset value.
*/
attribute AUTF8String serviceType;
/**
* The domain name of the service. (E.g. "local.")
* @throws NS_ERROR_NOT_INITIALIZED when getting unset value.
*/
attribute AUTF8String domainName;
/**
* The attributes of the service.
*/
attribute nsIPropertyBag2 attributes;
};
/**
* The callback interface for service discovery
*/
[scriptable, uuid(3025b7f2-97bb-435b-b43d-26731b3f5fc4)]
interface nsIDNSServiceDiscoveryListener : nsISupports
{
/**
* Callback when the discovery begins.
* @param aServiceType
* the service type of |startDiscovery|.
*/
void onDiscoveryStarted(in AUTF8String aServiceType);
/**
* Callback when the discovery ends.
* @param aServiceType
* the service type of |startDiscovery|.
*/
void onDiscoveryStopped(in AUTF8String aServiceType);
/**
* Callback when the a service is found.
* @param aServiceInfo
* the info about the found service, where |serviceName|, |aServiceType|, and |domainName| are set.
*/
void onServiceFound(in nsIDNSServiceInfo aServiceInfo);
/**
* Callback when the a service is lost.
* @param aServiceInfo
* the info about the lost service, where |serviceName|, |aServiceType|, and |domainName| are set.
*/
void onServiceLost(in nsIDNSServiceInfo aServiceInfo);
/**
* Callback when the discovery cannot start.
* @param aServiceType
* the service type of |startDiscovery|.
* @param aErrorCode
* the error code.
*/
void onStartDiscoveryFailed(in AUTF8String aServiceType, in long aErrorCode);
/**
* Callback when the discovery cannot stop.
* @param aServiceType
* the service type of |startDiscovery|.
* @param aErrorCode
* the error code.
*/
void onStopDiscoveryFailed(in AUTF8String aServiceType, in long aErrorCode);
};
/**
* The callback interface for service registration
*/
[scriptable, uuid(e165e4be-abf4-4963-a66d-ed3ca116e5e4)]
interface nsIDNSRegistrationListener : nsISupports
{
const long ERROR_SERVICE_NOT_RUNNING = -65563;
/**
* Callback when the service is registered successfully.
* @param aServiceInfo
* the info about the registered service,
* where |serviceName|, |aServiceType|, and |domainName| are set.
*/
void onServiceRegistered(in nsIDNSServiceInfo aServiceInfo);
/**
* Callback when the service is unregistered successfully.
* @param aServiceInfo
* the info about the unregistered service.
*/
void onServiceUnregistered(in nsIDNSServiceInfo aServiceInfo);
/**
* Callback when the service cannot be registered.
* @param aServiceInfo
* the info about the service to be registered.
* @param aErrorCode
* the error code.
*/
void onRegistrationFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode);
/**
* Callback when the service cannot be unregistered.
* @param aServiceInfo
* the info about the registered service.
* @param aErrorCode
* the error code.
*/
void onUnregistrationFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode);
};
/**
* The callback interface for service resolve
*/
[scriptable, uuid(24ee6408-648e-421d-accf-c6e5adeccf97)]
interface nsIDNSServiceResolveListener : nsISupports
{
/**
* Callback when the service is resolved successfully.
* @param aServiceInfo
* the info about the resolved service, where |host| and |port| are set.
*/
void onServiceResolved(in nsIDNSServiceInfo aServiceInfo);
/**
* Callback when the service cannot be resolved.
* @param aServiceInfo
* the info about the service to be resolved.
* @param aErrorCode
* the error code.
*/
void onResolveFailed(in nsIDNSServiceInfo aServiceInfo, in long aErrorCode);
};
/**
* The interface for DNS service discovery/registration/resolve
*/
[scriptable, uuid(6487899b-beb1-455a-ba65-e4fd465066d7)]
interface nsIDNSServiceDiscovery : nsISupports
{
/**
* Browse for instances of a service.
* @param aServiceType
* the service type to be discovered, E.g. "_http._tcp".
* @param aListener
* callback interface for discovery notifications.
* @return An object that can be used to cancel the service discovery.
*/
nsICancelable startDiscovery(in AUTF8String aServiceType, in nsIDNSServiceDiscoveryListener aListener);
/**
* Register a service that is discovered via |startDiscovery| and |resolveService| calls.
* @param aServiceInfo
* the service information to be registered.
* |port| and |aServiceType| are required attributes.
* @param aListener
* callback interface for registration notifications.
* @return An object that can be used to cancel the service registration.
*/
nsICancelable registerService(in nsIDNSServiceInfo aServiceInfo, in nsIDNSRegistrationListener aListener);
/**
* Resolve a service name discovered via |startDiscovery| to a target host name, port number.
* @param aServiceInfo
* the service information to be registered.
* |serviceName|, |aServiceType|, and |domainName| are required attributes as reported to the |onServiceFound| callback.
* @param aListener
* callback interface for registration notifications.
*/
void resolveService(in nsIDNSServiceInfo aServiceInfo, in nsIDNSServiceResolveListener aListener);
};
%{ C++
#define DNSSERVICEDISCOVERY_CONTRACT_ID \
"@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1"
#define DNSSERVICEINFO_CONTRACT_ID \
"@mozilla.org/toolkit/components/mdnsresponder/dns-info;1"
%}

View File

@ -4,6 +4,10 @@
# 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/.
DIRS += [
'mdns',
]
XPIDL_SOURCES += [
'nsIDNSListener.idl',
'nsIDNSRecord.idl',

View File

@ -154,7 +154,7 @@ class DecisionTask(object):
'owner': params['owner'],
'as_slugid': SlugidJar(),
'from_now': json_time_from_now,
'now': datetime.datetime.now().isoformat()
'now': current_json_time()
}.items())
task = templates.load(params['task'], parameters)
print(json.dumps(task, indent=4))
@ -225,7 +225,7 @@ class Graph(object):
'head_rev': params['head_rev'],
'owner': params['owner'],
'from_now': json_time_from_now,
'now': datetime.datetime.now().isoformat(),
'now': current_json_time(),
'mozharness_repository': mozharness['repo'],
'mozharness_rev': mozharness['revision'],
'mozharness_ref':mozharness.get('reference', mozharness['revision']),

View File

@ -258,6 +258,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'sync',
]
if CONFIG['ANDROID_VERSION'] >= '16':
OS_LIBS += [
'mdnssd',
]
if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
OS_LIBS += [
'stagefright_foundation',

View File

@ -50,15 +50,23 @@ def MergeProfiles(files):
pidStr = pid + ":"
thread['startTime'] = fileData['profileJSON']['meta']['startTime']
samples = thread['samples']
for sample in thread['samples']:
for frame in sample['frames']:
if "location" in frame and frame['location'][0:2] == '0x':
oldLoc = frame['location']
newLoc = pidStr + oldLoc
frame['location'] = newLoc
# Default to the unprefixed symbol if no translation is available
symTable[newLoc] = oldLoc
if meta['version'] >= 3:
stringTable = thread['stringTable']
for i, str in enumerate(stringTable):
if str[:2] == '0x':
newLoc = pidStr + str
stringTable[i] = newLoc
symTable[newLoc] = str
else:
samples = thread['samples']
for sample in thread['samples']:
for frame in sample['frames']:
if "location" in frame and frame['location'][0:2] == '0x':
oldLoc = frame['location']
newLoc = pidStr + oldLoc
frame['location'] = newLoc
# Default to the unprefixed symbol if no translation is
symTable[newLoc] = oldLoc
filesyms = fileData['symbolicationTable']
for sym in filesyms.keys():
@ -68,11 +76,19 @@ def MergeProfiles(files):
# earliest start
for thread in threads:
delta = thread['startTime'] - minStartTime
for sample in thread['samples']:
if "time" in sample:
sample['time'] += delta
for marker in thread['markers']:
marker['time'] += delta
if meta['version'] >= 3:
idxTime = thread['samples']['schema']['time']
for sample in thread['samples']['data']:
sample[idxTime] += delta
idxTime = thread['markers']['schema']['time']
for marker in thread['markers']['data']:
marker[idxTime] += delta
else:
for sample in thread['samples']:
if "time" in sample:
sample['time'] += delta
for marker in thread['markers']:
marker['time'] += delta
result = dict()
result['profileJSON'] = dict()

View File

@ -149,6 +149,40 @@ status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
return NO_ERROR;
}
status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const {
const size_t N = mLedsByScanCode.size();
for (size_t i = 0; i < N; i++) {
if (mLedsByScanCode.valueAt(i).ledCode == ledCode) {
*outScanCode = mLedsByScanCode.keyAt(i);
#if DEBUG_MAPPING
ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode);
#endif
return NO_ERROR;
}
}
#if DEBUG_MAPPING
ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode);
#endif
return NAME_NOT_FOUND;
}
status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const {
const size_t N = mLedsByUsageCode.size();
for (size_t i = 0; i < N; i++) {
if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) {
*outUsageCode = mLedsByUsageCode.keyAt(i);
#if DEBUG_MAPPING
ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode);
#endif
return NO_ERROR;
}
}
#if DEBUG_MAPPING
ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode);
#endif
return NAME_NOT_FOUND;
}
// --- KeyLayoutMap::Parser ---
@ -178,6 +212,10 @@ status_t KeyLayoutMap::Parser::parse() {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseAxis();
if (status) return status;
} else if (keywordToken == "led") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseLed();
if (status) return status;
} else {
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
@ -363,4 +401,46 @@ status_t KeyLayoutMap::Parser::parseAxis() {
return NO_ERROR;
}
status_t KeyLayoutMap::Parser::parseLed() {
String8 codeToken = mTokenizer->nextToken(WHITESPACE);
bool mapUsage = false;
if (codeToken == "usage") {
mapUsage = true;
mTokenizer->skipDelimiters(WHITESPACE);
codeToken = mTokenizer->nextToken(WHITESPACE);
}
char* end;
int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
if (*end) {
ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode;
if (map.indexOfKey(code) >= 0) {
ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE);
int32_t ledCode = getLedByLabel(ledCodeToken.string());
if (ledCode < 0) {
ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(),
ledCodeToken.string());
return BAD_VALUE;
}
#if DEBUG_PARSER
ALOGD("Parsed led %s: code=%d, ledCode=%d.",
mapUsage ? "usage" : "scan code", code, ledCode);
#endif
Led led;
led.ledCode = ledCode;
map.add(code, led);
return NO_ERROR;
}
};

View File

@ -67,6 +67,8 @@ public:
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
@ -79,9 +81,16 @@ private:
uint32_t flags;
};
struct Led {
int32_t ledCode;
};
KeyedVector<int32_t, Key> mKeysByScanCode;
KeyedVector<int32_t, Key> mKeysByUsageCode;
KeyedVector<int32_t, AxisInfo> mAxes;
KeyedVector<int32_t, Led> mLedsByScanCode;
KeyedVector<int32_t, Led> mLedsByUsageCode;
KeyLayoutMap();
@ -99,6 +108,7 @@ private:
private:
status_t parseKey();
status_t parseAxis();
status_t parseLed();
};
};

View File

@ -204,6 +204,9 @@ const char* getAxisLabel(int32_t axisId) {
return lookupLabelByValue(axisId, AXES);
}
int32_t getLedByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, LEDS));
}
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
int32_t newMetaState;
if (down) {

View File

@ -105,6 +105,8 @@ extern int32_t getAxisByLabel(const char* label);
*/
extern const char* getAxisLabel(int32_t axisId);
extern int32_t getLedByLabel(const char* label);
/**
* Updates a meta state field when a key is pressed or released.
*/

View File

@ -356,4 +356,25 @@ static const KeycodeLabel AXES[] = {
{ NULL, -1 }
};
static const KeycodeLabel LEDS[] = {
{ "NUM_LOCK", 1},
{ "CAPS_LOCK", 2},
{ "SCROLL_LOCK", 3},
{ "COMPOSE", 4},
{ "KANA", 5},
{ "SLEEP", 6},
{ "SUSPEND", 7},
{ "MUTE", 8},
{ "MISC", 9},
{ "MAIL", 10},
{ "CHARGING", 11},
{ "CONTROLLER_1", 12},
{ "CONTROLLER_2", 13},
{ "CONTROLLER_3", 14},
{ "CONTROLLER_4", 15},
// NOTE: If you add new LEDs here, you must also add them to Input.h
{ NULL, 0 }
};
#endif // _ANDROIDFW_KEYCODE_LABELS_H