Bug 1462019 - Part 1. Support abstract socket address on nsIServerSocket and nsISocketTransportService. r=mayhemer

--HG--
extra : rebase_source : e7f4e258ce746f21c5792b148fd5ac4b4370eea6
This commit is contained in:
Makoto Kato 2018-07-26 18:06:42 +09:00
Родитель e67d9e1b9e
Коммит ca2b74b983
8 изменённых файлов: 176 добавлений и 18 удалений

Просмотреть файл

@ -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]