Sockaddr.java

  1. package org.jruby.util.io;

  2. import jnr.constants.platform.AddressFamily;
  3. import jnr.unixsocket.UnixSocketAddress;
  4. import org.jruby.Ruby;
  5. import org.jruby.RubyArray;
  6. import org.jruby.RubyNumeric;
  7. import org.jruby.exceptions.RaiseException;
  8. import org.jruby.ext.socket.Addrinfo;
  9. import org.jruby.platform.Platform;
  10. import org.jruby.runtime.ThreadContext;
  11. import org.jruby.runtime.builtin.IRubyObject;
  12. import org.jruby.util.ByteList;

  13. import java.io.ByteArrayOutputStream;
  14. import java.io.DataOutputStream;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.net.InetAddress;
  18. import java.net.InetSocketAddress;
  19. import java.net.UnknownHostException;
  20. import org.jruby.RubyString;
  21. import org.jruby.ext.socket.SocketUtils;
  22. import org.jruby.runtime.Helpers;

  23. public class Sockaddr {

  24.     public static InetAddress addressFromString(Ruby runtime, String s) {
  25.         try {
  26.             byte[] bs = ByteList.plain(s);
  27.             return InetAddress.getByAddress(bs);
  28.         } catch(Exception e) {
  29.             throw sockerr(runtime, "strtoaddr: " + e.toString());
  30.         }
  31.     }

  32.     public static String stringFromAddress(Ruby runtime, InetAddress as) {
  33.         try {
  34.             return new String(ByteList.plain(as.getAddress()));
  35.         } catch(Exception e) {
  36.             throw sockerr(runtime, "addrtostr: " + e.toString());
  37.         }
  38.     }

  39.     public static InetSocketAddress addressFromSockaddr_in(ThreadContext context, IRubyObject arg) {
  40.         RubyArray sockaddr = (RubyArray) unpack_sockaddr_in(context, arg);

  41.         IRubyObject addr = sockaddr.pop(context);
  42.         IRubyObject _port = sockaddr.pop(context);
  43.         int port = SocketUtils.portToInt(_port);

  44.         return new InetSocketAddress(
  45.                 addr.convertToString().toString(), port);
  46.     }

  47.     public static InetSocketAddress addressFromArg(ThreadContext context, IRubyObject arg) {
  48.         InetSocketAddress iaddr;
  49.         if (arg instanceof Addrinfo) {
  50.             Addrinfo addrinfo = (Addrinfo)arg;
  51.             iaddr = new InetSocketAddress(addrinfo.getInetAddress(), addrinfo.getPort());
  52.         } else {
  53.             iaddr = addressFromSockaddr_in(context, arg);
  54.         }

  55.         return iaddr;
  56.     }

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

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

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

  66.         return new UnixSocketAddress(new File(pathStr));
  67.     }

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

  71.         validateSockaddr(runtime, val);

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

  73.         StringBuilder sb = new StringBuilder()
  74.                 .append(val.get(4)&0xff)
  75.                 .append(".")
  76.                 .append(val.get(5)&0xff)
  77.                 .append(".")
  78.                 .append(val.get(6)&0xff)
  79.                 .append(".")
  80.                 .append(val.get(7)&0xff);

  81.         IRubyObject[] result = new IRubyObject[]{
  82.                 runtime.newFixnum(port),
  83.                 runtime.newString(sb.toString())};

  84.         return runtime.newArrayNoCopy(result);
  85.     }

  86.     public static IRubyObject packSockaddrFromAddress(ThreadContext context, InetSocketAddress sock) {
  87.         if (sock == null) {
  88.             return Sockaddr.pack_sockaddr_in(context, 0, "");
  89.         } else {
  90.             return Sockaddr.pack_sockaddr_in(context, sock);
  91.         }
  92.     }

  93.     public static IRubyObject pack_sockaddr_in(ThreadContext context, int iport, String host) {
  94.         ByteArrayOutputStream bufS = new ByteArrayOutputStream();
  95.         try {
  96.             DataOutputStream ds = new DataOutputStream(bufS);

  97.             writeSockaddrHeader(AddressFamily.AF_INET, ds);
  98.             writeSockaddrPort(ds, iport);

  99.             try {
  100.                 if(host != null && "".equals(host)) {
  101.                     ds.writeInt(0);
  102.                 } else {
  103.                     InetAddress[] addrs = InetAddress.getAllByName(host);
  104.                     byte[] addr = addrs[0].getAddress();
  105.                     ds.write(addr, 0, addr.length);
  106.                 }
  107.             } catch (UnknownHostException e) {
  108.                 throw sockerr(context.runtime, "getaddrinfo: No address associated with nodename");
  109.             }

  110.             writeSockaddrFooter(ds);
  111.         } catch (IOException e) {
  112.             throw sockerr(context.runtime, "pack_sockaddr_in: internal error");
  113.         }

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

  117.     public static IRubyObject pack_sockaddr_in(ThreadContext context, InetSocketAddress sock) {
  118.         ByteArrayOutputStream bufS = new ByteArrayOutputStream();

  119.         try {
  120.             DataOutputStream ds = new DataOutputStream(bufS);

  121.             writeSockaddrHeader(AddressFamily.AF_INET, ds);
  122.             writeSockaddrPort(ds, sock);

  123.             String host = sock.getAddress().getHostAddress();

  124.             if(host != null && "".equals(host)) {
  125.                 ds.writeInt(0);

  126.             } else {
  127.                 byte[] addr = sock.getAddress().getAddress();
  128.                 ds.write(addr, 0, addr.length);

  129.             }

  130.             writeSockaddrFooter(ds);

  131.         } catch (IOException e) {
  132.             throw sockerr(context.runtime, "pack_sockaddr_in: internal error");

  133.         }

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

  137.     public static void writeSockaddrHeader(AddressFamily family, DataOutputStream ds) throws IOException {
  138.         int value = family.intValue();
  139.         int high = (value & 0xff00) >> 8;
  140.         int low = value & 0xff;

  141.         ds.write((byte)high);
  142.         ds.write((byte)low);
  143.     }

  144.     public static void writeSockaddrFooter(DataOutputStream ds) throws IOException {
  145.         ds.writeInt(0);
  146.         ds.writeInt(0);
  147.     }

  148.     public static void writeSockaddrPort(DataOutputStream ds, InetSocketAddress sockaddr) throws IOException {
  149.         writeSockaddrPort(ds, sockaddr.getPort());
  150.     }

  151.     public static void writeSockaddrPort(DataOutputStream ds, int port) throws IOException {
  152.         ds.write(port >> 8);
  153.         ds.write(port);
  154.     }

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

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

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

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