preserving state in driver process between callbacks to emulator

Jacob Vorreuter <>
Tue Jun 1 02:22:23 CEST 2010


As my linked-in driver adventure continues, I'm at a point where I'm wondering if there's a way to maintain state between callbacks to the emulator.  I'm writing an http proxy driver and I would like to be able to read the http headers from the client socket, return the host header to the Erlang emulator, receive back the ip and port of the backend server to connect to and then proxy the previously collected headers as well as the request body to the backend server.  My question is how to store the header data so that it's available on subsequent calls to the driver.

Is there a structure that persists between calls from the emulator?  I started structuring my driver as follows:

static void process(ErlDrvData handle, ErlIOVec *ev) {
    basic_drv_t* driver_data = (basic_drv_t*) handle;
    ErlDrvBinary* data = ev->binv[1];
    int cmd = data->orig_bytes[0];
    if(cmd == 1) {
	// read client fd from orig_bytes
	int clientfd = ...
	// read headers from client socket
	char *headers = ...
	// read host header
	char *host = ...
	// send host back to emulator to determine appropriate backend server
	ErlDrvTermData spec[] = {
            ERL_DRV_ATOM, driver_mk_atom("host"), 
            ERL_DRV_STRING, (ErlDrvTermData)host, strlen(host),
            ERL_DRV_TUPLE, 2
        };
        driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0]));
    } else if(cmd == 2) {
        // read backend host and port from orig_bytes
	// connect to backend server
	// proxy *headers data from above to backend server
	ErlDrvTermData spec[] = {ERL_DRV_ATOM, driver_mk_atom("ok")};
    	driver_output_term(driver_data->port, spec, sizeof(spec) / sizeof(spec[0]));
    }
}

And the Erlang code is something like this:

proxy_client_request(Fd) when is_integer(Fd) ->
    Port = open_port({spawn, 'basic_drv'}, [binary]),
    Cmd1 = 1,
    port_command(Port, <<Cmd1:8/integer, Fd:32/unsigned-integer>>),
    receive
        {host, Host} ->
		{ServerHost, ServerPort} = lookup_backend(Host),
		Cmd2 = 2,
   HostSize = size(ServerHost),
   port_command(Port, <<Cmd2:8/integer, Fd:32/unsigned-integer, ServerPort:32/unsigned-integer, HostSize:8/integer, ServerHost/binary>>),
   receive ok -> ok end
    after 5000 ->
        {error, timeout}
    end,
    port_close(Port).

Does is make sense what I'm trying to do?  Any insight?

Thanks, Jake




More information about the erlang-questions mailing list