tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_unix_domain.js (21547B)


      1 // Exercise Unix domain sockets.
      2 "use strict";
      3 
      4 var CC = Components.Constructor;
      5 
      6 const UnixServerSocket = CC(
      7  "@mozilla.org/network/server-socket;1",
      8  "nsIServerSocket",
      9  "initWithFilename"
     10 );
     11 const UnixAbstractServerSocket = CC(
     12  "@mozilla.org/network/server-socket;1",
     13  "nsIServerSocket",
     14  "initWithAbstractAddress"
     15 );
     16 
     17 const ScriptableInputStream = CC(
     18  "@mozilla.org/scriptableinputstream;1",
     19  "nsIScriptableInputStream",
     20  "init"
     21 );
     22 
     23 const socketTransportService = Cc[
     24  "@mozilla.org/network/socket-transport-service;1"
     25 ].getService(Ci.nsISocketTransportService);
     26 
     27 const threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
     28 
     29 const allPermissions = parseInt("777", 8);
     30 
     31 function run_test() {
     32  // If we're on Windows, simply check for graceful failure.
     33  if (mozinfo.os == "win") {
     34    test_not_supported();
     35    return;
     36  }
     37 
     38  // The xpcshell temp directory on Android doesn't seem to let us create
     39  // Unix domain sockets. (Perhaps it's a FAT filesystem?)
     40  if (mozinfo.os != "android") {
     41    add_test(test_echo);
     42    add_test(test_name_too_long);
     43    add_test(test_no_directory);
     44    add_test(test_no_such_socket);
     45    add_test(test_address_in_use);
     46    add_test(test_file_in_way);
     47    add_test(test_create_permission);
     48    add_test(test_connect_permission);
     49    add_test(test_long_socket_name);
     50    add_test(test_keep_when_offline);
     51  }
     52 
     53  if (mozinfo.os == "android" || mozinfo.os == "linux") {
     54    add_test(test_abstract_address_socket);
     55  }
     56 
     57  run_next_test();
     58 }
     59 
     60 // Check that creating a Unix domain socket fails gracefully on Windows.
     61 function test_not_supported() {
     62  let socketName = do_get_tempdir();
     63  socketName.append("socket");
     64  info("creating socket: " + socketName.path);
     65 
     66  do_check_throws_nsIException(
     67    () => new UnixServerSocket(socketName, allPermissions, -1),
     68    "NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED"
     69  );
     70 
     71  do_check_throws_nsIException(
     72    () => socketTransportService.createUnixDomainTransport(socketName),
     73    "NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED"
     74  );
     75 }
     76 
     77 // Actually exchange data with Unix domain sockets.
     78 function test_echo() {
     79  let log = "";
     80 
     81  let socketName = do_get_tempdir();
     82  socketName.append("socket");
     83 
     84  // Create a server socket, listening for connections.
     85  info("creating socket: " + socketName.path);
     86  let server = new UnixServerSocket(socketName, allPermissions, -1);
     87  server.asyncListen({
     88    onSocketAccepted(aServ, aTransport) {
     89      info("called test_echo's onSocketAccepted");
     90      log += "a";
     91 
     92      Assert.equal(aServ, server);
     93 
     94      let connection = aTransport;
     95 
     96      // Check the server socket's self address.
     97      let connectionSelfAddr = connection.getScriptableSelfAddr();
     98      Assert.equal(connectionSelfAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
     99      Assert.equal(connectionSelfAddr.address, socketName.path);
    100 
    101      // The client socket is anonymous, so the server transport should
    102      // have an empty peer address.
    103      Assert.equal(connection.host, "");
    104      Assert.equal(connection.port, 0);
    105      let connectionPeerAddr = connection.getScriptablePeerAddr();
    106      Assert.equal(connectionPeerAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
    107      Assert.equal(connectionPeerAddr.address, "");
    108 
    109      let serverAsyncInput = connection
    110        .openInputStream(0, 0, 0)
    111        .QueryInterface(Ci.nsIAsyncInputStream);
    112      let serverOutput = connection.openOutputStream(0, 0, 0);
    113 
    114      serverAsyncInput.asyncWait(
    115        function (aStream) {
    116          info("called test_echo's server's onInputStreamReady");
    117          let serverScriptableInput = new ScriptableInputStream(aStream);
    118 
    119          // Receive data from the client, and send back a response.
    120          Assert.equal(
    121            serverScriptableInput.readBytes(17),
    122            "Mervyn Murgatroyd"
    123          );
    124          info("server has read message from client");
    125          serverOutput.write("Ruthven Murgatroyd", 18);
    126          info("server has written to client");
    127        },
    128        0,
    129        0,
    130        threadManager.currentThread
    131      );
    132    },
    133 
    134    onStopListening(aServ) {
    135      info("called test_echo's onStopListening");
    136      log += "s";
    137 
    138      Assert.equal(aServ, server);
    139      Assert.equal(log, "acs");
    140 
    141      run_next_test();
    142    },
    143  });
    144 
    145  // Create a client socket, and connect to the server.
    146  let client = socketTransportService.createUnixDomainTransport(socketName);
    147  Assert.equal(client.host, socketName.path);
    148  Assert.equal(client.port, 0);
    149 
    150  let clientAsyncInput = client
    151    .openInputStream(0, 0, 0)
    152    .QueryInterface(Ci.nsIAsyncInputStream);
    153  let clientInput = new ScriptableInputStream(clientAsyncInput);
    154  let clientOutput = client.openOutputStream(0, 0, 0);
    155 
    156  clientOutput.write("Mervyn Murgatroyd", 17);
    157  info("client has written to server");
    158 
    159  clientAsyncInput.asyncWait(
    160    function (aStream) {
    161      info("called test_echo's client's onInputStreamReady");
    162      log += "c";
    163 
    164      Assert.equal(aStream, clientAsyncInput);
    165 
    166      // Now that the connection has been established, we can check the
    167      // transport's self and peer addresses.
    168      let clientSelfAddr = client.getScriptableSelfAddr();
    169      Assert.equal(clientSelfAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
    170      Assert.equal(clientSelfAddr.address, "");
    171 
    172      Assert.equal(client.host, socketName.path); // re-check, but hey
    173      let clientPeerAddr = client.getScriptablePeerAddr();
    174      Assert.equal(clientPeerAddr.family, Ci.nsINetAddr.FAMILY_LOCAL);
    175      Assert.equal(clientPeerAddr.address, socketName.path);
    176 
    177      Assert.equal(clientInput.readBytes(18), "Ruthven Murgatroyd");
    178      info("client has read message from server");
    179 
    180      server.close();
    181    },
    182    0,
    183    0,
    184    threadManager.currentThread
    185  );
    186 }
    187 
    188 // Create client and server sockets using a path that's too long.
    189 function test_name_too_long() {
    190  let socketName = do_get_tempdir();
    191  // The length limits on all the systems NSPR supports are a bit past 100.
    192  socketName.append(new Array(1000).join("x"));
    193 
    194  // The length must be checked before we ever make any system calls --- we
    195  // have to create the sockaddr first --- so it's unambiguous which error
    196  // we should get here.
    197 
    198  do_check_throws_nsIException(
    199    () => new UnixServerSocket(socketName, 0, -1),
    200    "NS_ERROR_FILE_NAME_TOO_LONG"
    201  );
    202 
    203  // Unlike most other client socket errors, this one gets reported
    204  // immediately, as we can't even initialize the sockaddr with the given
    205  // name.
    206  do_check_throws_nsIException(
    207    () => socketTransportService.createUnixDomainTransport(socketName),
    208    "NS_ERROR_FILE_NAME_TOO_LONG"
    209  );
    210 
    211  run_next_test();
    212 }
    213 
    214 // Try creating a socket in a directory that doesn't exist.
    215 function test_no_directory() {
    216  let socketName = do_get_tempdir();
    217  socketName.append("missing");
    218  socketName.append("socket");
    219 
    220  do_check_throws_nsIException(
    221    () => new UnixServerSocket(socketName, 0, -1),
    222    "NS_ERROR_FILE_NOT_FOUND"
    223  );
    224 
    225  run_next_test();
    226 }
    227 
    228 // Try connecting to a server socket that isn't there.
    229 function test_no_such_socket() {
    230  let socketName = do_get_tempdir();
    231  socketName.append("nonexistent-socket");
    232 
    233  let client = socketTransportService.createUnixDomainTransport(socketName);
    234  let clientAsyncInput = client
    235    .openInputStream(0, 0, 0)
    236    .QueryInterface(Ci.nsIAsyncInputStream);
    237  clientAsyncInput.asyncWait(
    238    function (aStream) {
    239      info("called test_no_such_socket's onInputStreamReady");
    240 
    241      Assert.equal(aStream, clientAsyncInput);
    242 
    243      // nsISocketTransport puts off actually creating sockets as long as
    244      // possible, so the error in connecting doesn't actually show up until
    245      // this point.
    246      do_check_throws_nsIException(
    247        () => clientAsyncInput.available(),
    248        "NS_ERROR_FILE_NOT_FOUND"
    249      );
    250 
    251      clientAsyncInput.close();
    252      client.close(Cr.NS_OK);
    253 
    254      run_next_test();
    255    },
    256    0,
    257    0,
    258    threadManager.currentThread
    259  );
    260 }
    261 
    262 // Creating a socket with a name that another socket is already using is an
    263 // error.
    264 function test_address_in_use() {
    265  let socketName = do_get_tempdir();
    266  socketName.append("socket-in-use");
    267 
    268  // Create one server socket.
    269  new UnixServerSocket(socketName, allPermissions, -1);
    270 
    271  // Now try to create another with the same name.
    272  do_check_throws_nsIException(
    273    () => new UnixServerSocket(socketName, allPermissions, -1),
    274    "NS_ERROR_SOCKET_ADDRESS_IN_USE"
    275  );
    276 
    277  run_next_test();
    278 }
    279 
    280 // Creating a socket with a name that is already a file is an error.
    281 function test_file_in_way() {
    282  let socketName = do_get_tempdir();
    283  socketName.append("file_in_way");
    284 
    285  // Create a file with the given name.
    286  socketName.create(Ci.nsIFile.NORMAL_FILE_TYPE, allPermissions);
    287 
    288  // Try to create a socket with the same name.
    289  do_check_throws_nsIException(
    290    () => new UnixServerSocket(socketName, allPermissions, -1),
    291    "NS_ERROR_SOCKET_ADDRESS_IN_USE"
    292  );
    293 
    294  // Try to create a socket under a name that uses that as a parent directory.
    295  socketName.append("socket");
    296  do_check_throws_nsIException(
    297    () => new UnixServerSocket(socketName, 0, -1),
    298    "NS_ERROR_FILE_NOT_DIRECTORY"
    299  );
    300 
    301  run_next_test();
    302 }
    303 
    304 // It is not permitted to create a socket in a directory which we are not
    305 // permitted to execute, or create files in.
    306 function test_create_permission() {
    307  let dirName = do_get_tempdir();
    308  dirName.append("unfriendly");
    309 
    310  let socketName = dirName.clone();
    311  socketName.append("socket");
    312 
    313  // The test harness has difficulty cleaning things up if we don't make
    314  // everything writable before we're done.
    315  try {
    316    // Create a directory which we are not permitted to search.
    317    dirName.create(Ci.nsIFile.DIRECTORY_TYPE, 0);
    318 
    319    // Try to create a socket in that directory. Because Linux returns EACCES
    320    // when a 'connect' fails because of a local firewall rule,
    321    // nsIServerSocket returns NS_ERROR_CONNECTION_REFUSED in this case.
    322    do_check_throws_nsIException(
    323      () => new UnixServerSocket(socketName, allPermissions, -1),
    324      "NS_ERROR_CONNECTION_REFUSED"
    325    );
    326 
    327    // Grant read and execute permission, but not write permission on the directory.
    328    dirName.permissions = parseInt("0555", 8);
    329 
    330    // This should also fail; we need write permission.
    331    do_check_throws_nsIException(
    332      () => new UnixServerSocket(socketName, allPermissions, -1),
    333      "NS_ERROR_CONNECTION_REFUSED"
    334    );
    335  } finally {
    336    // Make the directory writable, so the test harness can clean it up.
    337    dirName.permissions = allPermissions;
    338  }
    339 
    340  // This should succeed, since we now have all the permissions on the
    341  // directory we could want.
    342  do_check_instanceof(
    343    new UnixServerSocket(socketName, allPermissions, -1),
    344    Ci.nsIServerSocket
    345  );
    346 
    347  run_next_test();
    348 }
    349 
    350 // To connect to a Unix domain socket, we need search permission on the
    351 // directories containing it, and some kind of permission or other on the
    352 // socket itself.
    353 function test_connect_permission() {
    354  // This test involves a lot of callbacks, but they're written out so that
    355  // the actual control flow proceeds from top to bottom.
    356  let log = "";
    357 
    358  // Create a directory which we are permitted to search - at first.
    359  let dirName = do_get_tempdir();
    360  dirName.append("inhospitable");
    361  dirName.create(Ci.nsIFile.DIRECTORY_TYPE, allPermissions);
    362 
    363  let socketName = dirName.clone();
    364  socketName.append("socket");
    365 
    366  // Create a server socket in that directory, listening for connections,
    367  // and accessible.
    368  let server = new UnixServerSocket(socketName, allPermissions, -1);
    369  server.asyncListen({
    370    onSocketAccepted: socketAccepted,
    371    onStopListening: stopListening,
    372  });
    373 
    374  // Make the directory unsearchable.
    375  dirName.permissions = 0;
    376 
    377  let client3;
    378 
    379  let client1 = socketTransportService.createUnixDomainTransport(socketName);
    380  let client1AsyncInput = client1
    381    .openInputStream(0, 0, 0)
    382    .QueryInterface(Ci.nsIAsyncInputStream);
    383  client1AsyncInput.asyncWait(
    384    function () {
    385      info("called test_connect_permission's client1's onInputStreamReady");
    386      log += "1";
    387 
    388      // nsISocketTransport puts off actually creating sockets as long as
    389      // possible, so the error doesn't actually show up until this point.
    390      do_check_throws_nsIException(
    391        () => client1AsyncInput.available(),
    392        "NS_ERROR_CONNECTION_REFUSED"
    393      );
    394 
    395      client1AsyncInput.close();
    396      client1.close(Cr.NS_OK);
    397 
    398      // Make the directory searchable, but make the socket inaccessible.
    399      dirName.permissions = allPermissions;
    400      socketName.permissions = 0;
    401 
    402      let client2 =
    403        socketTransportService.createUnixDomainTransport(socketName);
    404      let client2AsyncInput = client2
    405        .openInputStream(0, 0, 0)
    406        .QueryInterface(Ci.nsIAsyncInputStream);
    407      client2AsyncInput.asyncWait(
    408        function () {
    409          info("called test_connect_permission's client2's onInputStreamReady");
    410          log += "2";
    411 
    412          do_check_throws_nsIException(
    413            () => client2AsyncInput.available(),
    414            "NS_ERROR_CONNECTION_REFUSED"
    415          );
    416 
    417          client2AsyncInput.close();
    418          client2.close(Cr.NS_OK);
    419 
    420          // Now make everything accessible, and try one last time.
    421          socketName.permissions = allPermissions;
    422 
    423          client3 =
    424            socketTransportService.createUnixDomainTransport(socketName);
    425 
    426          let client3Output = client3.openOutputStream(0, 0, 0);
    427          client3Output.write("Hanratty", 8);
    428 
    429          let client3AsyncInput = client3
    430            .openInputStream(0, 0, 0)
    431            .QueryInterface(Ci.nsIAsyncInputStream);
    432          client3AsyncInput.asyncWait(
    433            client3InputStreamReady,
    434            0,
    435            0,
    436            threadManager.currentThread
    437          );
    438        },
    439        0,
    440        0,
    441        threadManager.currentThread
    442      );
    443    },
    444    0,
    445    0,
    446    threadManager.currentThread
    447  );
    448 
    449  function socketAccepted(aServ, aTransport) {
    450    info("called test_connect_permission's onSocketAccepted");
    451    log += "a";
    452 
    453    let serverInput = aTransport
    454      .openInputStream(0, 0, 0)
    455      .QueryInterface(Ci.nsIAsyncInputStream);
    456    let serverOutput = aTransport.openOutputStream(0, 0, 0);
    457 
    458    serverInput.asyncWait(
    459      function () {
    460        info(
    461          "called test_connect_permission's socketAccepted's onInputStreamReady"
    462        );
    463        log += "i";
    464 
    465        // Receive data from the client, and send back a response.
    466        let serverScriptableInput = new ScriptableInputStream(serverInput);
    467        Assert.equal(serverScriptableInput.readBytes(8), "Hanratty");
    468        serverOutput.write("Ferlingatti", 11);
    469      },
    470      0,
    471      0,
    472      threadManager.currentThread
    473    );
    474  }
    475 
    476  function client3InputStreamReady(aStream) {
    477    info("called client3's onInputStreamReady");
    478    log += "3";
    479 
    480    let client3Input = new ScriptableInputStream(aStream);
    481 
    482    Assert.equal(client3Input.readBytes(11), "Ferlingatti");
    483 
    484    client3.close(Cr.NS_OK);
    485    server.close();
    486  }
    487 
    488  function stopListening() {
    489    info("called test_connect_permission's server's stopListening");
    490    log += "s";
    491 
    492    Assert.equal(log, "12ai3s");
    493 
    494    run_next_test();
    495  }
    496 }
    497 
    498 // Creating a socket with a long filename doesn't crash.
    499 function test_long_socket_name() {
    500  let socketName = do_get_tempdir();
    501  socketName.append(new Array(10000).join("long"));
    502 
    503  // Try to create a server socket with the long name.
    504  do_check_throws_nsIException(
    505    () => new UnixServerSocket(socketName, allPermissions, -1),
    506    "NS_ERROR_FILE_NAME_TOO_LONG"
    507  );
    508 
    509  // Try to connect to a socket with the long name.
    510  do_check_throws_nsIException(
    511    () => socketTransportService.createUnixDomainTransport(socketName),
    512    "NS_ERROR_FILE_NAME_TOO_LONG"
    513  );
    514 
    515  run_next_test();
    516 }
    517 
    518 // Going offline should not shut down Unix domain sockets.
    519 function test_keep_when_offline() {
    520  let log = "";
    521 
    522  let socketName = do_get_tempdir();
    523  socketName.append("keep-when-offline");
    524 
    525  // Create a listening socket.
    526  let listener = new UnixServerSocket(socketName, allPermissions, -1);
    527  listener.asyncListen({ onSocketAccepted: onAccepted, onStopListening });
    528 
    529  // Connect a client socket to the listening socket.
    530  let client = socketTransportService.createUnixDomainTransport(socketName);
    531  let clientOutput = client.openOutputStream(0, 0, 0);
    532  let clientInput = client.openInputStream(0, 0, 0);
    533  clientInput.asyncWait(clientReady, 0, 0, threadManager.currentThread);
    534  let clientScriptableInput = new ScriptableInputStream(clientInput);
    535 
    536  let server, serverInput, serverScriptableInput, serverOutput;
    537 
    538  // How many times has the server invited the client to go first?
    539  let count = 0;
    540 
    541  // The server accepted connection callback.
    542  function onAccepted(aListener, aServer) {
    543    info("test_keep_when_offline: onAccepted called");
    544    log += "a";
    545    Assert.equal(aListener, listener);
    546    server = aServer;
    547 
    548    // Prepare to receive messages from the client.
    549    serverInput = server.openInputStream(0, 0, 0);
    550    serverInput.asyncWait(serverReady, 0, 0, threadManager.currentThread);
    551    serverScriptableInput = new ScriptableInputStream(serverInput);
    552 
    553    // Start a conversation with the client.
    554    serverOutput = server.openOutputStream(0, 0, 0);
    555    serverOutput.write("After you, Alphonse!", 20);
    556    count++;
    557  }
    558 
    559  // The client has seen its end of the socket close.
    560  function clientReady(aStream) {
    561    log += "c";
    562    info("test_keep_when_offline: clientReady called: " + log);
    563    Assert.equal(aStream, clientInput);
    564 
    565    // If the connection has been closed, end the conversation and stop listening.
    566    let available;
    567    try {
    568      available = clientInput.available();
    569    } catch (ex) {
    570      do_check_instanceof(ex, Ci.nsIException);
    571      Assert.equal(ex.result, Cr.NS_BASE_STREAM_CLOSED);
    572 
    573      info("client received end-of-stream; closing client output stream");
    574      log += ")";
    575 
    576      client.close(Cr.NS_OK);
    577 
    578      // Now both output streams have been closed, and both input streams
    579      // have received the close notification. Stop listening for
    580      // connections.
    581      listener.close();
    582    }
    583 
    584    if (available) {
    585      // Check the message from the server.
    586      Assert.equal(clientScriptableInput.readBytes(20), "After you, Alphonse!");
    587 
    588      // Write our response to the server.
    589      clientOutput.write("No, after you, Gaston!", 22);
    590 
    591      // Ask to be called again, when more input arrives.
    592      clientInput.asyncWait(clientReady, 0, 0, threadManager.currentThread);
    593    }
    594  }
    595 
    596  function serverReady(aStream) {
    597    log += "s";
    598    info("test_keep_when_offline: serverReady called: " + log);
    599    Assert.equal(aStream, serverInput);
    600 
    601    // Check the message from the client.
    602    Assert.equal(serverScriptableInput.readBytes(22), "No, after you, Gaston!");
    603 
    604    // This should not shut things down: Unix domain sockets should
    605    // remain open in offline mode.
    606    if (count == 5) {
    607      Services.io.offline = true;
    608      log += "o";
    609    }
    610 
    611    if (count < 10) {
    612      // Insist.
    613      serverOutput.write("After you, Alphonse!", 20);
    614      count++;
    615 
    616      // As long as the input stream is open, always ask to be called again
    617      // when more input arrives.
    618      serverInput.asyncWait(serverReady, 0, 0, threadManager.currentThread);
    619    } else if (count == 10) {
    620      // After sending ten times and receiving ten replies, we're not
    621      // going to send any more. Close the server's output stream; the
    622      // client's input stream should see this.
    623      info("closing server transport");
    624      server.close(Cr.NS_OK);
    625      log += "(";
    626    }
    627  }
    628 
    629  // We have stopped listening.
    630  function onStopListening(aServ, aStatus) {
    631    info("test_keep_when_offline: onStopListening called");
    632    log += "L";
    633    Assert.equal(log, "acscscscscsocscscscscs(c)L");
    634 
    635    Assert.equal(aServ, listener);
    636    Assert.equal(aStatus, Cr.NS_BINDING_ABORTED);
    637 
    638    run_next_test();
    639  }
    640 }
    641 
    642 function test_abstract_address_socket() {
    643  const socketname = "abstractsocket";
    644  let server = new UnixAbstractServerSocket(socketname, -1);
    645  server.asyncListen({
    646    onSocketAccepted: (aServ, aTransport) => {
    647      let serverInput = aTransport
    648        .openInputStream(0, 0, 0)
    649        .QueryInterface(Ci.nsIAsyncInputStream);
    650      let serverOutput = aTransport.openOutputStream(0, 0, 0);
    651 
    652      serverInput.asyncWait(
    653        () => {
    654          info(
    655            "called test_abstract_address_socket's onSocketAccepted's onInputStreamReady"
    656          );
    657 
    658          // Receive data from the client, and send back a response.
    659          let serverScriptableInput = new ScriptableInputStream(serverInput);
    660          Assert.equal(serverScriptableInput.readBytes(9), "ping ping");
    661          serverOutput.write("pong", 4);
    662        },
    663        0,
    664        0,
    665        threadManager.currentThread
    666      );
    667    },
    668    onStopListening: () => {},
    669  });
    670 
    671  let client =
    672    socketTransportService.createUnixDomainAbstractAddressTransport(socketname);
    673  Assert.equal(client.host, socketname);
    674  Assert.equal(client.port, 0);
    675  let clientInput = client
    676    .openInputStream(0, 0, 0)
    677    .QueryInterface(Ci.nsIAsyncInputStream);
    678  let clientOutput = client.openOutputStream(0, 0, 0);
    679 
    680  clientOutput.write("ping ping", 9);
    681 
    682  clientInput.asyncWait(
    683    () => {
    684      let clientScriptInput = new ScriptableInputStream(clientInput);
    685      let available = clientScriptInput.available();
    686      if (available) {
    687        Assert.equal(clientScriptInput.readBytes(4), "pong");
    688 
    689        client.close(Cr.NS_OK);
    690        server.close(Cr.NS_OK);
    691 
    692        run_next_test();
    693      }
    694    },
    695    0,
    696    0,
    697    threadManager.currentThread
    698  );
    699 }