Сделать сокет TCP двунаправленным в расширении Thunderbird?

В расширении Thunderbird я использую следующий код для ожидания входящего TCP-соединения:

function MyExtension_OnNewConnection(srvSock, newSock)
{
    var block = Components.interfaces.nsITransport.OPEN_BLOCKING |
        Components.interfaces.nsITransport.OPEN_UNBUFFERED;
    var istream = newSock.openInputStream(block, 0, 0);
    var ostream = newSock.openOutputStream(block, 0, 0);

    var cstream = Components.
        classes["@mozilla.org/scriptableinputstream;1"].
        createInstance(Components.interfaces.nsIScriptableInputStream);
    cstream.init(istream);
    var y = cstream.read(1);
    cstream.close();
    if(y == "")
    {
        var y = "The socket is Tx-Only!\r\n";
        ostream.write(y, y.length);
    }

    istream.close();
    ostream.close();
}

...

waitSocket = Components.classes["@mozilla.org/network/server-socket;1"].
        createInstance(Components.interfaces.nsIServerSocket);
waitSocket.init(-1, false, -1);
waitSocket.asyncListen({
    onSocketAccepted: MyExtension_OnNewConnection,
    onStopListening: function(socket, status) {}
});

Согласно документации cstream.read() может возвращать пустую строку только тогда, когда сокет TCP закрыт.

Функция ostream.write() отправит некоторые данные, которые возможны только в том случае, если сокет TCP еще не закрыт.

Однако cstream.read() возвращает пустую строку, ostream.write() отправляет некоторые данные, а другой конец соединения TCP получает строку!

Это означает, что соединение TCP является однонаправленным (с самого начала!).

Вопросы:

  • Почему?
  • Как я могу сделать соединение TCP двунаправленным, чтобы я мог получать данные?

Что я уже пробовал:

  • не использовать флаги OPEN_BLOCKING и OPEN_UNBUFFERED => Нет эффекта.
  • проверка istream.available() в цикле вместо использования cstream => Всегда будет возвращать 0, даже если данные были отправлены другим концом соединения TCP.

person Martin Rosenau    schedule 14.05.2017    source источник


Ответы (1)


Я проанализировал исходный код Thunderbird:

Очевидно, что openInputStream использует довольно "простую" реализацию, если OPEN_UNBUFFERED установлено, а OPEN_BLOCKING не установлено, в то время как для трех других комбинаций используется довольно сложная реализация.

Простая реализация работает отлично, однако тогда блокировка доступа к сокету невозможна.

На другой странице говорится, что функции Javascript должны быть написаны неблокирующим образом, поэтому я решил использовать следующую реализацию:

function CalledOnTimer()
{
    try
    {
        while(true)
        {
            data = cstream.read(NumberOfBytes);
            if(data == "")
            {
                /* Socket has been closed */
                cstream.close();
                istream.close();
                ostream.close();
                ...
                return;
            }
            /* Process the data */
            ...
        }
    }
    catch(dummy)
    {
        /* Currently no (more) data on the socket */
        restartTheTimer();
    }
}

...
var istream = newSock.openInputStream(
    Components.interfaces.nsITransport.OPEN_UNBUFFERED, 0, 0);
...
cstream.init(istream);
...
startTheTimer();
person Martin Rosenau    schedule 15.05.2017