Skip to content

Commit a21de34

Browse files
committed
Implement socket.inet_(aton|pton|ntoa|ntop).
1 parent 692d723 commit a21de34

File tree

3 files changed

+154
-12
lines changed

3 files changed

+154
-12
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.io.BufferedReader;
4444
import java.io.IOException;
4545
import java.net.Inet4Address;
46+
import java.net.Inet6Address;
4647
import java.net.InetAddress;
4748
import java.net.UnknownHostException;
4849
import java.nio.charset.StandardCharsets;
@@ -53,11 +54,15 @@
5354
import java.util.Map;
5455
import java.util.Set;
5556

57+
import org.graalvm.nativeimage.ImageInfo;
58+
5659
import com.oracle.graal.python.builtins.Builtin;
5760
import com.oracle.graal.python.builtins.CoreFunctions;
5861
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5962
import com.oracle.graal.python.builtins.PythonBuiltins;
6063
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;
6166
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
6267
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
6368
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -68,6 +73,9 @@
6873
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
6974
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
7075
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;
7179
import com.oracle.graal.python.nodes.util.CastToJavaIntNode;
7280
import com.oracle.graal.python.nodes.util.CastToStringNode;
7381
import com.oracle.graal.python.runtime.PythonCore;
@@ -81,13 +89,17 @@
8189
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
8290
import com.oracle.truffle.api.dsl.NodeFactory;
8391
import com.oracle.truffle.api.dsl.Specialization;
92+
import com.oracle.truffle.api.dsl.TypeSystemReference;
8493
import com.oracle.truffle.api.frame.VirtualFrame;
8594
import com.oracle.truffle.api.profiles.BranchProfile;
8695

87-
import org.graalvm.nativeimage.ImageInfo;
88-
8996
@CoreFunctions(defineModule = "_socket")
9097
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+
91103
@Override
92104
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
93105
return SocketModuleBuiltinsFactory.getFactories();
@@ -201,6 +213,9 @@ public void initialize(PythonCore core) {
201213
services = parseServices(core.getContext().getEnv());
202214
protocols = parseProtocols(core.getContext().getEnv());
203215
}
216+
builtinConstants.put("AF_UNSPEC", AF_UNSPEC);
217+
builtinConstants.put("AF_INET", AF_INET);
218+
builtinConstants.put("AF_INET6", AF_INET6);
204219
}
205220

206221
// socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
@@ -635,4 +650,125 @@ Object close(@SuppressWarnings("unused") Object fd) {
635650
throw raise(PythonBuiltinClassType.TypeError);
636651
}
637652
}
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+
638774
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
import java.util.ArrayList;
4646

47+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4748
import com.oracle.graal.python.builtins.objects.bytes.AbstractBytesBuiltins.BytesLikeNoGeneralizationNode;
4849
import com.oracle.graal.python.builtins.objects.bytes.BytesNodesFactory.BytesJoinNodeGen;
4950
import com.oracle.graal.python.builtins.objects.bytes.BytesNodesFactory.FindNodeGen;
@@ -131,13 +132,19 @@ public static BytesJoinNode create() {
131132

132133
@ImportStatic({PGuards.class, SpecialMethodNames.class})
133134
public abstract static class ToBytesNode extends PNodeWithContext {
135+
private static final String DEFAULT_FORMAT = "expected a bytes-like object, %p found";
136+
134137
@Child private PRaiseNode raise = PRaiseNode.create();
135138
@Child private SequenceStorageNodes.ToByteArrayNode toByteArrayNode;
136139

137-
protected final boolean allowRecursive;
140+
private final PythonBuiltinClassType errorType;
141+
private final String errorMessageFormat;
142+
final boolean allowRecursive;
138143

139-
ToBytesNode(boolean allowRecursive) {
144+
ToBytesNode(boolean allowRecursive, PythonBuiltinClassType errorType, String errorMessageFormat) {
140145
this.allowRecursive = allowRecursive;
146+
this.errorType = errorType;
147+
this.errorMessageFormat = errorMessageFormat;
141148
}
142149

143150
public abstract byte[] execute(VirtualFrame frame, Object obj);
@@ -172,7 +179,7 @@ byte[] doMemoryView(VirtualFrame frame, PMemoryView memoryView,
172179

173180
@Fallback
174181
byte[] doError(Object obj) {
175-
throw raise.raise(TypeError, "expected a bytes-like object, %p found", obj);
182+
throw raise.raise(errorType, errorMessageFormat, obj);
176183
}
177184

178185
private SequenceStorageNodes.ToByteArrayNode getToByteArrayNode() {
@@ -183,7 +190,7 @@ private SequenceStorageNodes.ToByteArrayNode getToByteArrayNode() {
183190
return toByteArrayNode;
184191
}
185192

186-
protected ToBytesNode createRecursive() {
193+
ToBytesNode createRecursive() {
187194
return ToBytesNode.create(false);
188195
}
189196

@@ -192,7 +199,11 @@ public static ToBytesNode create() {
192199
}
193200

194201
public static ToBytesNode create(boolean allowRecursive) {
195-
return ToBytesNodeGen.create(allowRecursive);
202+
return ToBytesNodeGen.create(allowRecursive, TypeError, DEFAULT_FORMAT);
203+
}
204+
205+
public static ToBytesNode create(boolean allowRecursive, PythonBuiltinClassType errorType, String errorMessageFormat) {
206+
return ToBytesNodeGen.create(allowRecursive, errorType, errorMessageFormat);
196207
}
197208
}
198209

graalpython/lib-graalpython/_socket.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
# Address families
41-
AF_UNSPEC = 0
42-
AF_INET = 2
43-
AF_INET6 = 30
44-
4540
# Flag values for getaddrinfo()
4641
AI_PASSIVE = 1 # get address to use bind()
4742
AI_CANONNAME = 2 # fill ai_canonname

0 commit comments

Comments
 (0)