upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
338
android/kernel/tests/net/test/csocket.py
Normal file
338
android/kernel/tests/net/test/csocket.py
Normal file
|
@ -0,0 +1,338 @@
|
|||
# Copyright 2014 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Python wrapper for C socket calls and data structures."""
|
||||
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
import os
|
||||
import socket
|
||||
import struct
|
||||
|
||||
import cstruct
|
||||
|
||||
|
||||
# Data structures.
|
||||
# These aren't constants, they're classes. So, pylint: disable=invalid-name
|
||||
CMsgHdr = cstruct.Struct("cmsghdr", "@Lii", "len level type")
|
||||
Iovec = cstruct.Struct("iovec", "@PL", "base len")
|
||||
MsgHdr = cstruct.Struct("msghdr", "@LLPLPLi",
|
||||
"name namelen iov iovlen control msg_controllen flags")
|
||||
SockaddrIn = cstruct.Struct("sockaddr_in", "=HH4sxxxxxxxx", "family port addr")
|
||||
SockaddrIn6 = cstruct.Struct("sockaddr_in6", "=HHI16sI",
|
||||
"family port flowinfo addr scope_id")
|
||||
SockaddrStorage = cstruct.Struct("sockaddr_storage", "=H126s", "family data")
|
||||
SockExtendedErr = cstruct.Struct("sock_extended_err", "@IBBBxII",
|
||||
"errno origin type code info data")
|
||||
InPktinfo = cstruct.Struct("in_pktinfo", "@i4s4s", "ifindex spec_dst addr")
|
||||
In6Pktinfo = cstruct.Struct("in6_pktinfo", "@16si", "addr ifindex")
|
||||
|
||||
# Constants.
|
||||
# IPv4 socket options and cmsg types.
|
||||
IP_TTL = 2
|
||||
IP_MTU_DISCOVER = 10
|
||||
IP_PKTINFO = 8
|
||||
IP_RECVERR = 11
|
||||
IP_RECVTTL = 12
|
||||
IP_MTU = 14
|
||||
|
||||
# IPv6 socket options and cmsg types.
|
||||
IPV6_MTU_DISCOVER = 23
|
||||
IPV6_RECVERR = 25
|
||||
IPV6_RECVPKTINFO = 49
|
||||
IPV6_PKTINFO = 50
|
||||
IPV6_RECVHOPLIMIT = 51
|
||||
IPV6_HOPLIMIT = 52
|
||||
IPV6_PATHMTU = 61
|
||||
IPV6_DONTFRAG = 62
|
||||
|
||||
# PMTUD values.
|
||||
IP_PMTUDISC_DO = 1
|
||||
|
||||
CMSG_ALIGNTO = struct.calcsize("@L") # The kernel defines this as sizeof(long).
|
||||
|
||||
# Sendmsg flags
|
||||
MSG_CONFIRM = 0X800
|
||||
MSG_ERRQUEUE = 0x2000
|
||||
|
||||
# Linux errqueue API.
|
||||
SO_ORIGIN_ICMP = 2
|
||||
SO_ORIGIN_ICMP6 = 3
|
||||
|
||||
# Find the C library.
|
||||
libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
|
||||
|
||||
|
||||
# TODO: Move this to a utils.py or constants.py file, once we have one.
|
||||
def LinuxVersion():
|
||||
# Example: "3.4.67-00753-gb7a556f".
|
||||
# Get the part before the dash.
|
||||
version = os.uname()[2].split("-")[0]
|
||||
# Convert it into a tuple such as (3, 4, 67). That allows comparing versions
|
||||
# using < and >, since tuples are compared lexicographically.
|
||||
version = tuple(int(i) for i in version.split("."))
|
||||
return version
|
||||
|
||||
|
||||
def VoidPointer(s):
|
||||
return ctypes.cast(s.CPointer(), ctypes.c_void_p)
|
||||
|
||||
|
||||
def PaddedLength(length):
|
||||
return CMSG_ALIGNTO * ((length / CMSG_ALIGNTO) + (length % CMSG_ALIGNTO != 0))
|
||||
|
||||
|
||||
def MaybeRaiseSocketError(ret):
|
||||
if ret < 0:
|
||||
errno = ctypes.get_errno()
|
||||
raise socket.error(errno, os.strerror(errno))
|
||||
|
||||
|
||||
def Sockaddr(addr):
|
||||
if ":" in addr[0]:
|
||||
family = socket.AF_INET6
|
||||
if len(addr) == 4:
|
||||
addr, port, flowinfo, scope_id = addr
|
||||
else:
|
||||
(addr, port), flowinfo, scope_id = addr, 0, 0
|
||||
addr = socket.inet_pton(family, addr)
|
||||
return SockaddrIn6((family, socket.ntohs(port), socket.ntohl(flowinfo),
|
||||
addr, scope_id))
|
||||
else:
|
||||
family = socket.AF_INET
|
||||
addr, port = addr
|
||||
addr = socket.inet_pton(family, addr)
|
||||
return SockaddrIn((family, socket.ntohs(port), addr))
|
||||
|
||||
|
||||
def _MakeMsgControl(optlist):
|
||||
"""Creates a msg_control blob from a list of cmsg attributes.
|
||||
|
||||
Takes a list of cmsg attributes. Each attribute is a tuple of:
|
||||
- level: An integer, e.g., SOL_IPV6.
|
||||
- type: An integer, the option identifier, e.g., IPV6_HOPLIMIT.
|
||||
- data: The option data. This is either a string or an integer. If it's an
|
||||
integer it will be written as an unsigned integer in host byte order. If
|
||||
it's a string, it's used as is.
|
||||
|
||||
Data is padded to an integer multiple of CMSG_ALIGNTO.
|
||||
|
||||
Args:
|
||||
optlist: A list of tuples describing cmsg options.
|
||||
|
||||
Returns:
|
||||
A string, a binary blob usable as the control data for a sendmsg call.
|
||||
|
||||
Raises:
|
||||
TypeError: Option data is neither an integer nor a string.
|
||||
"""
|
||||
msg_control = ""
|
||||
|
||||
for i, opt in enumerate(optlist):
|
||||
msg_level, msg_type, data = opt
|
||||
if isinstance(data, int):
|
||||
data = struct.pack("=I", data)
|
||||
elif not isinstance(data, str):
|
||||
raise TypeError("unknown data type for opt %i: %s" % (i, type(data)))
|
||||
|
||||
datalen = len(data)
|
||||
msg_len = len(CMsgHdr) + datalen
|
||||
padding = "\x00" * (PaddedLength(datalen) - datalen)
|
||||
msg_control += CMsgHdr((msg_len, msg_level, msg_type)).Pack()
|
||||
msg_control += data + padding
|
||||
|
||||
return msg_control
|
||||
|
||||
|
||||
def _ParseMsgControl(buf):
|
||||
"""Parse a raw control buffer into a list of tuples."""
|
||||
msglist = []
|
||||
while len(buf) > 0:
|
||||
cmsghdr, buf = cstruct.Read(buf, CMsgHdr)
|
||||
datalen = cmsghdr.len - len(CMsgHdr)
|
||||
data, buf = buf[:datalen], buf[PaddedLength(datalen):]
|
||||
|
||||
if cmsghdr.level == socket.IPPROTO_IP:
|
||||
if cmsghdr.type == IP_PKTINFO:
|
||||
data = InPktinfo(data)
|
||||
elif cmsghdr.type == IP_TTL:
|
||||
data = struct.unpack("@I", data)[0]
|
||||
|
||||
if cmsghdr.level == socket.IPPROTO_IPV6:
|
||||
if cmsghdr.type == IPV6_PKTINFO:
|
||||
data = In6Pktinfo(data)
|
||||
elif cmsghdr.type == IPV6_RECVERR:
|
||||
err, source = cstruct.Read(data, SockExtendedErr)
|
||||
if err.origin == SO_ORIGIN_ICMP6:
|
||||
source, pad = cstruct.Read(source, SockaddrIn6)
|
||||
data = (err, source)
|
||||
elif cmsghdr.type == IPV6_HOPLIMIT:
|
||||
data = struct.unpack("@I", data)[0]
|
||||
|
||||
# If not, leave data as just the raw bytes.
|
||||
|
||||
msglist.append((cmsghdr.level, cmsghdr.type, data))
|
||||
|
||||
return msglist
|
||||
|
||||
|
||||
def Bind(s, to):
|
||||
"""Python wrapper for bind."""
|
||||
ret = libc.bind(s.fileno(), VoidPointer(to), len(to))
|
||||
MaybeRaiseSocketError(ret)
|
||||
return ret
|
||||
|
||||
|
||||
def Connect(s, to):
|
||||
"""Python wrapper for connect."""
|
||||
ret = libc.connect(s.fileno(), VoidPointer(to), len(to))
|
||||
MaybeRaiseSocketError(ret)
|
||||
return ret
|
||||
|
||||
|
||||
def Sendmsg(s, to, data, control, flags):
|
||||
"""Python wrapper for sendmsg.
|
||||
|
||||
Args:
|
||||
s: A Python socket object. Becomes sockfd.
|
||||
to: An address tuple, or a SockaddrIn[6] struct. Becomes msg->msg_name.
|
||||
data: A string, the data to write. Goes into msg->msg_iov.
|
||||
control: A list of cmsg options. Becomes msg->msg_control.
|
||||
flags: An integer. Becomes msg->msg_flags.
|
||||
|
||||
Returns:
|
||||
If sendmsg succeeds, returns the number of bytes written as an integer.
|
||||
|
||||
Raises:
|
||||
socket.error: If sendmsg fails.
|
||||
"""
|
||||
# Create ctypes buffers and pointers from our structures. We need to hang on
|
||||
# to the underlying Python objects, because we don't want them to be garbage
|
||||
# collected and freed while we have C pointers to them.
|
||||
|
||||
# Convert the destination address into a struct sockaddr.
|
||||
if to:
|
||||
if isinstance(to, tuple):
|
||||
to = Sockaddr(to)
|
||||
msg_name = to.CPointer()
|
||||
msg_namelen = len(to)
|
||||
else:
|
||||
msg_name = 0
|
||||
msg_namelen = 0
|
||||
|
||||
# Convert the data to a data buffer and a struct iovec pointing at it.
|
||||
if data:
|
||||
databuf = ctypes.create_string_buffer(data)
|
||||
iov = Iovec((ctypes.addressof(databuf), len(data)))
|
||||
msg_iov = iov.CPointer()
|
||||
msg_iovlen = 1
|
||||
else:
|
||||
msg_iov = 0
|
||||
msg_iovlen = 0
|
||||
|
||||
# Marshal the cmsg options.
|
||||
if control:
|
||||
control = _MakeMsgControl(control)
|
||||
controlbuf = ctypes.create_string_buffer(control)
|
||||
msg_control = ctypes.addressof(controlbuf)
|
||||
msg_controllen = len(control)
|
||||
else:
|
||||
msg_control = 0
|
||||
msg_controllen = 0
|
||||
|
||||
# Assemble the struct msghdr.
|
||||
msghdr = MsgHdr((msg_name, msg_namelen, msg_iov, msg_iovlen,
|
||||
msg_control, msg_controllen, flags)).Pack()
|
||||
|
||||
# Call sendmsg.
|
||||
ret = libc.sendmsg(s.fileno(), msghdr, 0)
|
||||
MaybeRaiseSocketError(ret)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _ToSocketAddress(addr, alen):
|
||||
addr = addr[:alen]
|
||||
|
||||
# Attempt to convert the address to something we understand.
|
||||
if alen == 0:
|
||||
return None
|
||||
elif alen == len(SockaddrIn) and SockaddrIn(addr).family == socket.AF_INET:
|
||||
return SockaddrIn(addr)
|
||||
elif alen == len(SockaddrIn6) and SockaddrIn6(addr).family == socket.AF_INET6:
|
||||
return SockaddrIn6(addr)
|
||||
elif alen == len(SockaddrStorage): # Can this ever happen?
|
||||
return SockaddrStorage(addr)
|
||||
else:
|
||||
return addr # Unknown or malformed. Return the raw bytes.
|
||||
|
||||
|
||||
def Recvmsg(s, buflen, controllen, flags, addrlen=len(SockaddrStorage)):
|
||||
"""Python wrapper for recvmsg.
|
||||
|
||||
Args:
|
||||
s: A Python socket object. Becomes sockfd.
|
||||
buflen: An integer, the maximum number of bytes to read.
|
||||
addrlen: An integer, the maximum size of the source address.
|
||||
controllen: An integer, the maximum size of the cmsg buffer.
|
||||
|
||||
Returns:
|
||||
A tuple of received bytes, socket address tuple, and cmg list.
|
||||
|
||||
Raises:
|
||||
socket.error: If recvmsg fails.
|
||||
"""
|
||||
addr = ctypes.create_string_buffer(addrlen)
|
||||
msg_name = ctypes.addressof(addr)
|
||||
msg_namelen = addrlen
|
||||
|
||||
buf = ctypes.create_string_buffer(buflen)
|
||||
iov = Iovec((ctypes.addressof(buf), buflen))
|
||||
msg_iov = iov.CPointer()
|
||||
msg_iovlen = 1
|
||||
|
||||
control = ctypes.create_string_buffer(controllen)
|
||||
msg_control = ctypes.addressof(control)
|
||||
msg_controllen = controllen
|
||||
|
||||
msghdr = MsgHdr((msg_name, msg_namelen, msg_iov, msg_iovlen,
|
||||
msg_control, msg_controllen, flags))
|
||||
ret = libc.recvmsg(s.fileno(), VoidPointer(msghdr), flags)
|
||||
MaybeRaiseSocketError(ret)
|
||||
|
||||
data = buf.raw[:ret]
|
||||
msghdr = MsgHdr(str(msghdr._buffer.raw))
|
||||
addr = _ToSocketAddress(addr, msghdr.namelen)
|
||||
control = control.raw[:msghdr.msg_controllen]
|
||||
msglist = _ParseMsgControl(control)
|
||||
|
||||
return data, addr, msglist
|
||||
|
||||
|
||||
def Recvfrom(s, size, flags=0):
|
||||
"""Python wrapper for recvfrom."""
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
addr = ctypes.create_string_buffer(len(SockaddrStorage))
|
||||
alen = ctypes.c_int(len(addr))
|
||||
|
||||
ret = libc.recvfrom(s.fileno(), buf, len(buf), flags,
|
||||
addr, ctypes.byref(alen))
|
||||
MaybeRaiseSocketError(ret)
|
||||
|
||||
data = buf[:ret]
|
||||
alen = alen.value
|
||||
|
||||
addr = _ToSocketAddress(addr.raw, alen)
|
||||
|
||||
return data, addr
|
Loading…
Add table
Add a link
Reference in a new issue