Hello,
I am trying to create a buffer which can be send with sendto (so the second argument of that function).
So far I have found two code snippets in C, which do what I want. Though I am a bit confused how to convert this to Nim. Using Stackoverflow I got a better understanding of the C snippets.
But I am not able to figure out how to translate one of the examples below to nim. Please see the attached sources for more context.
Example 1:
# https://github.com/amitsaha/ping/blob/master/ping.c
icp = (struct icmphdr *)packet;
/* We are sending a ICMP_ECHO ICMP packet */
icp->type = ICMP_ECHO;
icp->code = 0;
icp->checksum = 0;
icp->un.echo.sequence = htons(ntransmitted+1);
Example 2:
#https://github.com/amitsaha/ping/blob/master/ping.c
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = getpid();
for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
pckt.msg[i] = i+'0';
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = msg_count++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
Note bzero is outdated, memset would be a more modern choice.
On line 128 in this snippet a buffer is created, but this seems so custom.. this wasn't any use to my n00b level.
Any ideas?
Great idea! I have been trying to do so with c2nim, but it get something along the lines of
icp = cast[ptr icmphdr](packet)
## We are sending a ICMP_ECHO ICMP packet
icp.`type` = ICMP_ECHO
icp.code = 0
icp.checksum = 0
icp.un.echo.sequence = htons(ntransmitted + 1)
It actually fails to understand what to do with icmphdr. So I am not sure this is a feasible approach.
How would you wrap the code? I have been trying to do that, but I am not very experienced with wrapping C/C++ in nim.
you must first wrap the icmphdr struct itself.
https://sites.uclouvain.be/SystInfo/usr/include/netinet/ip_icmp.h.html
struct icmphdr
{
u_int8_t type; /* message type */
u_int8_t code; /* type sub-code */
u_int16_t checksum;
union
{
struct
{
u_int16_t id;
u_int16_t sequence;
} echo; /* echo datagram */
u_int32_t gateway; /* gateway address */
struct
{
u_int16_t __unused;
u_int16_t mtu;
} frag; /* path mtu discovery */
} un;
};
Thanks so far.
I have come up with the following code:
INNER_C_STRUCT_ping_24* {.bycopy.} = object
id*: uint16
sequence*: uint16
INNER_C_STRUCT_ping_30* {.bycopy.} = object
unused*: uint16
mtu*: uint16
INNER_C_UNION_ping_22* {.bycopy, union.} = object
echo*: INNER_C_STRUCT_ping_24 ## echo datagram
gateway*: uint32 ## gateway address
frag*: INNER_C_STRUCT_ping_30 ## path mtu discovery
icmphdr* {.bycopy.} = object
typee*: uint8 ## message type
code*: uint8 ## type sub-code
checksum*: uint16
un*: INNER_C_UNION_ping_22
var icp*: ptr icmphdr
var packet*: ptr cuchar
#let icp = cast[ptr icmphdr](packet)
## We are sending a ICMP_ECHO ICMP packet
icp.typee = 8
icp.code = 0
icp.checksum = 0
#icp.un.echo.sequence = htons(ntransmitted + 1)
Now, this gives a SIGSEGV when compiling. I think I am writing to memory to which I am not allowed.. but I am not sure. Note: where it says typee it used to say type.
Do you have a clue how I should proceed?
I get a sigsegv at runtime with that code
Trying to access members of icp without initializing it is a classic null pointer dereference.
One way to translate that snippet out of ping.c could be:
const
datalen = 56
MAXIPLEN = 60
MAXICMPLEN = 76
packlen = datalen + MAXIPLEN + MAXICMPLEN
let
packet = create array[packlen, byte]
var
ntransmitted = 0
icp: ptr icmphdr = cast[ptr icmphdr](packet)
Plus that error handling.
ntransmitted should be a uint16, You can use htons from std/nativesockets