5

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);
user207421
  • 305,947
  • 44
  • 307
  • 483
townlong
  • 189
  • 1
  • 7
  • 20
  • 7
    What are you actually trying to achieve? Show your python code. – Marcin Dec 03 '12 at 18:44
  • 5
    That appears to be socket related code. The Python [`socket`](http://docs.python.org/2/library/socket.html) library does a lot of that stuff for you, so you don't have to worry about using `htons()` etc in Python code. So it's hard to say without seeing more of your C code. – Greg Hewgill Dec 03 '12 at 18:47
  • 11
    Very, very rarely do you want to do a direct line-by-line transcoding. This is inefficient and fails to leverage the strengths of the new language. – Donnie Dec 03 '12 at 18:48
  • 1
    I would be asking what @marcin is - what is it that you're trying to do... what's the end goal for instance? – Jon Clements Dec 03 '12 at 18:48

2 Answers2

7

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.

abarnert
  • 354,177
  • 51
  • 601
  • 671
6

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.

Keith
  • 42,110
  • 11
  • 57
  • 76
  • 1
    Unless he's trying to, e.g., craft raw IP packets instead of just creating a socket, this is the right answer. – abarnert Dec 03 '12 at 19:07