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

Add Socket.unpack_sockaddr #4066

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions core/src/main/java/org/jruby/ext/socket/RubySocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ public static IRubyObject getservbyname(ThreadContext context, IRubyObject recv,

@JRubyMethod(name = {"pack_sockaddr_in", "sockaddr_in"}, meta = true)
public static IRubyObject pack_sockaddr_in(ThreadContext context, IRubyObject recv, IRubyObject port, IRubyObject host) {
return SocketUtils.pack_sockaddr_in(context, port, host);
return Sockaddr.pack_sockaddr_in(context, port, host);
}

@JRubyMethod(meta = true)
Expand All @@ -313,7 +313,12 @@ public static IRubyObject unpack_sockaddr_in(ThreadContext context, IRubyObject

@JRubyMethod(name = {"pack_sockaddr_un", "sockaddr_un"}, meta = true)
public static IRubyObject pack_sockaddr_un(ThreadContext context, IRubyObject recv, IRubyObject filename) {
return SocketUtils.pack_sockaddr_un(context, filename);
return Sockaddr.pack_sockaddr_un(context, filename);
}

@JRubyMethod(meta = true)
public static IRubyObject unpack_sockaddr_un(ThreadContext context, IRubyObject recv, IRubyObject addr) {
return Sockaddr.unpack_sockaddr_un(context, addr);
}

@JRubyMethod(meta = true)
Expand Down
35 changes: 6 additions & 29 deletions core/src/main/java/org/jruby/ext/socket/SocketUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,42 +130,19 @@ public static IRubyObject getservbyname(ThreadContext context, IRubyObject[] arg
return runtime.newFixnum(port);
}

@Deprecated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@etehtsea Since these are public static methods we should deprecate and call to the new location since there is a small possibility some Java Native Extension could be calling them.

public static IRubyObject pack_sockaddr_in(ThreadContext context, IRubyObject port, IRubyObject host) {
final int portNum;
if ( ! port.isNil() ) {
portNum = port instanceof RubyString ?
Integer.parseInt(port.convertToString().toString()) :
RubyNumeric.fix2int(port);
}
else {
portNum = 0;
}

final String hostStr = host.isNil() ? null : host.convertToString().toString();
return Sockaddr.pack_sockaddr_in(context, portNum, hostStr);
return Sockaddr.pack_sockaddr_in(context, port, host);
}

@Deprecated
public static RubyArray unpack_sockaddr_in(ThreadContext context, IRubyObject addr) {
return Sockaddr.unpack_sockaddr_in(context, addr);
}

@Deprecated
public static IRubyObject pack_sockaddr_un(ThreadContext context, IRubyObject filename) {
ByteList str = filename.convertToString().getByteList();

AddressFamily af = AddressFamily.AF_UNIX;
int high = (af.intValue() & 0xff00) >> 8;
int low = af.intValue() & 0xff;

ByteList bl = new ByteList();
bl.append((byte)high);
bl.append((byte)low);
bl.append(str);

for(int i=str.length();i<104;i++) {
bl.append((byte)0);
}

return context.runtime.newString(bl);
return Sockaddr.pack_sockaddr_un(context, filename);
}

public static IRubyObject gethostbyname(ThreadContext context, IRubyObject hostname) {
Expand Down Expand Up @@ -398,7 +375,7 @@ public static IRubyObject getnameinfo(ThreadContext context, IRubyObject[] args)
Matcher m = STRING_IPV4_ADDRESS_PATTERN.matcher(arg);

if (!m.matches()) {
RubyArray portAndHost = unpack_sockaddr_in(context, arg0);
RubyArray portAndHost = Sockaddr.unpack_sockaddr_in(context, arg0);

if (portAndHost.size() != 2) {
throw runtime.newArgumentError("invalid address representation");
Expand Down
162 changes: 107 additions & 55 deletions core/src/main/java/org/jruby/util/io/Sockaddr.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,61 +66,37 @@ public static InetSocketAddress addressFromArg(ThreadContext context, IRubyObjec
}

public static UnixSocketAddress addressFromSockaddr_un(ThreadContext context, IRubyObject arg) {
ByteList bl = arg.convertToString().getByteList();
byte[] raw = bl.bytes();

int end = 2;
for (; end < raw.length; end++) {
if (raw[end] == 0) break;
}

ByteList path = new ByteList(raw, 2, end, false);
String pathStr = Helpers.decodeByteList(context.runtime, path);
String pathStr = pathFromSockaddr_un(context, arg);

return new UnixSocketAddress(new File(pathStr));
}

public static RubyArray unpack_sockaddr_in(ThreadContext context, IRubyObject addr) {
final Ruby runtime = context.runtime;
ByteList val = addr.convertToString().getByteList();

validateSockaddr(runtime, val);

int port = ((val.get(2)&0xff) << 8) + (val.get(3)&0xff);

AddressFamily af = getAddressFamilyFromSockaddr(runtime, val);

final StringBuilder formatAddr = new StringBuilder();

if (af == AddressFamily.AF_INET) {
formatAddr.append(val.get(4) & 0xff)
.append('.')
.append(val.get(5) & 0xff)
.append('.')
.append(val.get(6) & 0xff)
.append('.')
.append(val.get(7) & 0xff);

} else { // if af == AddressFamily.AF_INET6
for (int i = 4; i <= 19; i++) {
if (i != 4 && i % 2 == 0) formatAddr.append(':');
formatAddr.append(Integer.toHexString(val.get(i) & 0xff | 0x100).substring(1));
}
}

return RubyArray.newArray(runtime, runtime.newFixnum(port), RubyString.newString(runtime, formatAddr));
}

public static IRubyObject packSockaddrFromAddress(ThreadContext context, InetSocketAddress sock) {
if (sock == null) {
return Sockaddr.pack_sockaddr_in(context, 0, "");
return pack_sockaddr_in(context, 0, "");
} else {
return Sockaddr.pack_sockaddr_in(context, sock);
return pack_sockaddr_in(context, sock);
}
}

public static IRubyObject pack_sockaddr_in(ThreadContext context, IRubyObject port, IRubyObject host) {
final int portNum;
if ( ! port.isNil() ) {
portNum = port instanceof RubyString ?
Integer.parseInt(port.convertToString().toString()) :
RubyNumeric.fix2int(port);
}
else {
portNum = 0;
}

final String hostStr = host.isNil() ? null : host.convertToString().toString();
return pack_sockaddr_in(context, portNum, hostStr);
}

public static IRubyObject pack_sockaddr_in(ThreadContext context, int port, String host) {
ByteArrayOutputStream bufS = new ByteArrayOutputStream();

try {
DataOutputStream ds = new DataOutputStream(bufS);

Expand Down Expand Up @@ -189,6 +165,76 @@ public static IRubyObject pack_sockaddr_in(ThreadContext context, InetSocketAddr
false));
}

public static RubyArray unpack_sockaddr_in(ThreadContext context, IRubyObject addr) {
final Ruby runtime = context.runtime;
ByteList val = addr.convertToString().getByteList();

AddressFamily af = getAddressFamilyFromSockaddr(runtime, val);

if (af != AddressFamily.AF_INET &&
af != AddressFamily.AF_INET6) {
throw runtime.newArgumentError("can't resolve socket address of wrong type");
}

int port = ((val.get(2)&0xff) << 8) + (val.get(3)&0xff);

final StringBuilder formatAddr = new StringBuilder();

if (af == AddressFamily.AF_INET) {
formatAddr.append(val.get(4) & 0xff)
.append('.')
.append(val.get(5) & 0xff)
.append('.')
.append(val.get(6) & 0xff)
.append('.')
.append(val.get(7) & 0xff);

} else { // if af == AddressFamily.AF_INET6
for (int i = 4; i <= 19; i++) {
if (i != 4 && i % 2 == 0) formatAddr.append(':');
formatAddr.append(Integer.toHexString(val.get(i) & 0xff | 0x100).substring(1));
}
}

return RubyArray.newArray(runtime, runtime.newFixnum(port), RubyString.newString(runtime, formatAddr));
}

public static IRubyObject pack_sockaddr_un(ThreadContext context, IRubyObject filename) {
ByteArrayOutputStream bufS = new ByteArrayOutputStream();

try {
DataOutputStream ds = new DataOutputStream(bufS);

String path = filename.convertToString().asJavaString();

writeSockaddrHeader(AddressFamily.AF_UNIX, ds);
ds.writeBytes(path);

for(int i=path.length();i<104;i++) {
ds.writeInt(0);
}
} catch (IOException e) {
throw sockerr(context.runtime, "pack_sockaddr_un: internal error");
}

return context.runtime.newString(new ByteList(bufS.toByteArray(),
false));
}

public static IRubyObject unpack_sockaddr_un(ThreadContext context, IRubyObject addr) {
final Ruby runtime = context.runtime;
ByteList val = addr.convertToString().getByteList();

AddressFamily af = getAddressFamilyFromSockaddr(runtime, val);

if (af != AddressFamily.AF_UNIX) {
throw runtime.newArgumentError("not an AF_UNIX sockaddr");
}

String filename = pathFromSockaddr_un(context, addr);
return context.runtime.newString(filename);
}

public static void writeSockaddrHeader(AddressFamily family, DataOutputStream ds) throws IOException {
int value = family.intValue();
int high = (value & 0xff00) >> 8;
Expand All @@ -212,26 +258,32 @@ public static void writeSockaddrPort(DataOutputStream ds, int port) throws IOExc
ds.write(port);
}

public static void validateSockaddr(Ruby runtime, ByteList val) {
int high = val.get(0) & 0xff;
int low = val.get(1) & 0xff;

AddressFamily af = AddressFamily.valueOf((high << 8) + low);

if (af != AddressFamily.AF_INET &&
af != AddressFamily.AF_INET6) {
throw runtime.newArgumentError("can't resolve socket address of wrong type");
public static AddressFamily getAddressFamilyFromSockaddr(Ruby runtime, ByteList val) {
if (val.length() < 2) {
throw runtime.newArgumentError("too short sockaddr");
}
}

public static AddressFamily getAddressFamilyFromSockaddr(Ruby runtime, ByteList val) {
int high = val.get(0) & 0xff;
int low = val.get(1) & 0xff;

return AddressFamily.valueOf((high << 8) + low);
}
}

private static RuntimeException sockerr(Ruby runtime, String msg) {
return new RaiseException(runtime, runtime.getClass("SocketError"), msg, true);
}

private static String pathFromSockaddr_un(ThreadContext context, IRubyObject arg) {
ByteList bl = arg.convertToString().getByteList();
byte[] raw = bl.bytes();

int end = 2;
for (; end < raw.length; end++) {
if (raw[end] == 0) break;
}

ByteList path = new ByteList(raw, 2, end, false);

return Helpers.decodeByteList(context.runtime, path);
}
}

This file was deleted.

1 change: 0 additions & 1 deletion spec/tags/ruby/library/socket/socket/sockaddr_un_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion test/mri/excludes/TestSocket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@
exclude :test_udp_server_sockets_in_rescue, "needs investigation"
exclude :test_unix, "needs investigation"
exclude :test_unix_server_socket, "needs investigation"
exclude :test_unpack_sockaddr, "needs investigation"