[pypy-commit] pypy default: Finish the support for AF_PACKET.
arigo
noreply at buildbot.pypy.org
Sat Mar 14 19:44:21 CET 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r76374:936a4272826a
Date: 2015-03-14 18:49 +0100
http://bitbucket.org/pypy/pypy/changeset/936a4272826a/
Log: Finish the support for AF_PACKET.
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -30,7 +30,7 @@
space.wrap(addr.get_protocol()),
space.wrap(addr.get_pkttype()),
space.wrap(addr.get_hatype()),
- space.wrap(addr.get_addr())])
+ space.wrap(addr.get_haddr())])
elif rsocket.HAS_AF_UNIX and isinstance(addr, rsocket.UNIXAddress):
return space.wrap(addr.get_path())
elif rsocket.HAS_AF_NETLINK and isinstance(addr, rsocket.NETLINKAddress):
@@ -79,7 +79,7 @@
raise NotImplementedError
# XXX Hack to seperate rpython and pypy
-def addr_from_object(family, space, w_address):
+def addr_from_object(family, fd, space, w_address):
if family == rsocket.AF_INET:
w_host, w_port = space.unpackiterable(w_address, 2)
host = space.str_w(w_host)
@@ -89,8 +89,9 @@
if family == rsocket.AF_INET6:
pieces_w = space.unpackiterable(w_address)
if not (2 <= len(pieces_w) <= 4):
- raise TypeError("AF_INET6 address must be a tuple of length 2 "
- "to 4, not %d" % len(pieces_w))
+ raise oefmt(space.w_TypeError,
+ "AF_INET6 address must be a tuple of length 2 "
+ "to 4, not %d", len(pieces_w))
host = space.str_w(pieces_w[0])
port = space.int_w(pieces_w[1])
port = make_ushort_port(space, port)
@@ -105,6 +106,28 @@
if rsocket.HAS_AF_NETLINK and family == rsocket.AF_NETLINK:
w_pid, w_groups = space.unpackiterable(w_address, 2)
return rsocket.NETLINKAddress(space.uint_w(w_pid), space.uint_w(w_groups))
+ if rsocket.HAS_AF_PACKET and family == rsocket.AF_PACKET:
+ pieces_w = space.unpackiterable(w_address)
+ if not (2 <= len(pieces_w) <= 5):
+ raise oefmt(space.w_TypeError,
+ "AF_PACKET address must be a tuple of length 2 "
+ "to 5, not %d", len(pieces_w))
+ ifname = space.str_w(pieces_w[0])
+ ifindex = rsocket.PacketAddress.get_ifindex_from_ifname(fd, ifname)
+ protocol = space.int_w(pieces_w[1])
+ if len(pieces_w) > 2: pkttype = space.int_w(pieces_w[2])
+ else: pkttype = 0
+ if len(pieces_w) > 3: hatype = space.int_w(pieces_w[3])
+ else: hatype = 0
+ if len(pieces_w) > 4: haddr = space.str_w(pieces_w[4])
+ else: haddr = ""
+ if len(haddr) > 8:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "Hardware address must be 8 bytes or less"))
+ if protocol < 0 or protocol > 0xfffff:
+ raise OperationError(space.w_OverflowError, space.wrap(
+ "protoNumber must be 0-65535."))
+ return rsocket.PacketAddress(ifindex, protocol, pkttype, hatype, haddr)
raise RSocketError("unknown address family")
# XXX Hack to seperate rpython and pypy
@@ -172,7 +195,8 @@
# convert an app-level object into an Address
# based on the current socket's family
def addr_from_object(self, space, w_address):
- return addr_from_object(self.sock.family, space, w_address)
+ fd = intmask(self.sock.fd)
+ return addr_from_object(self.sock.family, fd, space, w_address)
def bind_w(self, space, w_addr):
"""bind(address)
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -1,4 +1,4 @@
-import sys
+import sys, os
import py
from pypy.tool.pytest.objspace import gettestobjspace
from rpython.tool.udir import udir
@@ -615,6 +615,28 @@
os.chdir(oldcwd)
+class AppTestPacket:
+ def setup_class(cls):
+ if not hasattr(os, 'getuid') or os.getuid() != 0:
+ py.test.skip("AF_PACKET needs to be root for testing")
+ w_ok = space.appexec([], "(): import _socket; " +
+ "return hasattr(_socket, 'AF_PACKET')")
+ if not space.is_true(w_ok):
+ py.test.skip("no AF_PACKET on this platform")
+ cls.space = space
+
+ def test_convert_between_tuple_and_sockaddr_ll(self):
+ import _socket
+ s = _socket.socket(_socket.AF_PACKET, _socket.SOCK_RAW)
+ assert s.getsockname() == ('', 0, 0, 0, '')
+ s.bind(('lo', 123))
+ a, b, c, d, e = s.getsockname()
+ assert (a, b, c) == ('lo', 123, 0)
+ assert isinstance(d, int)
+ assert isinstance(e, str)
+ assert 0 <= len(e) <= 8
+
+
class AppTestSocketTCP:
HOST = 'localhost'
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -199,7 +199,7 @@
WSA_INVALID_PARAMETER WSA_NOT_ENOUGH_MEMORY WSA_OPERATION_ABORTED
SIO_RCVALL SIO_KEEPALIVE_VALS
-SIOCGIFNAME
+SIOCGIFNAME SIOCGIFINDEX
'''.split()
for name in constant_names:
@@ -328,7 +328,8 @@
if _HAS_AF_PACKET:
CConfig.sockaddr_ll = platform.Struct('struct sockaddr_ll',
- [('sll_ifindex', rffi.INT),
+ [('sll_family', rffi.INT),
+ ('sll_ifindex', rffi.INT),
('sll_protocol', rffi.INT),
('sll_pkttype', rffi.INT),
('sll_hatype', rffi.INT),
diff --git a/rpython/rlib/rsocket.py b/rpython/rlib/rsocket.py
--- a/rpython/rlib/rsocket.py
+++ b/rpython/rlib/rsocket.py
@@ -200,23 +200,49 @@
family = AF_PACKET
struct = _c.sockaddr_ll
maxlen = minlen = sizeof(struct)
+ ifr_name_size = _c.ifreq.c_ifr_name.length
+ sll_addr_size = _c.sockaddr_ll.c_sll_addr.length
+
+ def __init__(self, ifindex, protocol, pkttype=0, hatype=0, haddr=""):
+ addr = lltype.malloc(_c.sockaddr_ll, flavor='raw', zero=True,
+ track_allocation=False)
+ self.setdata(addr, PacketAddress.maxlen)
+ rffi.setintfield(addr, 'c_sll_family', AF_PACKET)
+ rffi.setintfield(addr, 'c_sll_protocol', htons(protocol))
+ rffi.setintfield(addr, 'c_sll_ifindex', ifindex)
+ rffi.setintfield(addr, 'c_sll_pkttype', pkttype)
+ rffi.setintfield(addr, 'c_sll_hatype', hatype)
+ halen = rffi.str2chararray(haddr,
+ rffi.cast(rffi.CCHARP, addr.c_sll_addr),
+ PacketAddress.sll_addr_size)
+ rffi.setintfield(addr, 'c_sll_halen', halen)
+
+ @staticmethod
+ def get_ifindex_from_ifname(fd, ifname):
+ p = lltype.malloc(_c.ifreq, flavor='raw')
+ iflen = rffi.str2chararray(ifname,
+ rffi.cast(rffi.CCHARP, p.c_ifr_name),
+ PacketAddress.ifr_name_size - 1)
+ p.c_ifr_name[iflen] = '\0'
+ err = _c.ioctl(fd, _c.SIOCGIFINDEX, p)
+ ifindex = p.c_ifr_ifindex
+ lltype.free(p, flavor='raw')
+ if err != 0:
+ raise RSocketError("invalid interface name")
+ return ifindex
def get_ifname(self, fd):
+ ifname = ""
a = self.lock(_c.sockaddr_ll)
- p = lltype.malloc(_c.ifreq, flavor='raw')
- rffi.setintfield(p, 'c_ifr_ifindex',
- rffi.getintfield(a, 'c_sll_ifindex'))
- if (_c.ioctl(fd, _c.SIOCGIFNAME, p) == 0):
- # eh, the iface name is a constant length array
- i = 0
- d = []
- while p.c_ifr_name[i] != '\x00' and i < len(p.c_ifr_name):
- d.append(p.c_ifr_name[i])
- i += 1
- ifname = ''.join(d)
- else:
- ifname = ""
- lltype.free(p, flavor='raw')
+ ifindex = rffi.getintfield(a, 'c_sll_ifindex')
+ if ifindex:
+ p = lltype.malloc(_c.ifreq, flavor='raw')
+ rffi.setintfield(p, 'c_ifr_ifindex', ifindex)
+ if (_c.ioctl(fd, _c.SIOCGIFNAME, p) == 0):
+ ifname = rffi.charp2strn(
+ rffi.cast(rffi.CCHARP, p.c_ifr_name),
+ PacketAddress.ifr_name_size)
+ lltype.free(p, flavor='raw')
self.unlock()
return ifname
@@ -235,11 +261,11 @@
def get_hatype(self):
a = self.lock(_c.sockaddr_ll)
- res = bool(rffi.getintfield(a, 'c_sll_hatype'))
+ res = rffi.getintfield(a, 'c_sll_hatype')
self.unlock()
return res
- def get_addr(self):
+ def get_haddr(self):
a = self.lock(_c.sockaddr_ll)
lgt = rffi.getintfield(a, 'c_sll_halen')
d = []
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -796,8 +796,10 @@
# str -> already-existing char[maxsize]
def str2chararray(s, array, maxsize):
+ length = min(len(s), maxsize)
ll_s = llstrtype(s)
- copy_string_to_raw(ll_s, array, 0, min(len(s), maxsize))
+ copy_string_to_raw(ll_s, array, 0, length)
+ return length
str2chararray._annenforceargs_ = [strtype, None, int]
# char* -> str
diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py b/rpython/rtyper/lltypesystem/test/test_rffi.py
--- a/rpython/rtyper/lltypesystem/test/test_rffi.py
+++ b/rpython/rtyper/lltypesystem/test/test_rffi.py
@@ -682,16 +682,16 @@
compilation_info=eci)
def f():
raw = str2charp("XxxZy")
- str2chararray("abcdef", raw, 4)
+ n = str2chararray("abcdef", raw, 4)
assert raw[0] == 'a'
assert raw[1] == 'b'
assert raw[2] == 'c'
assert raw[3] == 'd'
assert raw[4] == 'y'
lltype.free(raw, flavor='raw')
- return 0
+ return n
- assert interpret(f, []) == 0
+ assert interpret(f, []) == 4
def test_around_extcall(self):
if sys.platform == "win32":
More information about the pypy-commit
mailing list