forked from mirrors/gecko-dev
Bug 1462019 - Part 1. Support abstract socket address on nsIServerSocket and nsISocketTransportService. r=mayhemer
This commit is contained in:
parent
2d7e793ae4
commit
e788340ea4
8 changed files with 176 additions and 18 deletions
|
|
@ -150,6 +150,24 @@ interface nsIServerSocket : nsISupports
|
||||||
void initWithFilename(in nsIFile aPath, in unsigned long aPermissions,
|
void initWithFilename(in nsIFile aPath, in unsigned long aPermissions,
|
||||||
in long aBacklog);
|
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
|
* close
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,20 @@ interface nsISocketTransportService : nsISupports
|
||||||
*/
|
*/
|
||||||
nsISocketTransport createUnixDomainTransport(in nsIFile aPath);
|
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.
|
* Adds a new socket to the list of controlled sockets.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,29 @@ nsServerSocket::InitWithFilename(nsIFile *aPath, uint32_t aPermissions, int32_t
|
||||||
#endif
|
#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
|
NS_IMETHODIMP
|
||||||
nsServerSocket::InitSpecialConnection(int32_t aPort, nsServerSocketFlag aFlags,
|
nsServerSocket::InitSpecialConnection(int32_t aPort, nsServerSocketFlag aFlags,
|
||||||
int32_t aBackLog)
|
int32_t aBackLog)
|
||||||
|
|
|
||||||
|
|
@ -928,18 +928,34 @@ nsSocketTransport::Init(const char **types, uint32_t typeCount,
|
||||||
nsresult
|
nsresult
|
||||||
nsSocketTransport::InitWithFilename(const char *filename)
|
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;
|
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;
|
mPort = 0;
|
||||||
mTypeCount = 0;
|
mTypeCount = 0;
|
||||||
|
|
||||||
mNetAddr.local.family = AF_LOCAL;
|
mNetAddr.local.family = AF_LOCAL;
|
||||||
memcpy(mNetAddr.local.path, filename, filenameLength);
|
memcpy(mNetAddr.local.path, name, length);
|
||||||
mNetAddr.local.path[filenameLength] = '\0';
|
mNetAddr.local.path[length] = '\0';
|
||||||
mNetAddrIsSet = true;
|
mNetAddrIsSet = true;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,13 @@ public:
|
||||||
// connected to the given Unix domain address. We can only create
|
// connected to the given Unix domain address. We can only create
|
||||||
// unlayered, simple, stream sockets.
|
// unlayered, simple, stream sockets.
|
||||||
nsresult InitWithFilename(const char *filename);
|
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
|
#endif
|
||||||
|
|
||||||
// nsASocketHandler methods:
|
// nsASocketHandler methods:
|
||||||
|
|
|
||||||
|
|
@ -845,6 +845,30 @@ nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
|
||||||
#endif
|
#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
|
NS_IMETHODIMP
|
||||||
nsSocketTransportService::OnDispatchedEvent()
|
nsSocketTransportService::OnDispatchedEvent()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ var CC = Components.Constructor;
|
||||||
const UnixServerSocket = CC("@mozilla.org/network/server-socket;1",
|
const UnixServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||||
"nsIServerSocket",
|
"nsIServerSocket",
|
||||||
"initWithFilename");
|
"initWithFilename");
|
||||||
|
const UnixAbstractServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||||
|
"nsIServerSocket",
|
||||||
|
"initWithAbstractAddress");
|
||||||
|
|
||||||
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
|
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
|
||||||
"nsIScriptableInputStream",
|
"nsIScriptableInputStream",
|
||||||
|
|
@ -27,16 +30,24 @@ function run_test()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_test(test_echo);
|
// The xpcshell temp directory on Android doesn't seem to let us create
|
||||||
add_test(test_name_too_long);
|
// Unix domain sockets. (Perhaps it's a FAT filesystem?)
|
||||||
add_test(test_no_directory);
|
if (mozinfo.os != "android") {
|
||||||
add_test(test_no_such_socket);
|
add_test(test_echo);
|
||||||
add_test(test_address_in_use);
|
add_test(test_name_too_long);
|
||||||
add_test(test_file_in_way);
|
add_test(test_no_directory);
|
||||||
add_test(test_create_permission);
|
add_test(test_no_such_socket);
|
||||||
add_test(test_connect_permission);
|
add_test(test_address_in_use);
|
||||||
add_test(test_long_socket_name);
|
add_test(test_file_in_way);
|
||||||
add_test(test_keep_when_offline);
|
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();
|
run_next_test();
|
||||||
}
|
}
|
||||||
|
|
@ -543,3 +554,51 @@ function test_keep_when_offline()
|
||||||
run_next_test();
|
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_about_protocol.js]
|
||||||
[test_bug856978.js]
|
[test_bug856978.js]
|
||||||
[test_unix_domain.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_addr_in_use_error.js]
|
||||||
[test_about_networking.js]
|
[test_about_networking.js]
|
||||||
[test_ping_aboutnetworking.js]
|
[test_ping_aboutnetworking.js]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue