зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1462019 - Part 1. Support abstract socket address on nsIServerSocket and nsISocketTransportService. r=mayhemer
--HG-- extra : rebase_source : e7f4e258ce746f21c5792b148fd5ac4b4370eea6
This commit is contained in:
Родитель
e67d9e1b9e
Коммит
ca2b74b983
|
@ -150,6 +150,24 @@ interface nsIServerSocket : nsISupports
|
|||
void initWithFilename(in nsIFile aPath, in unsigned long aPermissions,
|
||||
in long aBacklog);
|
||||
|
||||
/**
|
||||
* initWithAbstractAddress
|
||||
*
|
||||
* This mehtod is a flavor of initWithFilename method. This initializes
|
||||
* a UNIX domain socket that uses abstract socket address.
|
||||
* This socket type is only supported on Linux and Android.
|
||||
*
|
||||
* On systems that don't support this type's UNIX domain sockets at all,
|
||||
* this returns NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED.
|
||||
*
|
||||
* @param aName
|
||||
* The abstract socket address which the socket should be created.
|
||||
* @param aBacklog
|
||||
* The maximum length the queue of pending connections may grow to.
|
||||
*/
|
||||
void initWithAbstractAddress(in AUTF8String aName,
|
||||
in long aBacklog);
|
||||
|
||||
/**
|
||||
* close
|
||||
*
|
||||
|
|
|
@ -84,6 +84,20 @@ interface nsISocketTransportService : nsISupports
|
|||
*/
|
||||
nsISocketTransport createUnixDomainTransport(in nsIFile aPath);
|
||||
|
||||
/**
|
||||
* Create a transport built on a Unix domain socket that uses abstract
|
||||
* address name.
|
||||
*
|
||||
* If abstract socket address isn't supported on System, this returns
|
||||
* NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED.
|
||||
*
|
||||
* @param aName
|
||||
* The name of abstract socket adress of the Unix domain socket to
|
||||
* which we should connect.
|
||||
*/
|
||||
nsISocketTransport
|
||||
createUnixDomainAbstractAddressTransport(in ACString aName);
|
||||
|
||||
/**
|
||||
* Adds a new socket to the list of controlled sockets.
|
||||
*
|
||||
|
|
|
@ -319,6 +319,29 @@ nsServerSocket::InitWithFilename(nsIFile *aPath, uint32_t aPermissions, int32_t
|
|||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServerSocket::InitWithAbstractAddress(const nsACString& aName,
|
||||
int32_t aBacklog)
|
||||
{
|
||||
// Abstract socket address is supported on Linux and Android only.
|
||||
// If not Linux, we should return error.
|
||||
#if defined(XP_LINUX)
|
||||
// Create an abstract socket address PRNetAddr referring to the name
|
||||
PRNetAddr addr;
|
||||
if (aName.Length() > sizeof(addr.local.path) - 2) {
|
||||
return NS_ERROR_FILE_NAME_TOO_LONG;
|
||||
}
|
||||
addr.local.family = PR_AF_LOCAL;
|
||||
addr.local.path[0] = 0;
|
||||
memcpy(addr.local.path + 1, aName.BeginReading(), aName.Length());
|
||||
addr.local.path[aName.Length() + 1] = 0;
|
||||
|
||||
return InitWithAddress(&addr, aBacklog);
|
||||
#else
|
||||
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServerSocket::InitSpecialConnection(int32_t aPort, nsServerSocketFlag aFlags,
|
||||
int32_t aBackLog)
|
||||
|
|
|
@ -928,18 +928,34 @@ nsSocketTransport::Init(const char **types, uint32_t typeCount,
|
|||
nsresult
|
||||
nsSocketTransport::InitWithFilename(const char *filename)
|
||||
{
|
||||
size_t filenameLength = strlen(filename);
|
||||
return InitWithName(filename, strlen(filename));
|
||||
}
|
||||
|
||||
if (filenameLength > sizeof(mNetAddr.local.path) - 1)
|
||||
nsresult
|
||||
nsSocketTransport::InitWithName(const char *name, size_t length)
|
||||
{
|
||||
if (length > sizeof(mNetAddr.local.path) - 1) {
|
||||
return NS_ERROR_FILE_NAME_TOO_LONG;
|
||||
}
|
||||
|
||||
mHost.Assign(filename);
|
||||
if (!name[0] && length > 1) {
|
||||
// name is abstract address name that is supported on Linux only
|
||||
#if defined(XP_LINUX)
|
||||
mHost.Assign(name + 1, length - 1);
|
||||
#else
|
||||
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
|
||||
#endif
|
||||
} else {
|
||||
// The name isn't abstract socket address. So this is Unix domain
|
||||
// socket that has file path.
|
||||
mHost.Assign(name, length);
|
||||
}
|
||||
mPort = 0;
|
||||
mTypeCount = 0;
|
||||
|
||||
mNetAddr.local.family = AF_LOCAL;
|
||||
memcpy(mNetAddr.local.path, filename, filenameLength);
|
||||
mNetAddr.local.path[filenameLength] = '\0';
|
||||
memcpy(mNetAddr.local.path, name, length);
|
||||
mNetAddr.local.path[length] = '\0';
|
||||
mNetAddrIsSet = true;
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -150,6 +150,13 @@ public:
|
|||
// connected to the given Unix domain address. We can only create
|
||||
// unlayered, simple, stream sockets.
|
||||
nsresult InitWithFilename(const char *filename);
|
||||
|
||||
// This method instructs the socket transport to open a socket
|
||||
// connected to the given Unix domain address that includes abstract
|
||||
// socket address. If using abstract socket address, first character of
|
||||
// name parameter has to be \0.
|
||||
// We can only create unlayered, simple, stream sockets.
|
||||
nsresult InitWithName(const char *name, size_t len);
|
||||
#endif
|
||||
|
||||
// nsASocketHandler methods:
|
||||
|
|
|
@ -845,6 +845,30 @@ nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
|
|||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::CreateUnixDomainAbstractAddressTransport(
|
||||
const nsACString& aName,
|
||||
nsISocketTransport **result)
|
||||
{
|
||||
// Abstract socket address is supported on Linux only
|
||||
#ifdef XP_LINUX
|
||||
RefPtr<nsSocketTransport> trans = new nsSocketTransport();
|
||||
// First character of Abstract socket address is null
|
||||
UniquePtr<char[]> name(new char[aName.Length() + 1]);
|
||||
*(name.get()) = 0;
|
||||
memcpy(name.get() + 1, aName.BeginReading(), aName.Length());
|
||||
nsresult rv = trans->InitWithName(name.get(), aName.Length() + 1);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
trans.forget(result);
|
||||
return NS_OK;
|
||||
#else
|
||||
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::OnDispatchedEvent()
|
||||
{
|
||||
|
|
|
@ -5,6 +5,9 @@ var CC = Components.Constructor;
|
|||
const UnixServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"initWithFilename");
|
||||
const UnixAbstractServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"initWithAbstractAddress");
|
||||
|
||||
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
|
||||
"nsIScriptableInputStream",
|
||||
|
@ -27,16 +30,24 @@ function run_test()
|
|||
return;
|
||||
}
|
||||
|
||||
add_test(test_echo);
|
||||
add_test(test_name_too_long);
|
||||
add_test(test_no_directory);
|
||||
add_test(test_no_such_socket);
|
||||
add_test(test_address_in_use);
|
||||
add_test(test_file_in_way);
|
||||
add_test(test_create_permission);
|
||||
add_test(test_connect_permission);
|
||||
add_test(test_long_socket_name);
|
||||
add_test(test_keep_when_offline);
|
||||
// The xpcshell temp directory on Android doesn't seem to let us create
|
||||
// Unix domain sockets. (Perhaps it's a FAT filesystem?)
|
||||
if (mozinfo.os != "android") {
|
||||
add_test(test_echo);
|
||||
add_test(test_name_too_long);
|
||||
add_test(test_no_directory);
|
||||
add_test(test_no_such_socket);
|
||||
add_test(test_address_in_use);
|
||||
add_test(test_file_in_way);
|
||||
add_test(test_create_permission);
|
||||
add_test(test_connect_permission);
|
||||
add_test(test_long_socket_name);
|
||||
add_test(test_keep_when_offline);
|
||||
}
|
||||
|
||||
if (mozinfo.os == "android" || mozinfo.os == "linux") {
|
||||
add_test(test_abstract_address_socket);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
@ -543,3 +554,51 @@ function test_keep_when_offline()
|
|||
run_next_test();
|
||||
}
|
||||
}
|
||||
|
||||
function test_abstract_address_socket()
|
||||
{
|
||||
const socketname = "abstractsocket";
|
||||
let server = new UnixAbstractServerSocket(socketname, -1);
|
||||
server.asyncListen({
|
||||
onSocketAccepted: (aServ, aTransport) => {
|
||||
let serverInput = aTransport.openInputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncInputStream);
|
||||
let serverOutput = aTransport.openOutputStream(0, 0, 0);
|
||||
|
||||
serverInput.asyncWait(aStream => {
|
||||
info("called test_abstract_address_socket's onSocketAccepted's onInputStreamReady");
|
||||
|
||||
// Receive data from the client, and send back a response.
|
||||
let serverScriptableInput = new ScriptableInputStream(serverInput);
|
||||
Assert.equal(serverScriptableInput.readBytes(9), "ping ping");
|
||||
serverOutput.write("pong", 4);
|
||||
|
||||
}, 0, 0, threadManager.currentThread);
|
||||
},
|
||||
onStopListening: (aServ, aTransport) => {
|
||||
},
|
||||
});
|
||||
|
||||
let client = socketTransportService
|
||||
.createUnixDomainAbstractAddressTransport(socketname);
|
||||
Assert.equal(client.host, socketname);
|
||||
Assert.equal(client.port, 0);
|
||||
let clientInput = client.openInputStream(0, 0, 0)
|
||||
.QueryInterface(Ci.nsIAsyncInputStream);
|
||||
let clientOutput = client.openOutputStream(0, 0, 0);
|
||||
|
||||
clientOutput.write("ping ping", 9);
|
||||
|
||||
clientInput.asyncWait(aStream => {
|
||||
let clientScriptInput = new ScriptableInputStream(clientInput);
|
||||
let available = clientScriptInput.available();
|
||||
if (available) {
|
||||
Assert.equal(clientScriptInput.readBytes(4), "pong");
|
||||
|
||||
client.close(Cr.NS_OK);
|
||||
server.close(Cr.NS_OK);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
}, 0, 0, threadManager.currentThread);
|
||||
}
|
||||
|
|
|
@ -336,9 +336,6 @@ run-sequentially = Hardcoded hash value includes port 4444.
|
|||
[test_about_protocol.js]
|
||||
[test_bug856978.js]
|
||||
[test_unix_domain.js]
|
||||
# The xpcshell temp directory on Android doesn't seem to let us create
|
||||
# Unix domain sockets. (Perhaps it's a FAT filesystem?)
|
||||
skip-if = os == "android"
|
||||
[test_addr_in_use_error.js]
|
||||
[test_about_networking.js]
|
||||
[test_ping_aboutnetworking.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче