static void zmqdrv_send(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; uint32_t idx = ntohl(*(uint32_t*)(bytes+1)); zmq_sock_info* si = drv->get_socket_info(idx); uint32_t flags = ntohl(*(uint32_t*)(bytes+5)); void* data = (void *)(bytes + 9); size_t size = bin->orig_size - 9; if (idx > drv->zmq_socket_count || !si) { zmqdrv_error_code(drv, ENODEV); return; } #ifdef ZMQDRV_DEBUG uint32_t events; size_t events_size = sizeof(events); zmq_getsockopt(si->socket, ZMQ_EVENTS, &events, &events_size); zmqdrv_fprintf("sending %p [idx=%d] %lu bytes (events=%d)\r\n", si->socket, idx, size, events); #endif if (si->out_caller != 0) { // There's still an unwritten message pending zmqdrv_error_code(drv, EBUSY); return; } // Increment the reference count on binary so that zmq can // take ownership of it. driver_binary_inc_refc(bin); if (zmq_msg_init_data(&si->out_msg, data, size, &zmq_free_binary, bin)) { zmqdrv_error_code(drv, zmq_errno()); driver_binary_dec_refc(bin); return; } if (zmq_send(si->socket, &si->out_msg, flags | ZMQ_NOBLOCK) == 0) { zmqdrv_ok(drv); zmqdrv_ready_input((ErlDrvData)drv, (ErlDrvEvent)si->fd); } else { int e = zmq_errno(); if (e == EAGAIN) { // No msg returned to caller - make him wait until async // send succeeds si->out_caller = driver_caller(drv->port); return; } zmqdrv_error_code(drv, e); } zmq_msg_close(&si->out_msg); }
void run_js(void *jsargs) { js_call *call_data = (js_call *) jsargs; spidermonkey_drv_t *dd = call_data->driver_data; ErlDrvBinary *args = call_data->args; driver_free(call_data); char *data = args->orig_bytes; char *command = read_command(&data); char *call_id = read_string(&data); char *result = NULL; if (strncmp(command, "ej", 2) == 0) { char *filename = read_string(&data); char *code = read_string(&data); result = sm_eval(dd->vm, filename, code, 1); if (strstr(result, "{\"error\"") != NULL) { send_error_string_response(dd, call_id, result); } else { send_string_response(dd, call_id, result); } driver_free(filename); driver_free(code); driver_free(result); } else if (strncmp(command, "dj", 2) == 0) { char *filename = read_string(&data); char *code = read_string(&data); result = sm_eval(dd->vm, filename, code, 0); if (result == NULL) { send_ok_response(dd, call_id); } else { send_error_string_response(dd, call_id, result); driver_free(result); } driver_free(filename); driver_free(code); } else if (strncmp(command, "sd", 2) == 0) { dd->shutdown = 1; send_ok_response(dd, call_id); } else { unknown_command(dd, call_id); } driver_free(command); driver_free(call_id); driver_binary_dec_refc(args); }
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ static void wrap_zmq_send(zmq_drv_t *drv, const uint8_t* bytes, size_t size, ErlDrvBinary* bin) { int flags = *bytes; void* data = (void *)(bytes+sizeof(uint8_t)); size_t data_size = size - sizeof(uint8_t); assert(sizeof(uint8_t) <= size); ErlDrvTermData caller = driver_caller(drv->port); if (drv->terminating) { reply_error(drv->port, caller, ETERM); return; } zmq_sock_info* si = drv->get_socket_info(caller); if (!si) { reply_error(drv->port, caller, ENODEV); return; } assert(0 == si->out_caller); zmqdrv_fprintf("send %p (flags: %d bytes: %u)\r\n", si->socket, flags, data_size); // Increment the reference count on binary so that zmq can take ownership of it. driver_binary_inc_refc(bin); if (zmq_msg_init_data(&si->out_msg, data, data_size, &zmqcb_free_binary, bin)) { reply_error(drv->port, caller, zmq_errno()); driver_binary_dec_refc(bin); return; } if (0 == zmq_send(si->socket, &si->out_msg, flags|ZMQ_NOBLOCK)) { reply_ok(drv->port, caller); zmq_msg_close(&si->out_msg); } else if (ZMQ_NOBLOCK != (ZMQ_NOBLOCK & flags) && EAGAIN == zmq_errno()) { // Caller requested blocking send // Can't send right now. Make the caller wait by not returning result zmqdrv_fprintf("send %p blocking\r\n", si->socket); si->out_flags = flags; si->out_caller = caller; if (!si->busy) { driver_select(drv->port, si->fd, ERL_DRV_READ, 1); si->busy = true; } } else { reply_error(drv->port, caller, zmq_errno()); zmq_msg_close(&si->out_msg); } }