3

I'm trying to convert a 16 byte blob of data returned by socket.inet_pton into a ctypes array of unsigned bytes. My data structure looks like this:

class in6_addr(ctypes.Structure):
    _fields_ = (("Byte", ctypes.c_ubyte * 16),)

And the blob is just:

data = socket.inet_pton(socket.AF_INET6, "2001::3")

However, these attempts get errors:

sin6 = in6_addr()

# TypeError: expected c_ubyte_Array_16 instance, got str
sin6.Byte = data
# TypeError: cast() argument 2 must be a pointer type, not c_ubyte_Array_16
sin6.Byte = ctypes.cast(data, ctypes.c_ubyte * 16)
# TypeError: incompatible types, LP_c_ubyte instance instead of c_ubyte_Array_16 instance
sin6.Byte = ctypes.cast(data, ctypes.POINTER(ctypes.c_ubyte))

All of the code: http://codepad.org/2cjyVXBA

Any ideas what type I need to cast to?

3 Answers 3

3

I might be completely wrong here (and it does seem a bit complex) but this works for me:

sin6.Byte = (ctypes.c_ubyte*16)(*list(bytearray(data)))

I had to convert the data into a list of integers and unpack them for the constructor. There must be an easier way!

Sign up to request clarification or add additional context in comments.

1 Comment

Can be more simple: sin6.Byte = (ctypes.c_ubyte * 16)(*data)
2

Arguably easier:

sin6.Byte = cast(data, ctypes.POINTER(ctypes.c_ubyte * 16)).contents

or:

sin6.Byte = (ctypes.c_ubyte * 16)(*[x for x in data])

Using bytes stream:

import io
io.BytesIO(data).readinto(sin6.Byte)

And since the considered structure contains the single field, the field name can be omited:

sin6 = (ctypes.c_ubyte * 16)(*data)
sin6 = cast(data, ctypes.POINTER(ctypes.c_ubyte * 16)).contents
io.BytesIO(data).readinto(sin6)

Comments

0

Easiest way:

import ctypes
import socket

class in6_addr(ctypes.Structure):
    _fields_ = (("Byte", ctypes.c_ubyte * 16),)

data = socket.inet_pton(socket.AF_INET6, "2001::3")

sin6 = in6_addr()
sin6.Byte[:] = data   # copy the data into a complete slice of the array

A couple of helper methods make the class easier to use as well:

import ctypes
import socket

class in6_addr(ctypes.Structure):
    _fields_ = ("Byte", ctypes.c_ubyte * 16),

    def __init__(self, data):
        self.Byte[:] = data

    def __repr__(self):
        return f'in6_addr(Bytes=bytes({list(self.Byte)}))'

data = socket.inet_pton(socket.AF_INET6, "2001::3")
sin6 = in6_addr(data)
print(sin6)

Output:

in6_addr(Bytes=bytes([32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.