I’m studying on how to integrate MirageOS OCaml TCP/IP stack into my C++ project. I already know how to call C from OCaml and call OCaml from C.
The OCaml will be controlled by C++, not the other way around. So, for a TCP/IP stack, I must be able to send and receive packets. I can easily send data to the TCP/IP stack through C++ calling OCaml, but how to receive it?
For example: the TCP/IP stack might have its own thread waiting for packets to arrive, but at some point, it must deliver it to C++ code. Ideally I’d like to pass a C function onTcpPacket(uint8_t* payload) to act as a callback. That is, OCaml would be able to call onTcpPacket with the payload buffer.
There’s also a concern about which threads can access or be accessed by OCaml runtime but I guess it shouldn’t be a problem.
Indeed you’re precisely right. In the language of most higher-level programming languages, the terms “callback” and (sometimes) “callout” are reserved for a call from C to the language. The term for “call from language X to C/C++” is invariably “foreign function interface”. Thus (barring odd/interesting/pathological edge-cases) your requirement, “a way to call from Ocaml into C/C++” should be the most straightforward thing, and well-supported.
It’s the other direction ( a call from C/C++ into Ocaml code) that is harder to support.
How I understand the question is (not knowing anything about any MirageOS anything)
OCaml: output_as_packet: bytes -> (bytes -> int -> ()) -> int
C++: n = ocaml_output_as_packet(caml_alloc_initialized_string(n, buf), Val_function(TcpPacket));
– except that there is nothing like Val_function, is there?
But he can make a helper function or two and pass around a function in a custom data object, so while the received object can’t be treated directly as a function, OCaml code can call its function indirectly.
type packet_object
external call_packet_object: packet_object -> bytes -> int -> int = “c_call_me”
Im trying to understand your answer. output_as_packet would be called with the bytes, but what is the second argument? A function that gets bytes and a size? Why is it needed?
What is Val_function?
I had a very simple idea: pass the int64_t address of the pointer to OCaml, and OCaml calls a simple C function passing this number and the packet, and then C calls another function that executes the pointer with the buffer.
But if you guys have a better idea, I’d prefer
Anyways, can buffers be passed from OCaml to C? Which structure should I use?
MirageOS seems to use Cstruct, but I dont know how it works
The int is indeed a byte count. Not strictly necessary, it just allows you to use a partially filled byte buffer without copying it to one with a smaller size. Maybe I’m too old school.
There is no Val_function, as far as I know.
I believe your int64_t pointer is the very same concept as my proposed work-around, so you may choose whichever you like best. int64_t is simpler to implement than a custom object, and in today’s increasingly tradition bound computing environment there seems to be no chance that it could fail as a way to pass a pointer to a function.
int8_t is string/byte, to my simple way of looking at it anyway.