PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/jruby-1.7.3/src/org/jruby/ext/socket/SocketUtils.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 507 lines | 349 code | 117 blank | 41 comment | 76 complexity | b8b19814e80d058f489d5052bee8a7af MD5 | raw file
  1. /***** BEGIN LICENSE BLOCK *****
  2. * Version: EPL 1.0/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Common Public
  5. * License Version 1.0 (the "License"); you may not use this file
  6. * except in compliance with the License. You may obtain a copy of
  7. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Software distributed under the License is distributed on an "AS
  10. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11. * implied. See the License for the specific language governing
  12. * rights and limitations under the License.
  13. *
  14. * Alternatively, the contents of this file may be used under the terms of
  15. * either of the GNU General Public License Version 2 or later (the "GPL"),
  16. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  17. * in which case the provisions of the GPL or the LGPL are applicable instead
  18. * of those above. If you wish to allow use of your version of this file only
  19. * under the terms of either the GPL or the LGPL, and not to allow others to
  20. * use your version of this file under the terms of the EPL, indicate your
  21. * decision by deleting the provisions above and replace them with the notice
  22. * and other provisions required by the GPL or the LGPL. If you do not delete
  23. * the provisions above, a recipient may use your version of this file under
  24. * the terms of any one of the EPL, the GPL or the LGPL.
  25. ***** END LICENSE BLOCK *****/
  26. package org.jruby.ext.socket;
  27. import jnr.constants.platform.AddressFamily;
  28. import jnr.constants.platform.ProtocolFamily;
  29. import jnr.constants.platform.Sock;
  30. import jnr.netdb.Service;
  31. import org.jruby.CompatVersion;
  32. import org.jruby.Ruby;
  33. import org.jruby.RubyArray;
  34. import org.jruby.RubyClass;
  35. import org.jruby.RubyFixnum;
  36. import org.jruby.RubyInteger;
  37. import org.jruby.RubyNumeric;
  38. import org.jruby.RubyString;
  39. import org.jruby.RubySymbol;
  40. import org.jruby.anno.JRubyMethod;
  41. import org.jruby.exceptions.RaiseException;
  42. import org.jruby.runtime.ThreadContext;
  43. import org.jruby.runtime.builtin.IRubyObject;
  44. import org.jruby.util.ByteList;
  45. import org.jruby.util.io.Sockaddr;
  46. import java.net.Inet4Address;
  47. import java.net.Inet6Address;
  48. import java.net.InetAddress;
  49. import java.net.NetworkInterface;
  50. import java.net.SocketException;
  51. import java.net.UnknownHostException;
  52. import java.util.ArrayList;
  53. import java.util.Arrays;
  54. import java.util.Enumeration;
  55. import java.util.List;
  56. import java.util.regex.Matcher;
  57. import java.util.regex.Pattern;
  58. import static jnr.constants.platform.AddressFamily.AF_INET6;
  59. import static jnr.constants.platform.IPProto.IPPROTO_TCP;
  60. import static jnr.constants.platform.IPProto.IPPROTO_UDP;
  61. import static jnr.constants.platform.NameInfo.NI_NUMERICHOST;
  62. import static jnr.constants.platform.NameInfo.NI_NUMERICSERV;
  63. import static jnr.constants.platform.ProtocolFamily.PF_INET;
  64. import static jnr.constants.platform.ProtocolFamily.PF_INET6;
  65. import static jnr.constants.platform.Sock.SOCK_DGRAM;
  66. import static jnr.constants.platform.Sock.SOCK_STREAM;
  67. /**
  68. * Socket class methods for addresses, structures, and so on.
  69. */
  70. public class SocketUtils {
  71. public static IRubyObject gethostname(ThreadContext context) {
  72. Ruby runtime = context.runtime;
  73. try {
  74. return runtime.newString(InetAddress.getLocalHost().getHostName());
  75. } catch(UnknownHostException e) {
  76. try {
  77. return runtime.newString(InetAddress.getByAddress(new byte[]{0,0,0,0}).getHostName());
  78. } catch(UnknownHostException e2) {
  79. throw sockerr(runtime, "gethostname: name or service not known");
  80. }
  81. }
  82. }
  83. public static IRubyObject gethostbyaddr(ThreadContext context, IRubyObject[] args) {
  84. Ruby runtime = context.runtime;
  85. IRubyObject[] ret = new IRubyObject[4];
  86. ret[0] = runtime.newString(Sockaddr.addressFromString(runtime, args[0].convertToString().toString()).getCanonicalHostName());
  87. ret[1] = runtime.newArray();
  88. ret[2] = runtime.newFixnum(2); // AF_INET
  89. ret[3] = args[0];
  90. return runtime.newArrayNoCopy(ret);
  91. }
  92. public static IRubyObject getservbyname(ThreadContext context, IRubyObject[] args) {
  93. Ruby runtime = context.runtime;
  94. String name = args[0].convertToString().toString();
  95. String proto = args.length == 1 ? "tcp" : args[1].convertToString().toString();
  96. Service service = Service.getServiceByName(name, proto);
  97. int port;
  98. if (service != null) {
  99. port = service.getPort();
  100. } else {
  101. // MRI behavior: try to convert the name string to port directly
  102. try {
  103. port = Integer.parseInt(name.trim());
  104. } catch (NumberFormatException nfe) {
  105. throw sockerr(runtime, "no such service " + name + "/" + proto);
  106. }
  107. }
  108. return runtime.newFixnum(port);
  109. }
  110. public static IRubyObject pack_sockaddr_in(ThreadContext context, IRubyObject port, IRubyObject host) {
  111. int portNum = port instanceof RubyString ?
  112. Integer.parseInt(port.convertToString().toString()) :
  113. RubyNumeric.fix2int(port);
  114. return Sockaddr.pack_sockaddr_in(
  115. context,
  116. portNum,
  117. host.isNil() ? null : host.convertToString().toString());
  118. }
  119. public static IRubyObject unpack_sockaddr_in(ThreadContext context, IRubyObject addr) {
  120. return Sockaddr.unpack_sockaddr_in(context, addr);
  121. }
  122. public static IRubyObject pack_sockaddr_un(ThreadContext context, IRubyObject filename) {
  123. ByteList str = filename.convertToString().getByteList();
  124. AddressFamily af = AddressFamily.AF_UNIX;
  125. int high = (af.intValue() & 0xff00) >> 8;
  126. int low = af.intValue() & 0xff;
  127. ByteList bl = new ByteList();
  128. bl.append((byte)high);
  129. bl.append((byte)low);
  130. bl.append(str);
  131. for(int i=str.length();i<104;i++) {
  132. bl.append((byte)0);
  133. }
  134. return context.runtime.newString(bl);
  135. }
  136. public static IRubyObject gethostbyname(ThreadContext context, IRubyObject hostname) {
  137. Ruby runtime = context.runtime;
  138. try {
  139. InetAddress addr = getRubyInetAddress(hostname.convertToString().getByteList());
  140. IRubyObject[] ret = new IRubyObject[4];
  141. ret[0] = runtime.newString(addr.getCanonicalHostName());
  142. ret[1] = runtime.newArray();
  143. ret[2] = runtime.newFixnum(2); // AF_INET
  144. ret[3] = runtime.newString(new ByteList(addr.getAddress()));
  145. return runtime.newArrayNoCopy(ret);
  146. } catch(UnknownHostException e) {
  147. throw sockerr(runtime, "gethostbyname: name or service not known");
  148. }
  149. }
  150. /**
  151. * Ruby definition would look like:
  152. *
  153. * def self.getaddrinfo(host, port, family = nil, socktype = nil, protocol = nil, flags = nil)
  154. */
  155. public static IRubyObject getaddrinfo(ThreadContext context, IRubyObject[] args) {
  156. Ruby runtime = context.runtime;
  157. IRubyObject host = args[0];
  158. IRubyObject port = args[1];
  159. boolean emptyHost = host.isNil() || host.convertToString().isEmpty();
  160. try {
  161. if(port instanceof RubyString) {
  162. port = getservbyname(context, new IRubyObject[]{port});
  163. }
  164. IRubyObject family = args.length > 2 ? args[2] : context.nil;
  165. IRubyObject socktype = args.length > 3 ? args[3] : context.nil;
  166. //IRubyObject protocol = args[4];
  167. IRubyObject flags = args.length > 5 ? args[5] : context.nil;
  168. boolean is_ipv6 = (! family.isNil()) && (RubyNumeric.fix2int(family) & AF_INET6.intValue()) == AF_INET6.intValue();
  169. boolean sock_stream = true;
  170. boolean sock_dgram = true;
  171. if(!socktype.isNil()) {
  172. int val = RubyNumeric.fix2int(socktype);
  173. if(val == SOCK_STREAM.intValue()) {
  174. sock_dgram = false;
  175. } else if(val == SOCK_DGRAM.intValue()) {
  176. sock_stream = false;
  177. }
  178. }
  179. // When Socket::AI_PASSIVE and host is nil, return 'any' address.
  180. InetAddress[] addrs = null;
  181. if(!flags.isNil() && RubyFixnum.fix2int(flags) > 0) {
  182. // The value of 1 is for Socket::AI_PASSIVE.
  183. int flag = RubyNumeric.fix2int(flags);
  184. if ((flag == 1) && emptyHost ) {
  185. // use RFC 2732 style string to ensure that we get Inet6Address
  186. addrs = InetAddress.getAllByName(is_ipv6 ? "[::]" : "0.0.0.0");
  187. }
  188. }
  189. if (addrs == null) {
  190. addrs = InetAddress.getAllByName(emptyHost ? (is_ipv6 ? "[::1]" : null) : host.convertToString().toString());
  191. }
  192. List<IRubyObject> l = new ArrayList<IRubyObject>();
  193. for(int i = 0; i < addrs.length; i++) {
  194. IRubyObject[] c;
  195. if(sock_dgram) {
  196. c = new IRubyObject[7];
  197. c[0] = runtime.newString(is_ipv6 ? "AF_INET6" : "AF_INET");
  198. c[1] = port;
  199. c[2] = runtime.newString(getHostAddress(context, addrs[i]));
  200. c[3] = runtime.newString(addrs[i].getHostAddress());
  201. c[4] = runtime.newFixnum(is_ipv6 ? PF_INET6 : PF_INET);
  202. c[5] = runtime.newFixnum(SOCK_DGRAM);
  203. c[6] = runtime.newFixnum(IPPROTO_UDP);
  204. l.add(runtime.newArrayNoCopy(c));
  205. }
  206. if(sock_stream) {
  207. c = new IRubyObject[7];
  208. c[0] = runtime.newString(is_ipv6 ? "AF_INET6" : "AF_INET");
  209. c[1] = port;
  210. c[2] = runtime.newString(getHostAddress(context, addrs[i]));
  211. c[3] = runtime.newString(addrs[i].getHostAddress());
  212. c[4] = runtime.newFixnum(is_ipv6 ? PF_INET6 : PF_INET);
  213. c[5] = runtime.newFixnum(SOCK_STREAM);
  214. c[6] = runtime.newFixnum(IPPROTO_TCP);
  215. l.add(runtime.newArrayNoCopy(c));
  216. }
  217. }
  218. return runtime.newArray(l);
  219. } catch(UnknownHostException e) {
  220. throw sockerr(runtime, "getaddrinfo: name or service not known");
  221. }
  222. }
  223. public static IRubyObject getnameinfo(ThreadContext context, IRubyObject[] args) {
  224. Ruby runtime = context.runtime;
  225. int flags = args.length == 2 ? RubyNumeric.num2int(args[1]) : 0;
  226. IRubyObject arg0 = args[0];
  227. String host, port;
  228. if (arg0 instanceof RubyArray) {
  229. List list = ((RubyArray)arg0).getList();
  230. int len = list.size();
  231. if (len < 3 || len > 4) {
  232. throw runtime.newArgumentError("array size should be 3 or 4, "+len+" given");
  233. }
  234. // if array has 4 elements, third element is ignored
  235. host = list.size() == 3 ? list.get(2).toString() : list.get(3).toString();
  236. port = list.get(1).toString();
  237. } else if (arg0 instanceof RubyString) {
  238. String arg = ((RubyString)arg0).toString();
  239. Matcher m = STRING_IPV4_ADDRESS_PATTERN.matcher(arg);
  240. if (!m.matches()) {
  241. IRubyObject obj = unpack_sockaddr_in(context, arg0);
  242. if (obj instanceof RubyArray) {
  243. List list = ((RubyArray)obj).getList();
  244. int len = list.size();
  245. if (len != 2) {
  246. throw runtime.newArgumentError("invalid address representation");
  247. }
  248. host = list.get(1).toString();
  249. port = list.get(0).toString();
  250. } else {
  251. throw runtime.newArgumentError("invalid address string");
  252. }
  253. } else if ((host = m.group(IPV4_HOST_GROUP)) == null || host.length() == 0 ||
  254. (port = m.group(IPV4_PORT_GROUP)) == null || port.length() == 0) {
  255. throw runtime.newArgumentError("invalid address string");
  256. } else {
  257. // Try IPv6
  258. try {
  259. InetAddress ipv6_addr = InetAddress.getByName(host);
  260. if (ipv6_addr instanceof Inet6Address) {
  261. host = ipv6_addr.getHostAddress();
  262. }
  263. } catch (UnknownHostException uhe) {
  264. throw runtime.newArgumentError("invalid address string");
  265. }
  266. }
  267. } else {
  268. throw runtime.newArgumentError("invalid args");
  269. }
  270. InetAddress addr;
  271. try {
  272. addr = InetAddress.getByName(host);
  273. } catch (UnknownHostException e) {
  274. throw sockerr(runtime, "unknown host: "+ host);
  275. }
  276. if ((flags & NI_NUMERICHOST.intValue()) == 0) {
  277. host = addr.getCanonicalHostName();
  278. } else {
  279. host = addr.getHostAddress();
  280. }
  281. jnr.netdb.Service serv = jnr.netdb.Service.getServiceByPort(Integer.parseInt(port), null);
  282. if (serv != null) {
  283. if ((flags & NI_NUMERICSERV.intValue()) == 0) {
  284. port = serv.getName();
  285. } else {
  286. port = Integer.toString(serv.getPort());
  287. }
  288. }
  289. return runtime.newArray(runtime.newString(host), runtime.newString(port));
  290. }
  291. public static IRubyObject ip_address_list(ThreadContext context) {
  292. Ruby runtime = context.runtime;
  293. try {
  294. RubyArray list = RubyArray.newArray(runtime);
  295. RubyClass addrInfoCls = runtime.getClass("Addrinfo");
  296. for (Enumeration<NetworkInterface> networkIfcs = NetworkInterface.getNetworkInterfaces() ; networkIfcs.hasMoreElements() ; ) {
  297. for (Enumeration<InetAddress> addresses = networkIfcs.nextElement().getInetAddresses() ; addresses.hasMoreElements() ; ) {
  298. list.append(new Addrinfo(runtime, addrInfoCls, addresses.nextElement()));
  299. }
  300. }
  301. return list;
  302. } catch (SocketException se) {
  303. throw sockerr(runtime, se.getLocalizedMessage());
  304. }
  305. }
  306. public static InetAddress getRubyInetAddress(ByteList address) throws UnknownHostException {
  307. // switched to String because the ByteLists were not comparing properly in 1.9 mode (encoding?
  308. String addressString = address.toString();
  309. if (addressString.equals(BROADCAST)) {
  310. return InetAddress.getByAddress(INADDR_BROADCAST);
  311. } else if (addressString.equals(ANY)) {
  312. return InetAddress.getByAddress(INADDR_ANY);
  313. } else {
  314. return InetAddress.getByName(address.toString());
  315. }
  316. }
  317. public static IRubyObject getaddress(ThreadContext context, IRubyObject hostname) {
  318. try {
  319. return context.runtime.newString(InetAddress.getByName(hostname.convertToString().toString()).getHostAddress());
  320. } catch(UnknownHostException e) {
  321. throw sockerr(context.runtime, "getaddress: name or service not known");
  322. }
  323. }
  324. public static RuntimeException sockerr(Ruby runtime, String msg) {
  325. return new RaiseException(runtime, runtime.getClass("SocketError"), msg, true);
  326. }
  327. public static int getPortFrom(ThreadContext context, IRubyObject _port) {
  328. int port;
  329. if (_port instanceof RubyInteger) {
  330. port = RubyNumeric.fix2int(_port);
  331. } else {
  332. IRubyObject portString = _port.convertToString();
  333. IRubyObject portInteger = portString.convertToInteger( "to_i");
  334. port = RubyNumeric.fix2int(portInteger);
  335. if (port <= 0) {
  336. port = RubyNumeric.fix2int(RubySocket.getservbyname(
  337. context, context.runtime.getObject(), new IRubyObject[]{portString}));
  338. }
  339. }
  340. return port;
  341. }
  342. private static String getHostAddress(ThreadContext context, InetAddress addr) {
  343. return context.runtime.isDoNotReverseLookupEnabled() ? addr.getHostAddress() : addr.getCanonicalHostName();
  344. }
  345. private static final Pattern STRING_IPV4_ADDRESS_PATTERN =
  346. Pattern.compile("((.*)\\/)?([\\.0-9]+)(:([0-9]+))?");
  347. private static final int IPV4_HOST_GROUP = 3;
  348. private static final int IPV4_PORT_GROUP = 5;
  349. private static final String BROADCAST = "<broadcast>";
  350. private static final byte[] INADDR_BROADCAST = new byte[] {-1,-1,-1,-1}; // 255.255.255.255
  351. private static final String ANY = "<any>";
  352. private static final byte[] INADDR_ANY = new byte[] {0,0,0,0}; // 0.0.0.0
  353. static AddressFamily addressFamilyFromArg(IRubyObject domain) {
  354. AddressFamily addressFamily = null;
  355. if(domain instanceof RubyString || domain instanceof RubySymbol) {
  356. String domainString = domain.toString();
  357. addressFamily = AddressFamily.valueOf("AF_" + domainString);
  358. } else {
  359. int domainInt = RubyNumeric.fix2int(domain);
  360. addressFamily = AddressFamily.valueOf(domainInt);
  361. }
  362. return addressFamily;
  363. }
  364. static Sock sockFromArg(IRubyObject type) {
  365. Sock sockType = null;
  366. if(type instanceof RubyString || type instanceof RubySymbol) {
  367. String typeString = type.toString();
  368. sockType = Sock.valueOf("SOCK_" + typeString);
  369. } else {
  370. int typeInt = RubyNumeric.fix2int(type);
  371. sockType = Sock.valueOf(typeInt);
  372. }
  373. return sockType;
  374. }
  375. static ProtocolFamily protocolFamilyFromArg(IRubyObject protocol) {
  376. ProtocolFamily protocolFamily = null;
  377. if(protocol instanceof RubyString || protocol instanceof RubySymbol) {
  378. String protocolString = protocol.toString();
  379. protocolFamily = ProtocolFamily.valueOf("PF_" + protocolString);
  380. } else {
  381. int protocolInt = RubyNumeric.fix2int(protocol);
  382. if (protocolInt == 0) return null;
  383. protocolFamily = ProtocolFamily.valueOf(protocolInt);
  384. }
  385. return protocolFamily;
  386. }
  387. public static int portToInt(IRubyObject port) {
  388. return port.isNil() ? 0 : RubyNumeric.fix2int(port);
  389. }
  390. }