Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is there a Python Equivalent to Memcpy

Tags:

python

c

memcpy

I am trying to port some C Code but I am really stuck cause of the use of memcpy I tried with ctypes (did not work). I am hoping to find a python way of using an equivalent function of memcpy

Any ideas

Here is an example of the C Code I am trying to port

i = l + 5;
t = htons(atoi(port));
memcpy((buf+i), &t, 2);
like image 996
townlong Avatar asked Dec 03 '12 18:12

townlong


2 Answers

You almost certainly don't need to call htons and then copy the 2 bytes into a buffer—see Keith's answer for why.

However, if you do need to do this (maybe you're crafting IP packets to compare to captured wire packets as a test or something?), you can.

First, if you're using a bytearray (or anything else that meets the writable buffer protocol), you just use normal list-style slice assignment:

# like C's memcpy(buf+i, foo, 2)
buf[i:i+2] = foo

You don't have that two-byte string foo; you have a short integer. In C, you can turn that into a pointer to two bytes just by using the & operator to get its address, but Python can't do that. Fortunately, there's a standard library module called struct designed for exactly this kind of thing:

t = socket.htons(int(port))
buf[i:i+2] = struct.pack('h', t)

Or, because struct can handle endianness for you:

t = int(port)
buf[i:i+2] = struct.pack('!h', t)

However, often you don't even need the buffer copying; you can define the entire structure all at once inside struct. For example, if you're trying to pack an IP address and port into a 6-byte array, you could do this:

buf = bytearray(6)
i = 0
addrbytes = [int(part) for part in addr.split('.')]
buf[i:i+4] = struct.pack('4B', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3])
i += 4
portshort = int(port)
buf[i:i+2] = struct.pack('!h', portshort)

But this is much simpler:

addrbytes = [int(part) for part in addr.split('.')]
portshort = int(port)
buf = struct.pack('!4Bh', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3], portshort)

I've just defined a structure that's in network order, with four bytes followed by a short, and packed my data into it.

One last thing to mention: If you really want to deal with C-style variables using C-style code, the ctypes module is another option. It's made specifically for interacting with C code, so in general it's pretty low-level (and the only module in the standard library that lets you segfault your code), but it let you build some nice mid-level stuff that looks a little more like C:

class ADDRPORT(ctypes.BigEndianStructure):
    _fields_ = [("addr", ctypes.c_char*4),
                ("port", ctypes.c_short)]

addrport = ADDRPORT(addrbytes, portshort)

Since your C code is progressively filling up a buffer, rather than setting elements of a struct, this probably isn't what you want. But it's worth being aware of, because it probably will be what you want at some point.

like image 57
abarnert Avatar answered Oct 20 '22 23:10

abarnert


It looks like you are trying to get a port number from user input or a string.

In Python:

port = int(port)

Then you can pass that directly to a socket instantiation:

socket = socket.socket(("127.0.0.1", port))

Python does the htons translation for you. You only need to supply an address to a socket (in the case of TCP) as a tuple of a string and integer.

like image 42
Keith Avatar answered Oct 21 '22 01:10

Keith