static void av_decoder_schedule_decode(ErlDrvData drv_data, ErlIOVec *ev) { H264Decoder* d = (H264Decoder*)drv_data; // av_log(d->dec,AV_LOG_WARNING,"\nVSIZE:: %i\n"); ErlDrvBinary *h264 = NULL; int i; for(i = 0; i < ev->vsize; i++) { if(h264 && ev->binv[i]) { driver_failure_atom(d->port, "invalid_output_vector"); return; } if(ev->binv[i]) h264 = ev->binv[i]; } if(!h264) { driver_failure_atom(d->port, "invalid_output_vector"); return; } H264Frame *frame = driver_alloc(sizeof(H264Frame)); bzero(frame, sizeof(H264Frame)); frame->h264 = h264; // av_log(NULL,AV_LOG_INFO,"Size:: %i ",h264->orig_size); frame->decoder = d; driver_binary_inc_refc(h264); // I must change driver_free for other, more clever clearer, because yuv field must be also freed. driver_async(d->port, &d->key, av_async_decode, frame, driver_free); }
static void fail_term(ErlDrvTermData* msg, int len, int line) { int status = erl_drv_output_term(driver_mk_port(erlang_port), msg, len); if (status == 1) { char buf[1024]; sprintf(buf, "%s:%d: unexpected success", __FILE__, line); driver_failure_atom(erlang_port, buf); } else if (status == 0) { char buf[1024]; sprintf(buf, "%s:%d: unexpected port error", __FILE__, line); driver_failure_atom(erlang_port, buf); } }
static int av_decoder_drv_command(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { H264Decoder* d = (H264Decoder*) handle; switch(command) { case CMD_INIT: { d->dec = new_software_decoder((uint8_t *)buf, len); if(!d->dec) { driver_failure_atom(d->port, "cant_open_decoder"); return 0; } memcpy(*rbuf, "ok", 2); return 2; } case CMD_INFO: { uint32_t *out = (uint32_t *)*rbuf; out[0] = d->dec ? htonl(d->dec->width) : 0; out[1] = d->dec ? htonl(d->dec->height) : 0; out[2] = htonl(d->total_time); return 3*4; } break; default: return 0; } return 0; }
static void crop(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; int index = 0; long width, height; int srcW, srcH, srcX, srcY, destX, destY, playX, playY; gdImagePtr destination = NULL; ei_decode_version(buff, &index, NULL); ei_decode_tuple_header(buff, &index, NULL); ei_decode_long(buff, &index, &width); ei_decode_long(buff, &index, &height); if (NULL == gd->image) { driver_failure_atom(gd->port, "null_image"); return; } srcW = gdImageSX(gd->image); srcH = gdImageSY(gd->image); destination = gdImageCreateTrueColor(width, height); if (NULL == destination) { driver_failure_posix(gd->port, ENOMEM); return; } gdImageFilledRectangle(destination, 0, 0, width, height, gdImageColorAllocate(destination, 255, 255, 255)); destX = (width - srcW) / 2; destY = (height - srcH) / 2; gdImageCopy(destination, gd->image, destX, destY, 0, 0, srcW, srcH); gdImageDestroy(gd->image); gd->image = destination; send_atom(gd->port, "ok"); }
static void resize(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; int index = 0; unsigned long width, height, srcW, srcH; gdImagePtr destination = NULL; ei_decode_version(buff, &index, NULL); ei_decode_tuple_header(buff, &index, NULL); ei_decode_ulong(buff, &index, &width); ei_decode_ulong(buff, &index, &height); if (NULL == gd->image) { driver_failure_atom(gd->port, "null_image"); return; } srcW = gdImageSX(gd->image); srcH = gdImageSY(gd->image); destination = gdImageCreateTrueColor(width, height); if (NULL == destination) { driver_failure_posix(gd->port, ENOMEM); return; } gdImageCopyResampled(destination, gd->image, 0, 0, 0, 0, width, height, srcW, srcH); gdImageDestroy(gd->image); gd->image = destination; send_atom(gd->port, "ok"); }
static void failure_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { FailureDrvData *data_p = (FailureDrvData *) drv_data; void *void_ptr; ErlDrvPort port = void_ptr = data_p; driver_failure_atom(port, "driver_failed"); }
static void kill_ports_driver_unloaded(DE_Handle *dh) { int ix, max = erts_ptab_max(&erts_port); for (ix = 0; ix < max; ix++) { erts_aint32_t state; Port* prt = erts_pix2port(ix); if (!prt) continue; ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER; state = erts_atomic32_read_nob(&prt->state); if (state & FREE_PORT_FLAGS) continue; erts_port_lock(prt); state = erts_atomic32_read_nob(&prt->state); if (!(state & ERTS_PORT_SFLGS_DEAD) && prt->drv_ptr->handle == dh) driver_failure_atom(ERTS_Port2ErlDrvPort(prt), "driver_unloaded"); erts_port_release(prt); } }
static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data; int res; if (ctsd->consume_timeslice) { int res = erl_drv_consume_timeslice(ctsd->port, 50); if (res < 0) { driver_failure_atom(ctsd->port, "erl_drv_consume_timeslice() failed"); return; } } res = erl_drv_output_term(ctsd->tport, ctsd->cmd_msg, sizeof(ctsd->cmd_msg)/sizeof(ErlDrvTermData)); if (res <= 0) { driver_failure_atom(ctsd->port, "erl_drv_output_term() failed"); return; } }
static void sendfile_drv_ready_output(ErlDrvData handle, ErlDrvEvent ev) { Desc* d = (Desc*)handle; ssize_t result; off_t cur_offset; Transfer* xfer; SocketFd* sfd = (SocketFd*)&ev; xfer = (Transfer*)hashtable_search(d->xfer_table, sfd->hashkey); if (xfer == NULL) { /* fatal error, something is very wrong */ driver_failure_atom(d->port, "socket_fd_not_found"); return; } cur_offset = xfer->offset; result = sendfile_call(sfd->socket_fd, xfer->file_fd, &xfer->offset, xfer->count); if (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY)) { if (xfer->offset != cur_offset) { off_t written = xfer->offset - cur_offset; xfer->count -= written; xfer->total += written; } } else { int save_errno = errno; ErlDrvSizeT out_buflen; char buf[36]; Buffer b; b.buffer = buf; memset(buf, 0, sizeof buf); #ifdef ERL_DRV_WRITE driver_select(d->port, ev, ERL_DRV_WRITE, 0); #else driver_select(d->port, ev, DO_WRITE, 0); #endif close(xfer->file_fd); if (result < 0) { out_buflen = set_error_buffer(&b, sfd->socket_fd, save_errno); } else { uint64_t total = xfer->total + result; put_int64(total, &(b.result->count.count)); put_int32(sfd->socket_fd, &(b.result->out_fd)); b.result->success = 1; b.result->errno_string[0] = '\0'; out_buflen = sizeof(*b.result); } xfer->file_fd = -1; xfer->offset = xfer->count = xfer->total = 0; driver_output(d->port, buf, out_buflen); } }
void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { int res; ErlDrvPort port = (ErlDrvPort) drv_data; ErlDrvTermData msg[] = { ERL_DRV_PORT, driver_mk_port(port), ERL_DRV_ATOM, driver_mk_atom("caller"), ERL_DRV_PID, driver_caller(port), ERL_DRV_TUPLE, (ErlDrvTermData) 3 }; res = erl_drv_output_term(driver_mk_port(port), msg, sizeof(msg)/sizeof(ErlDrvTermData)); if (res <= 0) driver_failure_atom(port, "erl_drv_output_term failed"); }
static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { async_blast_data_t *abd = (async_blast_data_t *) drv_data; if (abd->counter == 0) { int i; abd->caller = driver_caller(abd->port); abd->counter = NO_ASYNC_JOBS; for (i = 0; i < NO_ASYNC_JOBS; i++) { if (0 > driver_async(abd->port, NULL, async_invoke, NULL, NULL)) { driver_failure_atom(abd->port, "driver_async_failed"); break; } } } }
static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data; int res; char *res_str; ErlDrvSSizeT res_len; switch (command) { case 'E': ctsd->consume_timeslice = 1; res_str = "enabled"; break; case 'D': ctsd->consume_timeslice = 0; res_str = "disabled"; break; case 'S': #ifdef __WIN32__ Sleep((DWORD) 1000); #else sleep(1); #endif res_str = "sleeped"; break; default: res_str = "what?"; break; } res_len = strlen(res_str); if (res_len > rlen) { char *abuf = driver_alloc(sizeof(char)*res_len); if (!abuf) { driver_failure_atom(ctsd->port, "driver_alloc() failed"); return 0; } *rbuf = abuf; } memcpy((void *) *rbuf, (void *) res_str, res_len); return res_len; }
static void get_blob(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; int index = 0; void *imgData = NULL; int size = 0; ErlDrvBinary * bin; long quality; ei_decode_version(buff, &index, NULL); ei_decode_long(buff, &index, &quality); if (NULL == gd->image) { driver_failure_atom(gd->port, "null_image"); return; } imgData = gd->blob(gd->image, &size, quality); if (NULL == imgData) { driver_failure_posix(gd->port, ENOMEM); return; } bin = driver_alloc_binary(size); if (NULL == bin) { driver_failure_posix(gd->port, ENOMEM); return; } memcpy(bin->orig_bytes, imgData, size); gdFree(imgData); ErlDrvTermData spec[] = { ERL_DRV_PORT, driver_mk_port(gd->port), ERL_DRV_ATOM, driver_mk_atom("ok"), ERL_DRV_BINARY, bin, size, 0, ERL_DRV_TUPLE, 3}; driver_output_term(gd->port, spec, sizeof(spec) / sizeof(ERL_DRV_PORT)); driver_free_binary(bin); }
static void read_image(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; gd->format = buff[0]; char *data = &buff[1]; int size = len; if (gd->image != NULL) { gdImageDestroy(gd->image); gd->image = NULL; } switch (gd->format) { case JPG: gd->read = gdImageCreateFromJpegPtr; gd->blob = gdImageJpegPtr; break; case PNG: gd->read = gdImageCreateFromPngPtr; gd->blob = gdImagePngPtrEx; break; case GIF: gd->read = gdImageCreateFromGifPtr; gd->blob = gdImageGifPtrWrap; break; } gd->image = gd->read(size, data); if (NULL == gd->image) { driver_failure_atom(gd->port, "gd_create_failed"); return; } send_atom(gd->port, "ok"); }
static void get_size(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; unsigned int x; unsigned int y; ei_x_buff b; if (gd->image == NULL) { driver_failure_atom(gd->port, "null_image"); return; } x = gdImageSX(gd->image); y = gdImageSY(gd->image); ei_x_new_with_version(&b); ei_x_encode_tuple_header(&b, 2); ei_x_encode_long(&b, x); ei_x_encode_long(&b, y); driver_output(gd->port, b.buff, b.index); ei_x_free(&b); }
static void output_term(ErlDrvTermData* msg, int len) { if (erl_drv_output_term(driver_mk_port(erlang_port), msg, len) <= 0) { driver_failure_atom(erlang_port, "erl_drv_output_term_failed"); } }
static int control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) { int res; char *str; size_t slen, slen2; ErlDrvPort port = (ErlDrvPort) drv_data; unsigned deadbeef[] = {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}; ErlDrvSysInfo *sip = driver_alloc(ERL_DRV_SYS_INFO_SIZE + sizeof(deadbeef)); char *beyond_end_format = "error: driver_system_info() wrote beyond end " "of the ErlDrvSysInfo struct"; char *buf_overflow_format = "error: Internal buffer overflow"; if (!sip) { driver_failure_atom(port, "enomem"); return 0; } memset((char *) sip, 0xed, ERL_DRV_SYS_INFO_SIZE); memcpy(((char *) sip) + ERL_DRV_SYS_INFO_SIZE, (char *) &deadbeef[0], sizeof(deadbeef)); driver_system_info(sip, ERL_DRV_SYS_INFO_SIZE); slen = sys_info_drv_max_res_len(sip); slen2 = strlen(beyond_end_format) + 1; if (slen2 > slen) slen = slen2; slen2 = strlen(buf_overflow_format) + 1; if (slen2 > slen) slen = slen2; str = driver_alloc(slen); if (!str) { driver_free(sip); driver_failure_atom(port, "enomem"); return 0; } *rbuf = str; /* Check that the emulator didn't write beyond ERL_DRV_SYS_INFO_SIZE */ if (memcmp(((char *) sip) + ERL_DRV_SYS_INFO_SIZE, (char *) &deadbeef[0], sizeof(deadbeef)) != 0) { res = sprintf(str, beyond_end_format); } else { res = sys_info_drv_sprintf_sys_info(sip, str); if (res > slen) res = sprintf(str, buf_overflow_format); } driver_free(sip); return res; }
static int uvc_drv_command(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { Uvc* d = (Uvc*) handle; switch(command) { case CMD_OPEN: { if(len != sizeof(Config)) { driver_failure_atom(d->port, "invalid_config"); return 0; } Config *cfg = (Config *)buf; char device_path[1024]; snprintf(device_path, sizeof(device_path), "/dev/video%d", cfg->device); d->fd = open(device_path, O_RDWR); if(d->fd == -1) { driver_failure_posix(d->port, errno); return 0; } struct v4l2_capability cap; memset(&cap, 0, sizeof cap); int ret; ret = ioctl(d->fd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { driver_failure_posix(d->port, errno); return 0; } if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { driver_failure_atom(d->port, "not_a_capture_device"); return 0; } fprintf(stderr, "Setting size %dx%d\r\n", cfg->width, cfg->height); struct v4l2_format fmt; memset(&fmt, 0, sizeof fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(cfg->width > 640 || cfg->height > 480) { d->pixelformat = V4L2_PIX_FMT_MJPEG; } else { d->pixelformat = V4L2_PIX_FMT_YUYV; } d->width = cfg->width; d->height = cfg->height; fmt.fmt.pix.width = cfg->width; fmt.fmt.pix.height = cfg->height; fmt.fmt.pix.pixelformat = d->pixelformat; fmt.fmt.pix.field = V4L2_FIELD_ANY; ret = ioctl(d->fd, VIDIOC_S_FMT, &fmt); if (ret < 0) { driver_failure_posix(d->port, errno); return 0; } fprintf(stderr, "Setting fps %d\r\n", cfg->fps); struct v4l2_streamparm parm; memset(&parm, 0, sizeof parm); parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ioctl(d->fd, VIDIOC_G_PARM, &parm); if (ret < 0) { driver_failure_posix(d->port, errno); return 0; } parm.parm.capture.timeperframe.numerator = 1; parm.parm.capture.timeperframe.denominator = cfg->fps; ret = ioctl(d->fd, VIDIOC_S_PARM, &parm); if (ret < 0) { driver_failure_posix(d->port, errno); return 0; } fprintf(stderr, "Setting quality 100\r\n"); struct v4l2_jpegcompression jpeg; memset(&jpeg, 0, sizeof jpeg); jpeg.quality = 90; ret = ioctl(d->fd, VIDIOC_S_JPEGCOMP, &jpeg); if (ret < 0) { // driver_failure_posix(d->port, errno); // return 0; fprintf(stderr, "Failed to set quality\r\n"); } if(video_alloc_buffers(d) < 0) { driver_failure_posix(d->port, errno); return 0; } int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = ioctl(d->fd, VIDIOC_STREAMON, &type); if(ret < 0) { driver_failure_posix(d->port, errno); return 0; } fprintf(stderr, "Capture started\r\n"); driver_select(d->port, (ErlDrvEvent)d->fd, DO_READ, 1); memcpy(*rbuf, "ok", 2); return 2; } break; default: return 0; } return 0; }
static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count) { char buf7[1024]; ErlDrvTermData spec[1024]; ErlDrvTermData* msg = spec; ErlDrvBinary* bins[15]; int bin_ix = 0; ErlDrvSInt64 s64[15]; int s64_ix = 0; ErlDrvUInt64 u64[15]; int u64_ix = 0; int i = 0; for (i=0; i<count; i++) switch (buf[i]) { case 0: msg[0] = ERL_DRV_NIL; msg += 1; break; case 1: /* Most term types inside a tuple. */ { double f = 3.1416; msg[0] = ERL_DRV_ATOM; msg[1] = driver_mk_atom("blurf"); msg[2] = ERL_DRV_INT; msg[3] = (ErlDrvTermData) 42; msg[4] = ERL_DRV_NIL; msg[5] = ERL_DRV_INT; msg[6] = (ErlDrvTermData) -42; msg[7] = ERL_DRV_TUPLE; msg[8] = (ErlDrvTermData) 0; msg[9] = ERL_DRV_PORT; msg[10] = driver_mk_port(erlang_port); msg[11] = ERL_DRV_STRING_CONS; msg[12] = (ErlDrvTermData) "abc"; msg[13] = (ErlDrvTermData) 3; msg[14] = ERL_DRV_LIST; msg[15] = (ErlDrvTermData) 3; msg[16] = ERL_DRV_STRING; msg[17] = (ErlDrvTermData) "kalle"; msg[18] = (ErlDrvTermData) 5; msg[19] = ERL_DRV_FLOAT; msg[20] = (ErlDrvTermData) &f; msg[21] = ERL_DRV_PID; msg[22] = driver_connected(erlang_port); msg[23] = ERL_DRV_MAP; msg[24] = (ErlDrvTermData) 0; msg[25] = ERL_DRV_TUPLE; msg[26] = (ErlDrvTermData) 8; msg += 27; } break; case 2: /* Deep stack */ { int i; for (i = 0; i < 400; i += 2) { msg[i] = ERL_DRV_INT; msg[i+1] = (ErlDrvTermData) (i / 2); } msg[i] = ERL_DRV_NIL; msg[i+1] = ERL_DRV_LIST; msg[i+2] = (ErlDrvTermData) 201; msg += i+3; } break; case 3: /* Binaries */ { ErlDrvBinary* bin; int i; bin = bins[bin_ix++] = driver_alloc_binary(256); for (i = 0; i < 256; i++) { bin->orig_bytes[i] = i; } msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 256-23-17; msg[7] = (ErlDrvTermData) 23; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; msg += 10; } break; case 4: /* Pids */ msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); msg[2] = ERL_DRV_PID; msg[3] = driver_caller(erlang_port); msg[4] = ERL_DRV_TUPLE; msg[5] = (ErlDrvTermData) 2; msg += 6; break; case 5: msg += make_ext_term_list(msg, 0); break; case 6: msg[0] = ERL_DRV_INT; msg[1] = ~((ErlDrvTermData) 0); msg[2] = ERL_DRV_UINT; msg[3] = ~((ErlDrvTermData) 0); msg[4] = ERL_DRV_TUPLE; msg[5] = (ErlDrvTermData) 2; msg += 6; break; case 7: { int len = 0; memset(buf7, 17, sizeof(buf7)); /* empty heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */ msg[len++] = (ErlDrvTermData) 0; /* empty heap binary again */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; /* ptr is ok if size == 0 */ msg[len++] = (ErlDrvTermData) 0; /* heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; msg[len++] = (ErlDrvTermData) 17; /* off heap binary */ msg[len++] = ERL_DRV_BUF2BINARY; msg[len++] = (ErlDrvTermData) buf7; msg[len++] = (ErlDrvTermData) sizeof(buf7); msg[len++] = ERL_DRV_TUPLE; msg[len++] = (ErlDrvTermData) 4; msg += len; break; } case 8: msg[0] = ERL_DRV_NIL; msg += 1; break; case 9: msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom(""); msg += 2; break; case 10: msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); msg += 2; break; case 11: msg[0] = ERL_DRV_INT; msg[1] = (ErlDrvTermData) -4711; msg += 2; break; case 12: msg[0] = ERL_DRV_UINT; msg[1] = (ErlDrvTermData) 4711; msg += 2; break; case 13: msg[0] = ERL_DRV_PORT; msg[1] = driver_mk_port(erlang_port); msg += 2; break; case 14: { ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(0); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) 0; msg[3] = (ErlDrvTermData) 0; msg += 4; break; } case 15: { static const char buf[] = "hejsan"; ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(sizeof(buf)-1); if (dbin) memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0); msg[3] = (ErlDrvTermData) 0; msg += 4; break; } case 16: msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) NULL; msg[2] = (ErlDrvTermData) 0; msg += 3; break; case 17: { static const char buf[] = ""; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 18: { static const char buf[] = "hoppsan"; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 19: msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) 0; msg += 3; break; case 20: { static const char buf[] = ""; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 21: { static const char buf[] = "hippsan"; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg += 3; break; } case 22: msg[0] = ERL_DRV_TUPLE; msg[1] = (ErlDrvTermData) 0; msg += 2; break; case 23: msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_LIST; msg[2] = (ErlDrvTermData) 1; msg += 3; break; case 24: msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); msg += 2; break; case 25: msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_STRING_CONS; msg[2] = (ErlDrvTermData) ""; msg[3] = (ErlDrvTermData) 0; msg += 4; break; case 26: { static double my_float = 0.0; msg[0] = ERL_DRV_FLOAT; msg[1] = (ErlDrvTermData) &my_float; msg += 2; break; } case 27: { static char buf[] = {131, 106}; /* [] */ msg[0] = ERL_DRV_EXT2TERM; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf); msg += 3; break; } case 28: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = ~((ErlDrvUInt64) 0); msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 29: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = ((ErlDrvUInt64) 4711) << 32; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 30: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = 4711; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 31: { ErlDrvUInt64* x = &u64[u64_ix++]; *x = 0; msg[0] = ERL_DRV_UINT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 32: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((((ErlDrvUInt64) 0x7fffffff) << 32) | ((ErlDrvUInt64) 0xffffffff)); msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 33: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32); msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 34: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = 4711; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 35: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = 0; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 36: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = -1; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 37: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = -4711; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 38: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 39: { ErlDrvSInt64* x = &s64[s64_ix++]; *x = ((ErlDrvSInt64) 1) << 63; msg[0] = ERL_DRV_INT64; msg[1] = (ErlDrvTermData) x; msg += 2; break; } case 40: { msg[0] = ERL_DRV_MAP; msg[1] = (ErlDrvTermData) 0; msg += 2; break; } case 41: /* Most term types inside a map */ case 42: { double f = 3.1416; if (buf[i] == 41) { *msg++ = ERL_DRV_ATOM; *msg++ = driver_mk_atom("blurf"); } *msg++ = ERL_DRV_INT; *msg++ = (ErlDrvTermData)42; *msg++ = ERL_DRV_NIL; *msg++ = ERL_DRV_INT; *msg++ = (ErlDrvTermData)-42; *msg++ = ERL_DRV_TUPLE; *msg++ = (ErlDrvTermData)0; *msg++ = ERL_DRV_PORT; *msg++ = driver_mk_port(erlang_port); *msg++ = ERL_DRV_STRING_CONS; *msg++ = (ErlDrvTermData)"abc"; *msg++ = (ErlDrvTermData)3; *msg++ = ERL_DRV_LIST; *msg++ = (ErlDrvTermData)3; *msg++ = ERL_DRV_STRING; *msg++ = (ErlDrvTermData)"kalle"; *msg++ = (ErlDrvTermData)5; *msg++ = ERL_DRV_FLOAT; *msg++ = (ErlDrvTermData)&f; *msg++ = ERL_DRV_PID; *msg++ = driver_connected(erlang_port); *msg++ = ERL_DRV_MAP; *msg++ = (ErlDrvTermData)0; if (buf[i] == 42) { *msg++ = ERL_DRV_ATOM; *msg++ = driver_mk_atom("blurf"); } *msg++ = ERL_DRV_MAP; *msg++ = (ErlDrvTermData)4; break; } case 127: /* Error cases */ { long refc; ErlDrvBinary* bin = bins[bin_ix++] = driver_alloc_binary(256); FAIL_TERM(msg, 0); msg[0] = ERL_DRV_LIST; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 2); /* Not an atom */ msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_connected(erlang_port); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_ATOM; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Not a pid */ msg[0] = ERL_DRV_PID; msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PID; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Not a port */ msg[0] = ERL_DRV_PORT; msg[1] = (ErlDrvTermData) driver_mk_atom("blurf"); FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PORT; msg[1] = driver_term_nil; FAIL_TERM(msg, 2); /* Missing parameter on stack */ msg[0] = ERL_DRV_STRING_CONS; msg[1] = (ErlDrvTermData) "abc"; msg[2] = (ErlDrvTermData) 3; FAIL_TERM(msg, 3); /* * The first binary reference is correct, the second is incorrect. * There should not be any "binary leak". */ msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 257; msg[7] = (ErlDrvTermData) 0; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; FAIL_TERM(msg, 10); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) bin; msg[2] = (ErlDrvTermData) 256; msg[3] = (ErlDrvTermData) 0; msg[4] = ERL_DRV_BINARY; msg[5] = (ErlDrvTermData) bin; msg[6] = (ErlDrvTermData) 256; msg[7] = (ErlDrvTermData) 50; msg[8] = ERL_DRV_TUPLE; msg[9] = (ErlDrvTermData) 2; FAIL_TERM(msg, 10); /* * We have succefully built two binaries. We expect the ref count * to be 1 (SMP) or 3 (non-SMP). */ refc = driver_binary_get_refc(bin); if (refc > 3) { char sbuf[128]; sprintf(sbuf, "bad_refc:%ld", refc); driver_failure_atom(erlang_port, sbuf); } driver_free_binary(bin); FAIL_TERM(msg, make_ext_term_list(msg, 1)); /* * Check that we fail for missing args. * * We setup valid terms but pass a too small size. We * want valid terms since we want to verify that the * failure really is due to the small size. */ msg[0] = ERL_DRV_ATOM; msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom"); FAIL_TERM(msg, 1); msg[0] = ERL_DRV_INT; msg[1] = (ErlDrvTermData) -4711; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_UINT; msg[1] = (ErlDrvTermData) 4711; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_PORT; msg[1] = driver_mk_port(erlang_port); FAIL_TERM(msg, 1); { char buf[] = "hejsan"; ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1); if (!dbin) driver_failure_posix(erlang_port, ENOMEM); else { memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1); msg[0] = ERL_DRV_BINARY; msg[1] = (ErlDrvTermData) dbin; msg[2] = (ErlDrvTermData) sizeof(buf)-1; msg[3] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); FAIL_TERM(msg, 3); driver_free_binary(dbin); } } { char buf[] = "hoppsan"; msg[0] = ERL_DRV_BUF2BINARY; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } { char buf[] = "hippsan"; msg[0] = ERL_DRV_STRING; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf)-1; FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } msg[0] = ERL_DRV_TUPLE; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_LIST; msg[2] = (ErlDrvTermData) 1; FAIL_TERM(msg, 2); msg[0] = ERL_DRV_PID; msg[1] = driver_connected(erlang_port); FAIL_TERM(msg, 1); msg[0] = ERL_DRV_NIL; msg[1] = ERL_DRV_STRING_CONS; msg[2] = (ErlDrvTermData) ""; msg[3] = (ErlDrvTermData) 0; FAIL_TERM(msg, 2); FAIL_TERM(msg, 3); { double my_float = 0.0; msg[0] = ERL_DRV_FLOAT; msg[1] = (ErlDrvTermData) &my_float; FAIL_TERM(msg, 1); } { char buf[] = {131, 106}; /* [] */ msg[0] = ERL_DRV_EXT2TERM; msg[1] = (ErlDrvTermData) buf; msg[2] = (ErlDrvTermData) sizeof(buf); FAIL_TERM(msg, 1); FAIL_TERM(msg, 2); } msg[0] = ERL_DRV_MAP; msg[1] = (ErlDrvTermData) 0; FAIL_TERM(msg, 1); /* map with duplicate key */ msg[0] = ERL_DRV_ATOM; msg[1] = driver_mk_atom("key"); msg[2] = ERL_DRV_NIL; msg[3] = ERL_DRV_ATOM; msg[4] = driver_mk_atom("key"); msg[5] = ERL_DRV_INT; msg[6] = (ErlDrvTermData) -4711; msg[7] = ERL_DRV_MAP; msg[8] = 2; FAIL_TERM(msg, 9); /* Signal end of test case */ msg[0] = ERL_DRV_NIL; erl_drv_output_term(driver_mk_port(erlang_port), msg, 1); return; } break; default: driver_failure_atom(erlang_port, "bad_request"); break; } if (count > 1) { *msg++ = ERL_DRV_NIL; *msg++ = ERL_DRV_LIST; *msg++ = count + 1; } output_term(spec, msg-spec); if ((bin_ix|s64_ix|u64_ix) > 15) abort(); while (bin_ix) { driver_free_binary(bins[--bin_ix]); } }
static void io_ready_exit_ready_output(ErlDrvData drv_data, ErlDrvEvent event) { IOReadyExitDrvData *oeddp = (IOReadyExitDrvData *) drv_data; driver_failure_atom(oeddp->port, "ready_output_driver_failure"); }
static void enm_outputv(ErlDrvData drv_data, ErlIOVec *ev) { EnmData* d = (EnmData*)drv_data; ErlIOVec qev; ErlDrvSizeT qtotal; struct nn_msghdr msghdr; int i, rc = -1, err; if (d->fd == -1 || d->protocol == NN_PULL || d->protocol == NN_SUB) return; qtotal = driver_peekqv(d->port, &qev); if (qtotal > 0) { memset(&msghdr, 0, sizeof msghdr); msghdr.msg_iov = (struct nn_iovec*)qev.iov; msghdr.msg_iovlen = qev.vsize; msghdr.msg_control = 0; err = 0; do { rc = enm_do_send(d, &msghdr, &err); if (rc < 0) { if (err == EAGAIN) { d->b.writable = 0; break; } else if (err != EINTR) { char errstr[32]; switch (enm_errno_str(err, errstr)) { case ENM_NANOMSG_ERROR: driver_failure_atom(d->port, errstr); break; case ENM_POSIX_ERROR: driver_failure_posix(d->port, err); break; case ENM_UNKNOWN_ERROR: driver_failure(d->port, err); break; } return; } } } while (err == EINTR); } /* * Do nothing if the message has no data */ if (ev->size == 0 || ev->vsize == 0 || (ev->vsize == 1 && *ev->binv == 0 && ev->iov->iov_len == 0)) return; if (d->b.writable) { memset(&msghdr, 0, sizeof msghdr); msghdr.msg_iov = (struct nn_iovec*)ev->iov; msghdr.msg_iovlen = ev->vsize; msghdr.msg_control = 0; err = 0; do { rc = enm_do_send(d, &msghdr, &err); if (rc < 0) { if (err == EAGAIN) { d->b.writable = 0; break; } else if (err != EINTR) { char errstr[32]; switch (enm_errno_str(err, errstr)) { case ENM_NANOMSG_ERROR: driver_failure_atom(d->port, errstr); break; case ENM_POSIX_ERROR: driver_failure_posix(d->port, err); break; case ENM_UNKNOWN_ERROR: driver_failure(d->port, err); break; } return; } } } while (err == EINTR); } if (rc < 0 && !d->b.writable) { rc = 0; d->b.busy = 1; set_busy_port(d->port, d->b.busy); for (i = 0; i < ev->vsize; i++) { ErlDrvBinary* bin = 0; if (ev->binv[i] != 0) { bin = ev->binv[i]; driver_binary_inc_refc(bin); } else if (ev->iov[i].iov_len > 0) { SysIOVec* vec = &ev->iov[i]; bin = driver_alloc_binary(vec->iov_len); memcpy(bin->orig_bytes, vec->iov_base, vec->iov_len); } if (bin != 0) driver_enq_bin(d->port, bin, 0, bin->orig_size); } if (!d->b.write_poll) enm_write_select(d, 1); } if (rc > 0 && d->protocol == NN_SURVEYOR && d->b.active != ENM_FALSE) enm_read_select(d, 1); }
static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { EchoDrvData* data_p = (EchoDrvData *) drv_data; ErlDrvPort port = data_p->erlang_port; switch (buf[0]) { case ECHO_DRV_OUTPUT: { driver_output(port, buf+1, len-1); break; } case ECHO_DRV_OUTPUT2: { driver_output2(port, "a", 1, buf+1, len-1); break; } case ECHO_DRV_OUTPUT_BINARY: { ErlDrvBinary *bin = driver_alloc_binary(len-1); memcpy(&bin->orig_bytes, buf+1, len-1); driver_output_binary(port, "a", 1, bin, 1, len - 2); driver_free_binary(bin); break; } case ECHO_DRV_OUTPUTV: { ErlIOVec iov; ErlDrvSizeT sz; driver_enq(port, buf + 1, len - 1); sz = driver_peekqv(port, &iov); driver_outputv(port, "a", 1, &iov, 0); driver_deq(port, sz); break; } case ECHO_DRV_SET_TIMER: { driver_set_timer(port, 10); break; } case ECHO_DRV_FAILURE_EOF: { driver_failure_eof(port); break; } case ECHO_DRV_FAILURE_ATOM: { driver_failure_atom(port, buf+1); break; } case ECHO_DRV_FAILURE_POSIX: { driver_failure_posix(port, EAGAIN); break; } case ECHO_DRV_FAILURE: { driver_failure(port, buf[1]); break; } case ECHO_DRV_OUTPUT_TERM: case ECHO_DRV_DRIVER_OUTPUT_TERM: case ECHO_DRV_SEND_TERM: case ECHO_DRV_DRIVER_SEND_TERM: { ErlDrvTermData term[] = { ERL_DRV_ATOM, driver_mk_atom("echo"), ERL_DRV_PORT, driver_mk_port(port), ERL_DRV_BUF2BINARY, (ErlDrvTermData)(buf+1), (ErlDrvTermData)(len - 1), ERL_DRV_TUPLE, 3}; switch (buf[0]) { case ECHO_DRV_OUTPUT_TERM: erl_drv_output_term(driver_mk_port(port), term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_DRIVER_OUTPUT_TERM: driver_output_term(port, term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_SEND_TERM: driver_send_term(port, data_p->caller, term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_DRIVER_SEND_TERM: erl_drv_send_term(driver_mk_port(port), data_p->caller, term, sizeof(term) / sizeof(ErlDrvTermData)); break; } break; } case ECHO_DRV_SAVE_CALLER: data_p->caller = driver_caller(port); break; default: break; } }