Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIx socket option handling #37

Merged
merged 1 commit into from
Apr 2, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fix NPE after 2nd send() in unconnected channel + cleanup.
[#33](https://github.com/netsec-ethz/scion-java-client/pull/33)
- Fixed traffic class not set. [#36](https://github.com/netsec-ethz/scion-java-client/pull/36)
- Fixed handling of channel options. [#37](https://github.com/netsec-ethz/scion-java-client/pull/37)

### Removed

Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ Options are defined in `ScionSocketOptions`, see javadoc for details.
| `SN_API_WRITE_TO_USER_BUFFER` | `false` | Throw exception when receiving an invalid packet |
| `SN_PATH_EXPIRY_MARGIN` | `2` | A new path is requested if `now + margin > pathExpirationDate` |

The following standard options are **not** supported:

| Option |
|--------------------------------|
| `StandardSocketOptions.SO_BROADCAST` |
| `StandardSocketOptions.IP_MULTICAST_IF` |
| `StandardSocketOptions.IP_MULTICAST_TTL` |
| `StandardSocketOptions.IP_MULTICAST_LOOP` |

## Performance pitfalls

- **Using `SocketAddress` for `send()`**. `send(buffer, socketAddress)` is a convenience function. However, when sending
Expand Down Expand Up @@ -248,8 +257,8 @@ attempt to get network information in the following order until it succeeds:
- Check for DNS NAPTR record (if record entry name is given)
- Check for to daemon

The reason that the daemon is checked last is that it has a default setting (localhost:30255) while
the other options are skipped if no property or environment variable is defined.
The reason that the daemon is checked last is that it has a default setting (`localhost:30255`)
while the other options are skipped if no property or environment variable is defined.

| Option | Java property | Environment variable | Default value |
|-------------------------------------|----------------------------------|------------------------------|---------------|
Expand Down
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
- Multipathing: We probably ignore that for now. Multipathing can be done in
many different ways, it may be difficult to design a one-size-fits-all API.
E.g. "Hercules" uses a round-robin fashion with multiple path to fire UDP packets.
- MulticastSocket / MulticastChannel (?)

- For Android look into
- android.net.Network:
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/org/scion/AbstractDatagramChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ public boolean isConnected() {

@SuppressWarnings({"unchecked", "deprecation"})
public <T> T getOption(SocketOption<T> option) throws IOException {
checkOpen();
synchronized (stateLock) {
if (option instanceof ScionSocketOptions.SciSocketOption) {
if (ScionSocketOptions.SN_API_THROW_PARSER_FAILURE.equals(option)) {
Expand All @@ -402,12 +403,17 @@ public <T> T getOption(SocketOption<T> option) throws IOException {
throw new UnsupportedOperationException();
}
}

if (StandardSocketOptions.SO_BROADCAST.equals(option)) {
throw new UnsupportedOperationException();
}
return channel.getOption(option);
}
}

@SuppressWarnings({"unchecked", "deprecation"})
public <T> C setOption(SocketOption<T> option, T t) throws IOException {
checkOpen();
synchronized (stateLock) {
if (option instanceof ScionSocketOptions.SciSocketOption) {
if (ScionSocketOptions.SN_API_THROW_PARSER_FAILURE.equals(option)) {
Expand All @@ -424,6 +430,9 @@ public <T> C setOption(SocketOption<T> option, T t) throws IOException {
throw new UnsupportedOperationException();
}
} else {
if (StandardSocketOptions.SO_BROADCAST.equals(option)) {
throw new UnsupportedOperationException();
}
channel.setOption(option, t);
}
return (C) this;
Expand Down
38 changes: 37 additions & 1 deletion src/test/java/org/scion/api/DatagramChannelApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ void testBug_doubleSendCausesNPE() throws IOException {
}

@Test
void setOption() throws IOException {
void setOption_SCION() throws IOException {
try (DatagramChannel channel = DatagramChannel.open()) {
assertFalse(channel.getOption(ScionSocketOptions.SN_API_THROW_PARSER_FAILURE));
DatagramChannel dc = channel.setOption(ScionSocketOptions.SN_API_THROW_PARSER_FAILURE, true);
Expand All @@ -618,6 +618,14 @@ void setOption() throws IOException {
int tc = channel.getOption(ScionSocketOptions.SN_TRAFFIC_CLASS);
channel.setOption(ScionSocketOptions.SN_TRAFFIC_CLASS, tc + 1);
assertEquals(tc + 1, channel.getOption(ScionSocketOptions.SN_TRAFFIC_CLASS));

channel.close();
assertThrows(
ClosedChannelException.class,
() -> channel.getOption(ScionSocketOptions.SN_PATH_EXPIRY_MARGIN));
assertThrows(
ClosedChannelException.class,
() -> channel.setOption(ScionSocketOptions.SN_PATH_EXPIRY_MARGIN, 11));
}
}

Expand Down Expand Up @@ -650,4 +658,32 @@ void setOption_TrafficClass() throws IOException {
channel.send(buf, dummyAddress);
}
}

@Test
void setOption_Standard() throws IOException {
try (DatagramChannel channel = DatagramChannel.open()) {
DatagramChannel ds = channel.setOption(StandardSocketOptions.SO_RCVBUF, 10000);
assertEquals(channel, ds);
assertEquals(10000, channel.getOption(StandardSocketOptions.SO_RCVBUF));

channel.setOption(StandardSocketOptions.SO_SNDBUF, 10000);
assertEquals(10000, channel.getOption(StandardSocketOptions.SO_SNDBUF));

channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
assertTrue(channel.getOption(StandardSocketOptions.SO_REUSEADDR));

channel.setOption(StandardSocketOptions.IP_TOS, 5);
assertEquals(5, channel.getOption(StandardSocketOptions.IP_TOS));

assertThrows(
UnsupportedOperationException.class,
() -> channel.getOption(StandardSocketOptions.SO_BROADCAST));
channel.close();
assertThrows(
ClosedChannelException.class, () -> channel.getOption(StandardSocketOptions.SO_RCVBUF));
assertThrows(
ClosedChannelException.class,
() -> channel.setOption(StandardSocketOptions.SO_RCVBUF, 10000));
}
}
}