On Sat, Mar 3, 2018 at 10:58 PM, Richard Hainsworth
<rnhainswo...@gmail.com> wrote:
> I realised from the C documentation that a fixed 14 byte variable was
> required, but I could not find a mention about how to map that into Perl6.
> Suppose it was necessary to create a structure, how would this be done?

There isn't (currently?) a way (that I know of?) to declare an actual
array inside a CStruct:
(See 
https://stackoverflow.com/questions/48646159/declaring-an-array-inside-a-perl-6-nativecall-cstruct)

I've worked around this a few times.  I just stuff enough
int64/int32/etc. in there to make the right number of bytes.

You can see that in SockAddr-in6, which needs a 16 byte address field.
I just put two int64s in there which take
8 bytes each.

> Actually you use .allocate  below, is this the mechanism?

You could do that too.  Just make a Buf with the right number of total
bytes, but then you have to write the code to access the bits you need
within the Buf.  CStruct repr gives some nice syntax even if it
doesn't (yet) support arrays.

>> sub inet_ntop(int32, Pointer, Blob, int32 --> Str)
>>      is native() {}
>
> a) Blob is TBD in NativeCall
> Some explanation would be useful.

A Blob is just a raw bunch of bytes, can be a Blob (immutable) or a
Buf (mutable).

> b) I used 'returns Str' and you have used '--> Str'
> Are the two equivalent and the choice is a programmer style one, or are
> there differences?
> Is there a reason '-->' is better than 'returns'?

Both are identical.  I used to use returns all the time.  I prefer -->
of late since it puts the whole signature between the parens, which I
think is nice.  I believe the preference is now for -->, and there is
talk of deprecating 'returns' eventually.

Some discussion here:
https://docs.perl6.org/type/Signature#index-entry---%3E-returns-Constraining_Return_Types

> I have not come across the stanza 'buf8.allocate(...)' before.

https://docs.perl6.org/routine/allocate#role_Blob

It just makes a buffer with that number of elements.
buf8 is shorthand for Buf[uint8] a buffer of plain 8 bit bytes, so
buf8.allocate(n) make a buffer of n bytes.
inet_ntop() requires a buffer of already allocated memory to hold the
string it is writing.

We've declared inet_ntop() as returning a Str, so a pointer to that
buffer also gets returned, which Perl then decodes into a new string
which gets returned, while the actual buffer falls out of scope and
eventually gets garbage collected.

> Are these zero initialised automatically by Perl6?

I think so (pretty sure), but I'm not certain of this..  It doesn't
matter for this, since inet_ntop() doesn't depend on it.  It writes a
NUL terminated C-String into the buffer.

> Also the code 'Pointer.new(nativecast(Pointer,self)+4)'

for inet_ntop(), we need a Pointer directly to the address part of the
sockaddr structures.

self = is Perl 6 reference to the SockAddr-in structure in memory.
nativecast(Pointer,self) = turn it into a Pointer that points to the
structure in memory.
It starts at the beginning of the CStruct, so it points to the
'$.sin_family' attribute.
Pointers can be treated as integers that are memory addresses. +4
skips over the 2 bytes of sin_family and 2 bytes of sin_port, so it
becomes an integer memory address for the sin_addr, but then we need
to turn that memory address back into a Pointer with Pointer.new() to
use it as a Pointer.

nativecast() is a very powerful, but very dangerous way to change the
way Perl thinks about a pointer.  You can easily get SEGVs if you do
it wrong.

> I understand you said pointer arithmetic. Where did the +4 for INET and +8
> for INET6 come from?

same process for the INET6, but we need to skip over family, port,
flowinfo (8 bytes total) to point to the address field.

Would be nice to add a "native-cstruct-pointer-to-attribute" or
something like that that does what in C would be &(sockaddr->sin_addr)
to get the address of an element inside a CStruct.

Curt

Reply via email to