Exemple #1
0
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);
}
Exemple #2
0
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);
    }
}
Exemple #3
0
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;
}
Exemple #4
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");
}
Exemple #5
0
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");
}
Exemple #6
0
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");
}
Exemple #7
0
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;
    }
}
Exemple #9
0
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);
    }
}
Exemple #10
0
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");
}
Exemple #11
0
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;
}
Exemple #13
0
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);
}
Exemple #14
0
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");
}
Exemple #15
0
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);
}
Exemple #16
0
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");
    }
}
Exemple #17
0
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;
}
Exemple #18
0
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;
}
Exemple #19
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");
}
Exemple #21
0
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);
}
Exemple #22
0
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;
    }
}