Some questions about FFI (libuv)

I have two questions. I'm trying to make a test binding to libuv ... I don't quite understand few things on the rebol and on c side.

  1. When c creates a struct and passes its address to a function that then sets its fields.

    static struct sockaddr_in addr4;
    uv_ip4_addr(address_ip4, port, &addr4);

What should I do on FFI side to achieve the same? I tried to just allocate some memory (via malloc) and pass a pointer to that instead but it doesn't seem to work. I also tried to create hopefully correct struct! and pass addr-of to func but it doesn't seem to get set. In first case I can't know for sure, since I can't see what the address holds after the call, but the later c function that uses the addr behaves as if it weren't correctly set.

  1. ... I have a function that you give pointer to char and it sets the string to it. Is there a way to get to the containing c-string on that address from rebol side after it sets it?

    int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size)

I don't know anything about C or the FFI but I presume that you've looked at the example ?

I looked at the GTK example lately ( https://github.com/metaeducation/ren-c/blob/master/tests/misc/gtk.r ), since the one you linked was not up to date. make routine! doesn't work now for example - but make-routine.

But I see some new things in your example about struct and a buffer which might help me understand this.

... I figured out (2) at least in this case. the trick was making a buffer out of struct and a func I never saw before values of. Haven't figured out what reflect does, although I suspect. It creates a core dump when I try to use it.

name: make struct! [s [uint8 [128]]]
uv-ip4-name addr-of addr addr-of name 128

print name
print to-string values of name

//edit
first problem is solved too. The problem was that ubuntu has old libuv .. I recompiled the latest one myself and now binding to port works.

Good to hear.

What's the use case for using libuv given that we already have asynchronous networking in Ren-C?

I wanted to play with libuv for a while already. It has more multiplatform functionalites than just networking. And since @hostilefork said that rebol networking could be improved I wanted to see what style of API I would be getting to if I start from totally different perspective.

Currently I get negative length at read callback, and can't figure out why. A special variant of question no. (2) is again actual for another case:

const char* uv_strerror(int err); 

returns the description of error as a pointer. How can I turn this to string to print it in rebol? "Values of" doesn't work on this. I tried to set return value to struct, "uv-err-name: make-routine libuv "uv_err_name" [ n [ int32 ] return: [ struct! [s [uint8 [128]]] ] ]" but I don't get what I would like to. I can't find in source code of libev what -105 should mean. It looks error codes aren't defined in classic way.

The problem maybe starts one callback before: alloc-buffer is called before on_read like this:

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
  buf->base = (char*) malloc(suggested_size);
  buf->len = suggested_size;
}

or like this

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
  *buf = uv_buf_init((char*) malloc(suggested_size), suggested_size);
}

I do it like this:

alloc-buffer: make-callback [
  handle [ pointer ]
  size [ int32 ]
  buf [ struct! [ base [ pointer ] len [ int32 ] ] ]
] [
  buf/base: mem-alloc size
  buf/len: size
]

Glad you're looking into this and are such a self-starter. :slight_smile:

I'm a little busy right now with New Years and travel to really be able to help the next few days. But I will say my opinion that the way to go for most of these bindings/extensions is probably to avoid FFI, if you are comfortable with C. The way we're leaning is to let you establish a module as some C code and some Rebol code.

For example, look at how the ODBC is done. You write a REBNATIVE(your_function) and you can embed the spec in C comments (spacing matters!):

Then, you put together any supporting Rebol code, the text of which is compressed and put in the DLL along with the compiled C:

While the ergonomics of the build system and the exact way this all fits together needs work (imo), the idea is on the right track. There are a lot of advantages of going this route instead of trying to do FFI--your extension will not depend on the FFI (itself an extension, which is mostly factored out). It will be a bit faster. And you'll have a nicer time debugging directly with a C debugger.

As I said, I'm a little busy at the moment. But if this is a real focus for you and you're willing to make some amount of commitment to working on it :slight_smile: then I can get involved supporting you on it.