Erlang Port drivers and Erl_interface

Robert Raschke rrerlang@REDACTED
Thu Jan 27 15:09:47 CET 2005


Hi Eranga,

you wrote:
> Let's say I want to pass a complex structure back and forth. And I opened
> the linked-in driver port using binary. Then can I use term_to_binary and
> binary_to_term in the Erlang side and erl_decode, erl_encode and other erl
> interface functions in the C side?

I have been using the term_to_binary and binary_to_term functions as
well.  In my C port program I use the ei_decode...() and
ei_encode...() functions.  It took me a little bit to get used to the
way these functions handle the message buffer, but with a little bit
of experimentation you will get up and running quickly.

For example I send my requests from erlang in a predefined format
(obviously), and then I unpack it in my C program like this, with the
x_in buffer holding a message.  It is very verbose, as I was learning
how the ei functions work while writing it.

static void
handle_regular_message(ei_x_buff *x_in, ei_x_buff *x_out)
{
	int valid = 1;
	int version;
	int arity;
	char call_atom[MAXATOMLEN];
	erlang_pid from;
	char fn_atom[MAXATOMLEN];

	/*
		Incoming message has to be
			{call, Caller_Pid, Fn, [Params]}
		with
			call - the atom 'call'
			Caller_Pid - erlang pid of process that sent the message
			Fn - name as atom of the function to invoke
			Params - parameters to pass to Fn

		For an invalid request message the return message has the form
	   		{error, badmsg}

		For a valid request message the return message has the form
	   		{Caller_Pid, Result}
		with
			Result = ok | {ok, Value} | {error, internal, error} | {error, badarg, args}
	*/

	if (valid && ei_decode_version(x_in->buff, &x_in->index, &version) != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message (bad version).\n");
		valid = 0;
	}

	if (valid && ei_decode_tuple_header(x_in->buff, &x_in->index, &arity) != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message (not tuple).\n");
		valid = 0;
	}
	if (valid && arity != 4) {
		fprintf(stderr, "Warning: Ignoring received malformed message (not 4-arity tuple).\n");
		valid = 0;
	}

	if (valid && ei_decode_atom(x_in->buff, &x_in->index, call_atom) != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message (first tuple element not atom).\n");
		valid = 0;
	}
	if (valid && strcmp(call_atom, "call") != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message"
			" (first tuple element not atom 'call').\n");
		valid = 0;
	}

	if (valid && ei_decode_pid(x_in->buff, &x_in->index, &from) != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message (Second tuple element not pid).\n");
		valid = 0;
	}

	if (valid && ei_decode_atom(x_in->buff, &x_in->index, fn_atom) != 0) {
		fprintf(stderr, "Warning: Ignoring received malformed message (Third tuple element not atom).\n");
		valid = 0;
	}

	if (valid) {
		x_out->index = 0;
		ei_x_encode_version(x_out);
		ei_x_encode_tuple_header(x_out, 2);
		ei_x_encode_pid(x_out, &from);

		fprintf(stderr, "Attempting to call e_%s().\n", fn_atom);

		if (strcmp(fn_atom, "my_fun_1") == 0) my_fun_1(x_in, x_out);
		else if (strcmp(fn_atom, "my_fun_2") == 0) my_fun_2(x_in, x_out);
		else if (strcmp(fn_atom, "my_fun_3") == 0) my_fun_3(x_in, x_out);
		else {
			fprintf(stderr, "Warning: Ignoring received malformed message"
				" (Third tuple element not recognised function).\n");
			valid = 0;
		}
		if (valid) {
			fprintf(stderr, "Returned from my_fun().\n");
		}
	}

	if (! valid) {
		x_out->index = 0;
		ei_x_encode_version(x_out);
		ei_x_encode_tuple_header(x_out, 2);
		ei_x_encode_atom(x_out, "error");
		ei_x_encode_atom(x_out, "badmsg");
	}
}

Each function I invoke (my_fun()) takes apart the rest of the x_in
buffer, and completes the result buffer x_out (which gets sent back to
Erlang).

I hope this gets you further along,
Robby




More information about the erlang-questions mailing list