0
votes

I want to pass a buffer of a network packet to C. I already figured out how to do that for simple OCaml types but I don't know how to pass a buffer from this CStruct library.

The library that I'm using uses https://github.com/mirage/ocaml-cstruct which I don't know why but looks like it mimics a C struct, so I guess it should be easy to pass this as a buffer to C.

This is how the buffer is created in my code:

let buf = Cstruct.create size in

If we look at its code, it calls https://github.com/mirage/ocaml-cstruct/blob/master/lib/cstruct.ml#L98 which is

let buffer = Bigarray_compat.(Array1.create char c_layout len) in
  { buffer ; len ; off = 0 }

For a recent version of OCaml, Bigarray is just the standar lib Bigarray, it's simply a module that does

include Stdlib.Bigarray

I couldn't find anything about passing a bigarray to C as a pointer that can be read.

1
What does this have to do with functional programming? - Scott Hunter

1 Answers

0
votes

interface.cc:

#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/bigarray.h>

uint8_t *return_big_array()
{
    static const value *make_and_fill_array_closure = NULL;
    if (make_and_fill_array_closure == NULL)
    {
        make_and_fill_array_closure = caml_named_value("make_and_fill_array");
        if (make_and_fill_array_closure == NULL)
        {
            printf("couldn't find OCaml function");
            std::exit(1);
        }
    }
    value bigArrayValue = caml_callback(*make_and_fill_array_closure, Val_unit);
    void *bigArrayPointer = Caml_ba_data_val(bigArrayValue);
    uint8_t *p = (uint8_t *)bigArrayPointer;
    return p;
}

main.cc

#include <stdio.h>
#include <caml/callback.h>

extern uint8_t* return_big_array();

int main(int argc, char ** argv)
{

  /* Initialize OCaml code */
  caml_startup(argv);
  /* Do some computation */
  uint8_t* p = return_big_array();
  //Should print 5
  printf("first element: %d \n", p[0]);
  return 0;
}

bigarray.ml:

open Format

let make_byte_array len = 
    Bigarray.Array1.create Bigarray.int8_signed Bigarray.c_layout len 

let make_and_fill_array () =  
    let b = make_byte_array 10 in 
    let s = Bigarray.Array1.fill b 5 in
    b

let () = Callback.register "make_and_fill_array" make_and_fill_array

Compile:

ocamlopt -output-obj -o s.o bigarray.ml
g++ -o bigarray -I $(ocamlopt -where) \
    main.cc interface.cc s.o $(ocamlopt -where)/libasmrun.a -ldl