[erlang-questions] Encode and decode binary data on port driver: undefined symbol ei_decode_version

Brisa Jiménez <>
Thu Nov 22 20:09:18 CET 2012


Hi everyone!
I want to send and receive binary data through Erlang port, and use ei to
encode and decode data, but when I try to test code below the next error
occurs:

Erlang R14B03 (erts-5.8.4) [source] [rq:1] [async-threads:0]
[kernel-poll:false]

Eshell V5.8.4  (abort with ^G)
1> erl_drv:start().
** exception exit: {error,"undefined symbol: ei_decode_version"}
     in function  erl_drv:start/0

Can anybody give me an example of how do it what I'm want?
I appreciate any advice.
Thanks.

===

-module(erl_drv).
-export([start/0, stop/0, init/1]).
-export([foz/1, baz/1]).
-define(C_LIBRARY, "library").

start() ->
    case erl_ddll:load_driver("priv", ?C_LIBRARY) of
ok -> ok;
{error, already_loaded} -> ok;
 {error, Reason}-> exit({error, erl_ddll:format_error(Reason)})
    end,
    spawn(?MODULE, init, [?C_LIBRARY]).

init(?C_LIBRARY) ->
    register(erl_drv, self()),
    Port = open_port({spawn, ?C_LIBRARY}, [binary]),
    loop(Port).

stop() ->
    erl_drv ! stop.

foz(Arg)->
    call_port({foz, Arg}).

baz(Arg)->
    call_port({baz, Arg}).

call_port(Msg) ->
    erl_drv ! {call, self(), Msg},
    receive
        {erl_drv, Res} ->
    Res
    end.

loop(Port) ->
    receive
 {call, Caller, {Command, Data}}->
    case Command of
foz-> port_control(Port, 3, encode(Data));
 baz-> port_control(Port, 4, encode(Data))
    end,

    receive
        {Port, {data, Data}} ->
    Caller ! {erl_drv, decode(Data)}
       end,
    loop(Port);
    stop ->
    Port ! {self(), close},
    receive
{Port, closed} ->
    exit(normal)
    end;
    {'EXIT', Port, Reason} ->
    io:format("~p ~n", [Reason]),
    exit(port_terminated)
    end.

encode(Msg)->
    term_to_binary(Msg).

decode(RetVal)->
    binary_to_term(RetVal).

===

/* port_driver.c*/

#include <stdio.h>
#include "erl_driver.h"
#include "ei.h"
#include "erl_interface.h"

double foz(double);
double baz(double);

typedef size_t ErlDrvSizeT;
typedef ssize_t ErlDrvSSizeT;

typedef struct {
    ErlDrvPort port;
} ptr_port;

static ErlDrvData start(ErlDrvPort port, char *buff)
{
    ptr_port* ptr_port1 = (ptr_port*)driver_alloc(sizeof(ptr_port));
    set_port_control_flags(port , PORT_CONTROL_FLAG_BINARY);
    ptr_port1->port = port;
    return (ErlDrvData)ptr_port1;
}

static void stop(ErlDrvData handle)
{
    driver_free((char*)handle);
}

static ErlDrvSSizeT control(ErlDrvData handle, unsigned int command,
                            char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
ptr_port *ptr_port1 = (ptr_port*)handle;
    double arg, res;
    int version, index = 0;

    if (ei_decode_version(buf, &index, &version))
        return((ErlDrvSSizeT) ERL_DRV_ERROR_GENERAL);
    if (ei_decode_double(buf, &index, &arg))
        return((ErlDrvSSizeT) ERL_DRV_ERROR_BADARG);
    switch (command) {
        case 3:
            res = foz(arg);
            break;
        case 4:
            res = baz(arg);
            break;
        default:
            return((ErlDrvSSizeT) ERL_DRV_ERROR_BADARG);
    }
    index = 0;
    if (ei_encode_version(*rbuf, &index)
            || ei_encode_double(*rbuf, &index, res))
        return((ErlDrvSSizeT) ERL_DRV_ERROR_ERRNO);
    else
        return((ErlDrvSSizeT) index);
}

ErlDrvEntry driver_entry = {
    NULL, //* F_PTR init, N/A
    start, //* L_PTR start, called when port is opened
    stop, //* F_PTR stop, called when port is closed
 NULL, //* F_PTR output, called when erlang has sent
    NULL, //* F_PTR ready_input, called when input descriptor ready
    NULL, //* F_PTR ready_output, called when output descriptor ready
    "library", //* char *driver_name, the argument to open_port
    NULL, //* F_PTR finish, called when unloaded
    control, //* F_PTR control, port_command callback
    NULL, //* F_PTR timeout, reserved
    NULL //* F_PTR outputv, reserved
};

DRIVER_INIT(library) /* must match name in driver_entry */
{
return &driver_entry;
}

===

/*library.c*/

double foz(double x) {
return x/1.0;
}

double baz(double y) {
return y/2.0;
}

===

# Makefile

ERL_ROOT=/usr/local/lib/erlang

all: compile_c compile

compile_c:
@mkdir -p priv
 gcc -o priv/library.so -I$(ERL_ROOT)/usr/include/
-I$(ERL_ROOT)/lib/erl_interface-3.7.4/include/ -fpic -shared c_src/*.c

compile:
 @mkdir -p ebin
erlc -o ebin/ src/erl_drv.erl

clean:
 @rm -rf ebin priv

test:
erl -pa ebin/
 .PHONY: c_src
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20121122/7840bf20/attachment.html>


More information about the erlang-questions mailing list