static void zmqdrv_getsockopt(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; uint32_t idx = ntohl(*(uint32_t*)(bytes+1)); void* s = drv->get_zmq_socket(idx); uint32_t opt = ntohl (*(uint32_t*)(bytes+sizeof(idx)+1)); if (opt == ZMQ_RCVMORE) { int64_t val; size_t valsz = sizeof (val); if (zmq_getsockopt (s, opt, &val, &valsz) < 0) { zmqdrv_error_code(drv, zmq_errno()); return; } ErlDrvTermData spec[] = { ERL_DRV_ATOM, am_zok, ERL_DRV_ATOM, (val ? am_true : am_false), ERL_DRV_TUPLE, 2}; driver_send_term(drv->port, driver_caller(drv->port), spec, sizeof(spec)/sizeof(spec[0])); return; } zmqdrv_error(drv, "Not implemented"); }
/* Erlang command, called on binary input from VM. */ static void zmqdrv_outputv(ErlDrvData handle, ErlIOVec *ev) { zmq_drv_t* drv = (zmq_drv_t *)handle; ErlDrvBinary* data = ev->binv[1]; unsigned char cmd = data->orig_bytes[0]; // First byte is the command zmqdrv_fprintf("driver got command %d on thread %p\r\n", (int)cmd, erl_drv_thread_self()); switch (cmd) { case ZMQ_INIT : zmqdrv_init(drv, ev); break; case ZMQ_TERM : zmqdrv_term(drv, ev); break; case ZMQ_SOCKET : zmqdrv_socket(drv, ev); break; case ZMQ_CLOSE : zmqdrv_close(drv, ev); break; case ZMQ_SETSOCKOPT : zmqdrv_setsockopt(drv, ev); break; case ZMQ_GETSOCKOPT : zmqdrv_getsockopt(drv, ev); break; case ZMQ_BIND : zmqdrv_bind(drv, ev); break; case ZMQ_CONNECT : zmqdrv_connect(drv, ev); break; case ZMQ_SEND : zmqdrv_send(drv, ev); break; case ZMQ_RECV : zmqdrv_recv(drv, ev); break; default : zmqdrv_error(drv, "Invalid driver command"); } }
static void zmqdrv_socket(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; int type = *(bytes + 1); void* s = zmq_socket(drv->zmq_context, type); if (!s) { zmqdrv_error_code(drv, zmq_errno()); return; } int sig_fd; size_t sig_size = sizeof(sig_fd); zmq_getsockopt(s, ZMQ_FD, &sig_fd, &sig_size); if (sig_fd < 0) { zmqdrv_error(drv, "Invalid signaler"); return; } // Register a new socket handle in order to avoid // passing actual address of socket to Erlang. This // way it's more safe and also portable between 32 and // 64 bit OS's. uint32_t n = ++drv->zmq_socket_count; zmq_sock_info* zsi = new zmq_sock_info(s, n, driver_caller(drv->port), sig_fd); if (!zsi) { driver_failure_posix(drv->port, ENOMEM); return; } drv->add_socket(zsi); zmqdrv_fprintf("socket %p [idx=%d] owner=%ld\r\n", s, n, zsi->owner); ErlDrvTermData spec[] = {ERL_DRV_ATOM, am_zok, ERL_DRV_UINT, n, ERL_DRV_TUPLE, 2}; driver_send_term(drv->port, zsi->owner, spec, sizeof(spec)/sizeof(spec[0])); }
static void zmqdrv_getsockopt(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; uint32_t idx = ntohl(*(uint32_t*)(bytes+1)); void* s = drv->get_zmq_socket(idx); zmq_sock_info* si = drv->get_socket_info(idx); uint32_t opt = ntohl (*(uint32_t*)(bytes+sizeof(idx)+1)); union { uint8_t a[255]; uint64_t ui64; int64_t i64; int i; uint32_t ui; } val; size_t vallen; if (idx > drv->zmq_socket_count || !s || !si) { zmqdrv_error_code(drv, ENODEV); return; } zmqdrv_fprintf("setsockopt %p (setting %d options)\r\n", si->socket, (int)n); switch (opt) { case ZMQ_AFFINITY: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_BACKLOG: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_EVENTS: vallen = sizeof(uint32_t); if (zmq_getsockopt(s, opt, &val.ui, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui); break; case ZMQ_FD: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_HWM: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_IDENTITY: vallen = sizeof(val); if (zmq_getsockopt(s, opt, val.a, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_binary(drv, driver_caller(drv->port), val.a, vallen); break; case ZMQ_LINGER: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i); break; case ZMQ_MCAST_LOOP: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64); break; case ZMQ_RATE: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_RCVBUF: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_RCVMORE: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64); break; case ZMQ_RECONNECT_IVL: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_RECOVERY_IVL: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_RECOVERY_IVL_MSEC: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_SNDBUF: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_SWAP: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_TYPE: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_ACTIVE: zmqdrv_ok_atom(drv, driver_caller(drv->port), (si->active_mode == 1 ? am_true : (si->active_mode == 2 ? am_parts : am_false))); break; default: zmqdrv_error(drv, "Option not implemented!"); return; } }