Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ public void onClose(int id, Exception e) {
sendEvent("close", eventParams);
}

public void onEnd(int id) {
WritableMap eventParams = Arguments.createMap();
eventParams.putInt("id", id);
sendEvent("end", eventParams);
}

public void onError(int id, Exception e) {
Log.e(TcpSocketModule.TAG, "Exception on socket " + id, e);
String error = e.getMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ public void run() {
if (bufferCount > 0) {
receiverListener.onData(socketId, Arrays.copyOfRange(buffer, 0, bufferCount));
} else if (bufferCount == -1) {
clientSocket.destroy();
receiverListener.onEnd(socketId);
break;
}
}
} catch (IOException | InterruptedException ioe) {
Expand Down
1 change: 1 addition & 0 deletions ios/TcpSocketClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef enum RCTTCPError RCTTCPError;
- (void)onClose:(TcpSocketClient *)client withError:(NSError *)err;
- (void)onError:(TcpSocketClient *)client withError:(NSError *)err;
- (void)onWrittenData:(TcpSocketClient *)client msgId:(NSNumber *)msgId;
- (void)onEnd:(NSNumber *)clientID;
- (NSNumber *)getNextId;

@end
Expand Down
5 changes: 2 additions & 3 deletions ios/TcpSocketClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -579,9 +579,8 @@ - (void)socket:(GCDAsyncSocket *)sock
}

- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock {
// TODO : investigate for half-closed sockets
// for now close the stream completely
[sock disconnect];
// Half-closed socket support
[_clientDelegate onEnd:_id];
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
Expand Down
9 changes: 8 additions & 1 deletion ios/TcpSockets.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ @implementation TcpSockets {
- (NSArray<NSString *> *)supportedEvents {
return @[
@"connect", @"listening", @"connection", @"secureConnection", @"data",
@"close", @"error", @"written"
@"close", @"error", @"written", @"end"
];
}

Expand Down Expand Up @@ -217,6 +217,13 @@ - (void)onWrittenData:(TcpSocketClient *)client msgId:(NSNumber *)msgId {
}];
}

- (void)onEnd:(NSNumber *)clientID {
[self sendEventWithName:@"end"
body:@{
@"id" : clientID
}];
}

- (void)onConnect:(TcpSocketClient *)client {
GCDAsyncSocket *socket = [client getSocket];
[self sendEventWithName:@"connect"
Expand Down
4 changes: 4 additions & 0 deletions src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ export default class Server extends EventEmitter {
const keepAliveDelay = this._serverOptions.keepAliveInitialDelay || 0;
newSocket.setKeepAlive(this._serverOptions.keepAlive, keepAliveDelay);
}

if (this._serverOptions.allowHalfOpen !== undefined) {
newSocket.allowHalfOpen = this._serverOptions.allowHalfOpen;
}
}

return newSocket;
Expand Down
11 changes: 11 additions & 0 deletions src/Socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default class Socket extends EventEmitter {
this.remoteAddress = undefined;
this.remotePort = undefined;
this.remoteFamily = undefined;
this.allowHalfOpen = false; // Default per Node.js spec
this._registerEvents();
}

Expand Down Expand Up @@ -457,6 +458,15 @@ export default class Socket extends EventEmitter {
this.destroy();
this.emit('error', evt.error);
});
this._endListener = this._eventEmitter.addListener('end', (evt) => {
if (evt.id !== this._id) return;
this._readyState = 'readOnly'; // Can still write but not read
this.emit('end');
// If allowHalfOpen is false, auto-close the writable side
if (!this.allowHalfOpen) {
this.end();
}
});
this._closeListener = this._eventEmitter.addListener('close', (evt) => {
if (evt.id !== this._id) return;
this._setDisconnected();
Expand All @@ -479,6 +489,7 @@ export default class Socket extends EventEmitter {
_unregisterEvents() {
this._dataListener?.remove();
this._errorListener?.remove();
this._endListener?.remove();
this._closeListener?.remove();
this._connectListener?.remove();
this._writtenListener?.remove();
Expand Down