Skip to content

Commit 1902354

Browse files
committed
Properly handle SO_LINGER set/get sockopt
Fixes #4040
1 parent 40f6b41 commit 1902354

File tree

2 files changed

+24
-17
lines changed

2 files changed

+24
-17
lines changed

core/src/main/java/org/jruby/ext/socket/RubyBasicSocket.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,20 @@ public IRubyObject getsockopt(ThreadContext context, IRubyObject _level, IRubyOb
266266
}
267267

268268
int value = SocketType.forChannel(channel).getSocketOption(channel, opt);
269-
ByteList packedValue = Option.packInt(value);
269+
ByteList packedValue;
270+
271+
if (opt == SocketOption.SO_LINGER) {
272+
if (value == -1) {
273+
// Hardcode to 0, because Java Socket API drops actual value
274+
// if lingering is disabled
275+
packedValue = Option.packLinger(0, 0);
276+
} else {
277+
packedValue = Option.packLinger(1, value);
278+
}
279+
} else {
280+
packedValue = Option.packInt(value);
281+
}
282+
270283
return new Option(runtime, ProtocolFamily.PF_INET, level, opt, packedValue);
271284

272285
default:
@@ -307,17 +320,12 @@ public IRubyObject setsockopt(ThreadContext context, IRubyObject _level, IRubyOb
307320
case SOL_UDP:
308321

309322
if (opt == SocketOption.SO_LINGER) {
310-
if(val instanceof RubyBoolean && !val.isTrue()) {
311-
socketType.setSoLinger(channel, false, 0);
323+
if (val instanceof RubyString) {
324+
int[] linger = Option.unpackLinger(val.convertToString().getByteList());
325+
socketType.setSoLinger(channel, linger[0] != 0, linger[1]);
312326
} else {
313-
int num = asNumber(val);
314-
if(num == -1) {
315-
socketType.setSoLinger(channel, false, 0);
316-
} else {
317-
socketType.setSoLinger(channel, true, num);
318-
}
327+
throw runtime.newErrnoEINVALError("setsockopt(2)");
319328
}
320-
321329
} else {
322330
socketType.setSocketOption(channel, opt, asNumber(val));
323331
}

core/src/main/java/org/jruby/ext/socket/SocketType.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public SocketAddress getLocalSocketAddress(Channel channel) {
177177
private DatagramSocket toSocket(Channel channel) {
178178
return ((DatagramChannel)channel).socket();
179179
}
180-
180+
181181
public int getSoTimeout(Channel channel) throws IOException {
182182
return toSocket(channel).getSoTimeout();
183183
}
@@ -241,14 +241,14 @@ public void shutdownOutput(Channel channel) throws IOException {
241241
},
242242

243243
UNKNOWN(Sock.SOCK_STREAM);
244-
244+
245245
public static SocketType forChannel(Channel channel) {
246246
if (channel instanceof SocketChannel) {
247247
return SOCKET;
248-
248+
249249
} else if (channel instanceof ServerSocketChannel) {
250250
return SERVER;
251-
251+
252252
} else if (channel instanceof DatagramChannel) {
253253
return DATAGRAM;
254254

@@ -301,7 +301,7 @@ public SocketAddress getLocalSocketAddress(Channel channel) {
301301
public Sock getSocketType() {
302302
return sock;
303303
}
304-
304+
305305
public int getSocketOption(Channel channel, SocketOption option) throws IOException {
306306
switch (option) {
307307

@@ -312,8 +312,7 @@ public int getSocketOption(Channel channel, SocketOption option) throws IOExcept
312312
return getKeepAlive(channel) ? 1 : 0;
313313

314314
case SO_LINGER: {
315-
int linger = getSoLinger(channel);
316-
return linger < 0 ? 0 : linger;
315+
return getSoLinger(channel);
317316
}
318317

319318
case SO_OOBINLINE:

0 commit comments

Comments
 (0)