Current section

Files

Jump to
libsodium c_src libsodium_drv.c
Raw

c_src/libsodium_drv.c

// -*- mode: c; tab-width: 8; indent-tabs-mode: 1; st-rulers: [70] -*-
// vim: ts=8 sw=8 ft=c noet
#include "libsodium_drv.h"
#include "libsodium_port.h"
#include "libsodium_request.h"
#include "libsodium_api.h"
#define INIT_ATOM(NAME) libsodium_drv->am_ ## NAME = driver_mk_atom(#NAME)
/*
* Erlang DRV functions
*/
static int
libsodium_drv_init(void)
{
TRACE_F("libsodium_drv_init:%s:%d\n", __FILE__, __LINE__);
if (libsodium_mutex == NULL) {
libsodium_mutex = erl_drv_mutex_create("libsodium");
if (libsodium_mutex == NULL) {
return -1;
}
}
(void) erl_drv_mutex_lock(libsodium_mutex);
if (sodium_init() == -1) {
(void) erl_drv_mutex_unlock(libsodium_mutex);
return -1;
}
if (libsodium_drv == NULL) {
libsodium_drv = (libsodium_drv_term_data_t *)(driver_alloc(sizeof (libsodium_drv_term_data_t)));
if (libsodium_drv == NULL) {
(void) erl_drv_mutex_unlock(libsodium_mutex);
return -1;
}
INIT_ATOM(ok);
INIT_ATOM(error);
INIT_ATOM(undefined);
}
(void) init_libsodium_api();
(void) erl_drv_mutex_unlock(libsodium_mutex);
return 0;
}
static ErlDrvData
libsodium_drv_start(ErlDrvPort drv_port, char *command)
{
libsodium_port_t *port;
(void) command; // Unused
TRACE_F("libsodium_drv_start:%s:%d\n", __FILE__, __LINE__);
port = libsodium_port_alloc(drv_port);
if (port == NULL) {
return ERL_DRV_ERROR_GENERAL;
}
return (ErlDrvData)(port);
}
static void
libsodium_drv_stop(ErlDrvData drv_data)
{
libsodium_port_t *port;
TRACE_F("libsodium_drv_stop:%s:%d\n", __FILE__, __LINE__);
port = (libsodium_port_t *)(drv_data);
(void) libsodium_port_free(port);
}
static void
libsodium_drv_finish(void)
{
TRACE_F("libsodium_drv_finish:%s:%d\n", __FILE__, __LINE__);
if (libsodium_mutex != NULL) {
(void) erl_drv_mutex_lock(libsodium_mutex);
}
if (libsodium_drv != NULL) {
(void) driver_free(libsodium_drv);
libsodium_drv = NULL;
}
if (libsodium_mutex != NULL) {
(void) erl_drv_mutex_unlock(libsodium_mutex);
(void) erl_drv_mutex_destroy(libsodium_mutex);
libsodium_mutex = NULL;
}
}
static ErlDrvSSizeT
libsodium_drv_call(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen, unsigned int *flags)
{
libsodium_port_t *port;
ErlDrvTermData caller;
libsodium_request_t *request;
ErlDrvSSizeT retval;
(void) flags; // Unused
TRACE_F("libsodium_drv_call:%s:%d\n", __FILE__, __LINE__);
port = (libsodium_port_t *)(drv_data);
if (port == NULL) {
return (ErlDrvSSizeT)(ERL_DRV_ERROR_GENERAL);
}
// (void) erl_drv_mutex_lock(libsodium_mutex);
caller = driver_caller(port->drv_port);
// (void) erl_drv_mutex_unlock(libsodium_mutex);
request = libsodium_request_alloc(port, caller, command);
if (request == NULL) {
LS_FAIL_OOM(port->drv_port);
return (ErlDrvSSizeT)(ERL_DRV_ERROR_GENERAL);
}
if (request->error < 0) {
retval = (ErlDrvSSizeT)(request->error);
(void) libsodium_request_free(request);
return retval;
}
(void) (request->command)(&request, buf, len);
if (request->error < 0) {
retval = (ErlDrvSSizeT)(request->error);
(void) libsodium_request_free(request);
return retval;
}
retval = (ErlDrvSSizeT)(request->reply.index);
if (rlen < retval) {
*rbuf = (char *)(driver_realloc((void *)(*rbuf), (ErlDrvSizeT)(retval)));
if ((*rbuf) == NULL) {
(void) libsodium_request_free(request);
LS_FAIL_OOM(port->drv_port);
return (ErlDrvSSizeT)(ERL_DRV_ERROR_GENERAL);
}
}
(void) memcpy((void *)(*rbuf), (void *)(request->reply.buff), (size_t)(request->reply.index));
(void) libsodium_request_free(request);
return retval;
}
DRIVER_INIT(libsodium_drv)
{
return &libsodium_driver_entry;
}