org.jruby.util.io.Sockaddr Maven / Gradle / Ivy
package org.jruby.util.io;
import jnr.constants.platform.AddressFamily;
import jnr.unixsocket.UnixSocketAddress;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyNumeric;
import org.jruby.exceptions.RaiseException;
import org.jruby.ext.socket.Addrinfo;
import org.jruby.platform.Platform;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import org.jruby.RubyString;
import org.jruby.ext.socket.SocketUtils;
import org.jruby.runtime.Helpers;
public class Sockaddr {
public static InetAddress addressFromString(Ruby runtime, String s) {
try {
byte[] bs = ByteList.plain(s);
return InetAddress.getByAddress(bs);
} catch(Exception e) {
throw sockerr(runtime, "strtoaddr: " + e.toString());
}
}
public static String stringFromAddress(Ruby runtime, InetAddress as) {
try {
return new String(ByteList.plain(as.getAddress()));
} catch(Exception e) {
throw sockerr(runtime, "addrtostr: " + e.toString());
}
}
public static InetSocketAddress addressFromSockaddr_in(ThreadContext context, IRubyObject arg) {
RubyArray sockaddr = (RubyArray) unpack_sockaddr_in(context, arg);
IRubyObject addr = sockaddr.pop(context);
IRubyObject _port = sockaddr.pop(context);
int port = SocketUtils.portToInt(_port);
return new InetSocketAddress(
addr.convertToString().toString(), port);
}
public static InetSocketAddress addressFromArg(ThreadContext context, IRubyObject arg) {
InetSocketAddress iaddr;
if (arg instanceof Addrinfo) {
Addrinfo addrinfo = (Addrinfo)arg;
iaddr = new InetSocketAddress(addrinfo.getInetAddress(), addrinfo.getPort());
} else {
iaddr = addressFromSockaddr_in(context, arg);
}
return iaddr;
}
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);
return new UnixSocketAddress(new File(pathStr));
}
public static IRubyObject unpack_sockaddr_in(ThreadContext context, IRubyObject addr) {
Ruby runtime = context.runtime;
ByteList val = addr.convertToString().getByteList();
validateSockaddr(runtime, val);
int port = ((val.get(2)&0xff) << 8) + (val.get(3)&0xff);
StringBuilder sb = new StringBuilder()
.append(val.get(4)&0xff)
.append(".")
.append(val.get(5)&0xff)
.append(".")
.append(val.get(6)&0xff)
.append(".")
.append(val.get(7)&0xff);
IRubyObject[] result = new IRubyObject[]{
runtime.newFixnum(port),
runtime.newString(sb.toString())};
return runtime.newArrayNoCopy(result);
}
public static IRubyObject packSockaddrFromAddress(ThreadContext context, InetSocketAddress sock) {
if (sock == null) {
return Sockaddr.pack_sockaddr_in(context, 0, "");
} else {
return Sockaddr.pack_sockaddr_in(context, sock);
}
}
public static IRubyObject pack_sockaddr_in(ThreadContext context, int iport, String host) {
ByteArrayOutputStream bufS = new ByteArrayOutputStream();
try {
DataOutputStream ds = new DataOutputStream(bufS);
writeSockaddrHeader(AddressFamily.AF_INET, ds);
writeSockaddrPort(ds, iport);
try {
if(host != null && "".equals(host)) {
ds.writeInt(0);
} else {
InetAddress[] addrs = InetAddress.getAllByName(host);
byte[] addr = addrs[0].getAddress();
ds.write(addr, 0, addr.length);
}
} catch (UnknownHostException e) {
throw sockerr(context.runtime, "getaddrinfo: No address associated with nodename");
}
writeSockaddrFooter(ds);
} catch (IOException e) {
throw sockerr(context.runtime, "pack_sockaddr_in: internal error");
}
return context.runtime.newString(new ByteList(bufS.toByteArray(),
false));
}
public static IRubyObject pack_sockaddr_in(ThreadContext context, InetSocketAddress sock) {
ByteArrayOutputStream bufS = new ByteArrayOutputStream();
try {
DataOutputStream ds = new DataOutputStream(bufS);
writeSockaddrHeader(AddressFamily.AF_INET, ds);
writeSockaddrPort(ds, sock);
String host = sock.getAddress().getHostAddress();
if(host != null && "".equals(host)) {
ds.writeInt(0);
} else {
byte[] addr = sock.getAddress().getAddress();
ds.write(addr, 0, addr.length);
}
writeSockaddrFooter(ds);
} catch (IOException e) {
throw sockerr(context.runtime, "pack_sockaddr_in: internal error");
}
return context.runtime.newString(new ByteList(bufS.toByteArray(),
false));
}
public static void writeSockaddrHeader(AddressFamily family, DataOutputStream ds) throws IOException {
int value = family.intValue();
int high = (value & 0xff00) >> 8;
int low = value & 0xff;
ds.write((byte)high);
ds.write((byte)low);
}
public static void writeSockaddrFooter(DataOutputStream ds) throws IOException {
ds.writeInt(0);
ds.writeInt(0);
}
public static void writeSockaddrPort(DataOutputStream ds, InetSocketAddress sockaddr) throws IOException {
writeSockaddrPort(ds, sockaddr.getPort());
}
public static void writeSockaddrPort(DataOutputStream ds, int port) throws IOException {
ds.write(port >> 8);
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");
}
}
private static RuntimeException sockerr(Ruby runtime, String msg) {
return new RaiseException(runtime, runtime.getClass("SocketError"), msg, true);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy