Skip to content

Commit 9f22c70

Browse files
committed
Add UNIX protocol implementation, and add enum for QUIC
1 parent acb9e5d commit 9f22c70

3 files changed

Lines changed: 61 additions & 13 deletions

File tree

src/main/java/io/ipfs/multiaddr/MultiAddress.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.io.*;
66
import java.util.*;
7+
import java.util.stream.*;
78

89
public class MultiAddress
910
{
@@ -67,11 +68,15 @@ private static byte[] decodeFromString(String addr) {
6768
if (p.size() == 0)
6869
continue;
6970

70-
String component = parts[i++];
71+
String component = p.isTerminal() ?
72+
Stream.of(Arrays.copyOfRange(parts, i, parts.length)).reduce("", (a, b) -> a + "/" + b) :
73+
parts[i++];
7174
if (component.length() == 0)
7275
throw new IllegalStateException("Protocol requires address, but non provided!");
7376

7477
bout.write(p.addressToBytes(component));
78+
if (p.isTerminal())
79+
break;
7580
}
7681
return bout.toByteArray();
7782
} catch (IOException e) {

src/main/java/io/ipfs/multiaddr/Protocol.java

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ enum Type {
1919
SCTP(132, 16, "sctp"),
2020
UTP(301, 0, "utp"),
2121
UDT(302, 0, "udt"),
22+
UNIX(400, LENGTH_PREFIXED_VAR_SIZE, "unix"),
2223
IPFS(421, LENGTH_PREFIXED_VAR_SIZE, "ipfs"),
24+
QUIC(460, 0, "quic"),
2325
HTTPS(443, 0, "https"),
2426
HTTP(480, 0, "http"),
2527
ONION(444, 80, "onion");
@@ -52,6 +54,10 @@ public void appendCode(OutputStream out) throws IOException {
5254
out.write(type.encoded);
5355
}
5456

57+
public boolean isTerminal() {
58+
return type == Type.UNIX;
59+
}
60+
5561
public int size() {
5662
return type.size;
5763
}
@@ -95,29 +101,43 @@ public byte[] addressToBytes(String addr) {
95101
bout.write(varint);
96102
bout.write(hashBytes);
97103
return bout.toByteArray();
98-
case ONION:
104+
case ONION: {
99105
String[] split = addr.split(":");
100106
if (split.length != 2)
101-
throw new IllegalStateException("Onion address needs a port: "+addr);
107+
throw new IllegalStateException("Onion address needs a port: " + addr);
102108

103109
// onion address without the ".onion" substring
104110
if (split[0].length() != 16)
105-
throw new IllegalStateException("failed to parse "+name()+" addr: "+addr+" not a Tor onion address.");
111+
throw new IllegalStateException("failed to parse " + name() + " addr: " + addr + " not a Tor onion address.");
106112

107113
byte[] onionHostBytes = Base32.decode(split[0].toUpperCase());
108114
int port = Integer.parseInt(split[1]);
109115
if (port > 65535)
110-
throw new IllegalStateException("Port is > 65535: "+port);
116+
throw new IllegalStateException("Port is > 65535: " + port);
111117

112118
if (port < 1)
113-
throw new IllegalStateException("Port is < 1: "+port);
119+
throw new IllegalStateException("Port is < 1: " + port);
114120

115121
ByteArrayOutputStream b = new ByteArrayOutputStream();
116122
DataOutputStream dout = new DataOutputStream(b);
117123
dout.write(onionHostBytes);
118124
dout.writeShort(port);
119125
dout.flush();
120126
return b.toByteArray();
127+
}
128+
case UNIX: {
129+
if (addr.startsWith("/"))
130+
addr = addr.substring(1);
131+
byte[] path = addr.getBytes();
132+
ByteArrayOutputStream b = new ByteArrayOutputStream();
133+
DataOutputStream dout = new DataOutputStream(b);
134+
byte[] length = new byte[(32 - Integer.numberOfLeadingZeros(path.length)+6)/7];
135+
putUvarint(length, path.length);
136+
dout.write(length);
137+
dout.write(path);
138+
dout.flush();
139+
return b.toByteArray();
140+
}
121141
}
122142
} catch (IOException e) {
123143
throw new RuntimeException(e);
@@ -131,11 +151,11 @@ public String readAddress(InputStream in) throws IOException {
131151
switch (type) {
132152
case IP4:
133153
buf = new byte[sizeForAddress];
134-
in.read(buf);
154+
read(in, buf);
135155
return Inet4Address.getByAddress(buf).toString().substring(1);
136156
case IP6:
137157
buf = new byte[sizeForAddress];
138-
in.read(buf);
158+
read(in, buf);
139159
return Inet6Address.getByAddress(buf).toString().substring(1);
140160
case TCP:
141161
case UDP:
@@ -144,15 +164,32 @@ public String readAddress(InputStream in) throws IOException {
144164
return Integer.toString((in.read() << 8) | (in.read()));
145165
case IPFS:
146166
buf = new byte[sizeForAddress];
147-
in.read(buf);
167+
read(in, buf);
148168
return Cid.cast(buf).toString();
149169
case ONION:
150170
byte[] host = new byte[10];
151-
in.read(host);
171+
read(in, host);
152172
String port = Integer.toString((in.read() << 8) | (in.read()));
153173
return Base32.encode(host)+":"+port;
174+
case UNIX:
175+
buf = new byte[sizeForAddress];
176+
read(in, buf);
177+
return new String(buf);
178+
}
179+
throw new IllegalStateException("Unimplemented protocol type: "+type.name);
180+
}
181+
182+
private static void read(InputStream in, byte[] b) throws IOException {
183+
read(in, b, 0, b.length);
184+
}
185+
186+
private static void read(InputStream in, byte[] b, int offset, int len) throws IOException {
187+
int total=0, r=0;
188+
while (total < len && r != -1) {
189+
r = in.read(b, offset + total, len - total);
190+
if (r >=0)
191+
total += r;
154192
}
155-
throw new IllegalStateException("Unimplemented protocl type: "+type.name);
156193
}
157194

158195
public int sizeForAddress(InputStream in) throws IOException {

src/test/java/io/ipfs/api/MultiAddressTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public void fails() {
3636
"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
3737
"/ip4/127.0.0.1/tcp",
3838
"/ip4/127.0.0.1/ipfs",
39-
"/ip4/127.0.0.1/ipfs/tcp"
39+
"/ip4/127.0.0.1/ipfs/tcp",
40+
"/quic/65536",
41+
"/unix"
4042
).flatMap(s -> {
4143
try {
4244
new MultiAddress(s);
@@ -79,7 +81,11 @@ public void succeeds() {
7981
"/ip4/127.0.0.1/tcp/1234",
8082
"/ip4/127.0.0.1/tcp/1234/",
8183
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
82-
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234"
84+
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
85+
"/unix/a/b/c/d/e",
86+
"/unix/stdio",
87+
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
88+
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio"
8389
).flatMap(s -> {
8490
try {
8591
new MultiAddress(s);

0 commit comments

Comments
 (0)