From 5c31cac04b07979485637806e4635b584ebfb71c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 24 Jan 2017 16:47:09 +0100 Subject: [PATCH] before writing check if the socket has been destroyed, fixes #19176 --- src/typings/node.d.ts | 3 +++ src/vs/base/parts/ipc/node/ipc.net.ts | 11 +++++++---- src/vs/base/parts/ipc/test/node/ipc.net.test.ts | 6 ++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/typings/node.d.ts b/src/typings/node.d.ts index 2dbf882d869..dee050edebd 100644 --- a/src/typings/node.d.ts +++ b/src/typings/node.d.ts @@ -1239,6 +1239,9 @@ declare module "net" { unref(): void; ref(): void; + /** A Boolean value that indicates if the connection is destroyed or not. Once a connection is destroyed no further data can be transferred using it.*/ + destroyed: boolean; + remoteAddress: string; remoteFamily: string; remotePort: number; diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index fe2db748080..15e7366b946 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -6,7 +6,6 @@ 'use strict'; import { Socket, Server as NetServer, createConnection, createServer } from 'net'; -import { Duplex } from 'stream'; import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter, once, mapEvent } from 'vs/base/common/event'; import { fromEventEmitter } from 'vs/base/node/event'; @@ -33,7 +32,7 @@ export class Protocol implements IMessagePassingProtocol { readonly onMessage: Event = this._onMessage.event; - constructor(private stream: Duplex) { + constructor(private _socket: Socket) { let chunks = []; let totalLength = 0; @@ -44,7 +43,7 @@ export class Protocol implements IMessagePassingProtocol { bodyLen: -1, }; - stream.on('data', (data: Buffer) => { + _socket.on('data', (data: Buffer) => { chunks.push(data); totalLength += data.length; @@ -139,12 +138,16 @@ export class Protocol implements IMessagePassingProtocol { private _writeSoon(header: Buffer, data: Buffer): void { if (this._writeBuffer.add(header, data)) { setImmediate(() => { + // return early if socket has been destroyed in the meantime + if (this._socket.destroyed) { + return; + } // we ignore the returned value from `write` because we would have to cached the data // anyways and nodejs is already doing that for us: // > https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback // > However, the false return value is only advisory and the writable stream will unconditionally // > accept and buffer chunk even if it has not not been allowed to drain. - this.stream.write(this._writeBuffer.take()); + this._socket.write(this._writeBuffer.take()); }); } } diff --git a/src/vs/base/parts/ipc/test/node/ipc.net.test.ts b/src/vs/base/parts/ipc/test/node/ipc.net.test.ts index de1afd9faef..6b48161d026 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.net.test.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.net.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { TPromise } from 'vs/base/common/winjs.base'; -import { Duplex } from 'stream'; +import { Socket } from 'net'; import { EventEmitter } from 'events'; import { Protocol } from 'vs/base/parts/ipc/node/ipc.net'; @@ -15,6 +15,8 @@ class MockDuplex extends EventEmitter { private _cache: Buffer[] = []; + readonly destroyed = false; + private _deliver(): void { if (this._cache.length) { const data = Buffer.concat(this._cache); @@ -33,7 +35,7 @@ class MockDuplex extends EventEmitter { suite('IPC, Socket Protocol', () => { - let stream: Duplex; + let stream: Socket; setup(() => { stream = new MockDuplex();