|
43 | 43 | import java.io.BufferedReader;
|
44 | 44 | import java.io.IOException;
|
45 | 45 | import java.net.Inet4Address;
|
| 46 | +import java.net.Inet6Address; |
46 | 47 | import java.net.InetAddress;
|
47 | 48 | import java.net.UnknownHostException;
|
48 | 49 | import java.nio.charset.StandardCharsets;
|
|
53 | 54 | import java.util.Map;
|
54 | 55 | import java.util.Set;
|
55 | 56 |
|
| 57 | +import org.graalvm.nativeimage.ImageInfo; |
| 58 | + |
56 | 59 | import com.oracle.graal.python.builtins.Builtin;
|
57 | 60 | import com.oracle.graal.python.builtins.CoreFunctions;
|
58 | 61 | import com.oracle.graal.python.builtins.PythonBuiltinClassType;
|
59 | 62 | import com.oracle.graal.python.builtins.PythonBuiltins;
|
60 | 63 | import com.oracle.graal.python.builtins.objects.PNone;
|
| 64 | +import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; |
| 65 | +import com.oracle.graal.python.builtins.objects.bytes.PBytes; |
61 | 66 | import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
|
62 | 67 | import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
|
63 | 68 | import com.oracle.graal.python.builtins.objects.ints.PInt;
|
|
68 | 73 | import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
|
69 | 74 | import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
|
70 | 75 | import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
|
| 76 | +import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; |
| 77 | +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; |
| 78 | +import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes; |
71 | 79 | import com.oracle.graal.python.nodes.util.CastToJavaIntNode;
|
72 | 80 | import com.oracle.graal.python.nodes.util.CastToStringNode;
|
73 | 81 | import com.oracle.graal.python.runtime.PythonCore;
|
|
81 | 89 | import com.oracle.truffle.api.dsl.GenerateNodeFactory;
|
82 | 90 | import com.oracle.truffle.api.dsl.NodeFactory;
|
83 | 91 | import com.oracle.truffle.api.dsl.Specialization;
|
| 92 | +import com.oracle.truffle.api.dsl.TypeSystemReference; |
84 | 93 | import com.oracle.truffle.api.frame.VirtualFrame;
|
85 | 94 | import com.oracle.truffle.api.profiles.BranchProfile;
|
86 | 95 |
|
87 |
| -import org.graalvm.nativeimage.ImageInfo; |
88 |
| - |
89 | 96 | @CoreFunctions(defineModule = "_socket")
|
90 | 97 | public class SocketModuleBuiltins extends PythonBuiltins {
|
| 98 | +// Address families |
| 99 | + private static final int AF_UNSPEC = 0; |
| 100 | + private static final int AF_INET = 2; |
| 101 | + private static final int AF_INET6 = 30; |
| 102 | + |
91 | 103 | @Override
|
92 | 104 | protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
|
93 | 105 | return SocketModuleBuiltinsFactory.getFactories();
|
@@ -201,6 +213,9 @@ public void initialize(PythonCore core) {
|
201 | 213 | services = parseServices(core.getContext().getEnv());
|
202 | 214 | protocols = parseProtocols(core.getContext().getEnv());
|
203 | 215 | }
|
| 216 | + builtinConstants.put("AF_UNSPEC", AF_UNSPEC); |
| 217 | + builtinConstants.put("AF_INET", AF_INET); |
| 218 | + builtinConstants.put("AF_INET6", AF_INET6); |
204 | 219 | }
|
205 | 220 |
|
206 | 221 | // socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
|
@@ -635,4 +650,125 @@ Object close(@SuppressWarnings("unused") Object fd) {
|
635 | 650 | throw raise(PythonBuiltinClassType.TypeError);
|
636 | 651 | }
|
637 | 652 | }
|
| 653 | + |
| 654 | + @Builtin(name = "inet_aton", minNumOfPositionalArgs = 1) |
| 655 | + @GenerateNodeFactory |
| 656 | + @TypeSystemReference(PythonArithmeticTypes.class) |
| 657 | + abstract static class InetAtoNNode extends PythonUnaryBuiltinNode { |
| 658 | + @Specialization |
| 659 | + PBytes doConvert(VirtualFrame frame, String addr) { |
| 660 | + return factory().createBytes(aton(addr)); |
| 661 | + } |
| 662 | + |
| 663 | + @TruffleBoundary |
| 664 | + private byte[] aton(String s) { |
| 665 | + try { |
| 666 | + return Inet4Address.getByName(s).getAddress(); |
| 667 | + } catch (UnknownHostException e) { |
| 668 | + throw raise(PythonBuiltinClassType.OSError, "illegal IP address string passed to inet_aton"); |
| 669 | + } |
| 670 | + } |
| 671 | + |
| 672 | + @Fallback |
| 673 | + PBytes doError(Object obj) { |
| 674 | + throw raise(PythonBuiltinClassType.TypeError, "inet_aton() argument 1 must be str, not %p", obj); |
| 675 | + } |
| 676 | + } |
| 677 | + |
| 678 | + @Builtin(name = "inet_ntoa", minNumOfPositionalArgs = 1) |
| 679 | + @GenerateNodeFactory |
| 680 | + abstract static class InetNtoANode extends PythonUnaryBuiltinNode { |
| 681 | + @Specialization |
| 682 | + String doGeneric(VirtualFrame frame, Object obj, |
| 683 | + @Cached("createToBytes()") BytesNodes.ToBytesNode toBytesNode) { |
| 684 | + return ntoa(toBytesNode.execute(frame, obj)); |
| 685 | + } |
| 686 | + |
| 687 | + @TruffleBoundary |
| 688 | + private String ntoa(byte[] bytes) { |
| 689 | + try { |
| 690 | + return InetAddress.getByAddress(bytes).toString(); |
| 691 | + } catch (UnknownHostException e) { |
| 692 | + // the exception will only be thrown if 'bytes' has the wrong length |
| 693 | + throw raise(PythonBuiltinClassType.OSError, "packed IP wrong length for inet_ntoa"); |
| 694 | + } |
| 695 | + } |
| 696 | + |
| 697 | + static BytesNodes.ToBytesNode createToBytes() { |
| 698 | + return BytesNodes.ToBytesNode.create(true, PythonBuiltinClassType.TypeError, "a bytes-like object is required, not '%p'"); |
| 699 | + } |
| 700 | + } |
| 701 | + |
| 702 | + @Builtin(name = "inet_pton", minNumOfPositionalArgs = 1) |
| 703 | + @GenerateNodeFactory |
| 704 | + @TypeSystemReference(PythonArithmeticTypes.class) |
| 705 | + abstract static class InetPtoNNode extends PythonBinaryBuiltinNode { |
| 706 | + @Specialization |
| 707 | + PBytes doConvert(VirtualFrame frame, Object addrFamily, String addr, |
| 708 | + @Cached CastToJavaIntNode castToJavaIntNode) { |
| 709 | + return factory().createBytes(aton(castToJavaIntNode.execute(addrFamily), addr)); |
| 710 | + } |
| 711 | + |
| 712 | + @TruffleBoundary |
| 713 | + private byte[] aton(int addrFamily, String s) { |
| 714 | + try { |
| 715 | + if (addrFamily != AF_INET && addrFamily != AF_INET6) { |
| 716 | + throw raise(PythonBuiltinClassType.ValueError, "unknown address family %d", addrFamily); |
| 717 | + } |
| 718 | + |
| 719 | + byte[] bytes = InetAddress.getByName(s).getAddress(); |
| 720 | + |
| 721 | + // we also need to check the size otherwise one could parse an IPv4 address even if |
| 722 | + // he specified AF_INET6 (and vice versa) |
| 723 | + int ip4Len = Inet4Address.getLoopbackAddress().getAddress().length; |
| 724 | + int ip6Len = Inet6Address.getLoopbackAddress().getAddress().length; |
| 725 | + if (addrFamily == AF_INET && bytes.length == ip4Len || addrFamily == AF_INET6 && bytes.length == ip6Len) { |
| 726 | + return bytes; |
| 727 | + } |
| 728 | + } catch (UnknownHostException e) { |
| 729 | + // fall through |
| 730 | + } |
| 731 | + throw raise(PythonBuiltinClassType.OSError, "illegal IP address string passed to inet_pton"); |
| 732 | + } |
| 733 | + |
| 734 | + @Fallback |
| 735 | + PBytes doError(@SuppressWarnings("unused") Object addrFamily, Object obj) { |
| 736 | + throw raise(PythonBuiltinClassType.TypeError, "inet_aton() argument 1 must be str, not %p", obj); |
| 737 | + } |
| 738 | + } |
| 739 | + |
| 740 | + @Builtin(name = "inet_ntop", minNumOfPositionalArgs = 1) |
| 741 | + @GenerateNodeFactory |
| 742 | + abstract static class InetNtoPNode extends PythonBinaryBuiltinNode { |
| 743 | + @Specialization |
| 744 | + String doGeneric(VirtualFrame frame, int addrFamily, Object obj, |
| 745 | + @Cached("createToBytes()") BytesNodes.ToBytesNode toBytesNode) { |
| 746 | + return ntoa(addrFamily, toBytesNode.execute(frame, obj)); |
| 747 | + } |
| 748 | + |
| 749 | + @TruffleBoundary |
| 750 | + private String ntoa(int addrFamily, byte[] bytes) { |
| 751 | + if (addrFamily != AF_INET && addrFamily != AF_INET6) { |
| 752 | + throw raise(PythonBuiltinClassType.ValueError, "unknown address family %d", addrFamily); |
| 753 | + } |
| 754 | + // we also need to check the size otherwise one could convert an IPv4 address even if |
| 755 | + // he specified AF_INET6 (and vice versa) |
| 756 | + int ip4Len = Inet4Address.getLoopbackAddress().getAddress().length; |
| 757 | + int ip6Len = Inet6Address.getLoopbackAddress().getAddress().length; |
| 758 | + if (addrFamily == AF_INET && bytes.length != ip4Len || addrFamily == AF_INET6 && bytes.length != ip6Len) { |
| 759 | + throw raise(PythonBuiltinClassType.OSError, "packed IP wrong length for inet_ntoa"); |
| 760 | + } |
| 761 | + try { |
| 762 | + return InetAddress.getByAddress(bytes).toString(); |
| 763 | + } catch (UnknownHostException e) { |
| 764 | + // should not be reached |
| 765 | + throw new IllegalStateException("should not be reached"); |
| 766 | + } |
| 767 | + } |
| 768 | + |
| 769 | + static BytesNodes.ToBytesNode createToBytes() { |
| 770 | + return BytesNodes.ToBytesNode.create(true, PythonBuiltinClassType.TypeError, "a bytes-like object is required, not '%p'"); |
| 771 | + } |
| 772 | + } |
| 773 | + |
638 | 774 | }
|
0 commit comments