Beispiel #1
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_socket(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    int type = *bytes;

    assert(sizeof(uint8_t) == size);

    zmqdrv_fprintf("socket (type: %d)\r\n", type);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    assert(NULL == drv->get_socket_info(caller));

    // Runtime validation as well in case zmq_drv.erl is used directly rather
    // than through zmq_socket.erl gen_server.
    if (NULL != drv->get_socket_info(caller))
    {
        reply_error(drv->port, caller, EBUSY);
        return;
    }

    void* s = zmq_socket(drv->zmq_context, type);

    if (!s)
    {
        reply_error(drv->port, caller, zmq_errno());
        return;
    }

    //TODO: Support Windows 'SOCKET' type?
    int fd; size_t fd_size = sizeof(fd);
    if (0 != zmq_getsockopt(s, ZMQ_FD, &fd, &fd_size))
    {
        reply_error(drv->port, caller, zmq_errno());
        zmq_close(s);
        return;
    }

    zmq_sock_info* si = new zmq_sock_info(s, (ErlDrvEvent)fd);

    if (!si)
    {
        driver_failure_posix(drv->port, ENOMEM);
        return;
    }

    driver_monitor_process(drv->port, caller, &si->monitor);
    drv->zmq_pid_socket[caller] = si;
    drv->zmq_fd_socket[si->fd] = si;

    zmqdrv_fprintf("socket %p owner %lu\r\n", si->socket, caller);

    reply_ok(drv->port, caller);
}
Beispiel #2
0
static void
enm_add_waiter(EnmData* d, erlang_ref* ref)
{
    EnmRecv *rcv, *cur;

    rcv = driver_alloc(sizeof(EnmRecv));
    if (rcv == 0) {
        driver_failure_posix(d->port, ENOMEM);
        return;
    }
    memcpy(&rcv->ref, ref, sizeof *ref);
    rcv->rcvr = driver_caller(d->port);
    rcv->next = 0;
    driver_monitor_process(d->port, rcv->rcvr, &rcv->monitor);
    cur = d->waiting_recvs;
    if (cur == 0)
        d->waiting_recvs = rcv;
    else {
        while (cur) {
            if (cur->next != 0)
                cur = cur->next;
            else {
                cur->next = rcv;
                break;
            }
        }
    }
}
Beispiel #3
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");
}
Beispiel #4
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");
}
Beispiel #5
0
/*
** Timeout from driver_set_timer.
*/
static void trace_file_timeout(ErlDrvData handle) {
    TraceFileData *data = (TraceFileData *) handle;
    if (data->wrap) {
        if (wrap_file(data) < 0) {
            driver_failure_posix(data->port, errno); /* XXX */
            return;
        } else {
            driver_set_timer(data->port, data->wrap->time);
        }
    }
}
Beispiel #6
0
static void trace_file_output(ErlDrvData handle, char *buff,
			      ErlDrvSizeT bufflen)
{
    int heavy = 0;
    TraceFileData *data = (TraceFileData *) handle;
    unsigned char b[5] = "";
    put_be((unsigned) bufflen, b + 1);
    switch (my_write(data, (unsigned char *) b, sizeof(b))) {
    case 1:
	heavy = !0;
    case 0:
	switch (my_write(data, (unsigned char *) buff, bufflen)) {
	case 1:
	    heavy = !0;
	case 0:
	    break;
	case -1:
	    driver_failure_posix(data->port, errno); /* XXX */
	    return;
	}
	break;
    case -1:
	driver_failure_posix(data->port, errno); /* XXX */
	return;
    }
    if (data->wrap) {
	TraceFileWrapData *wrap = data->wrap;
	/* Size limited wrapping log files */
	wrap->len += sizeof(b) + bufflen;
	if (wrap->time == 0 && wrap->len >= wrap->size) {
	    if (wrap_file(data) < 0) {
		driver_failure_posix(data->port, errno); /* XXX */
		return;
	    }
	    heavy = !0;
	}
    }
    if (heavy) {
	set_port_control_flags(data->port, PORT_CONTROL_FLAG_HEAVY);
    }
}
Beispiel #7
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);
}
Beispiel #8
0
ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
		     ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
    switch (command) {
    case 'B': /* busy */
	set_busy_port((ErlDrvPort) drv_data, 1);
	break;
    case 'N': /* not busy */
	set_busy_port((ErlDrvPort) drv_data, 0);
	break;
    default:
	driver_failure_posix((ErlDrvPort) drv_data, EINVAL);
	break;
    }
    return 0;
}
Beispiel #9
0
/*
** Control message from erlang, we handle $f, which is flush.
*/
static int trace_file_control(ErlDrvData handle, unsigned int command,
                              char* buff, int count,
                              char** res, int res_size)
{
    if (command == 'f') {
        TraceFileData *data = (TraceFileData *) handle;
        if (my_flush(data) < 0) {
            driver_failure_posix(data->port, errno); /* XXX */
        }
        if (res_size < 1) {
            *res = my_alloc(1);
        }
        **res = '\0';
        return 1;
    }
    return -1;
}
Beispiel #10
0
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]));
}
Beispiel #11
0
static void uvc_drv_input(ErlDrvData handle, ErlDrvEvent io_event)
{
  Uvc* d = (Uvc*) handle;
  struct v4l2_buffer buf;
	
  memset(&buf, 0, sizeof buf);
	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;
	int ret = ioctl(d->fd, VIDIOC_DQBUF, &buf);
	if(ret < 0) {
    driver_failure_posix(d->port, errno);
    return;
	}
	
  ErlDrvBinary* bin;
  size_t len;
  if(d->pixelformat == V4L2_PIX_FMT_YUYV) {
    len = d->width*d->height*3/2;
    bin = driver_alloc_binary(len);
    
    if(!d->scale_ctx) d->scale_ctx = sws_getContext(
      d->width, d->height, PIX_FMT_YUYV422, 
      d->width, d->height, PIX_FMT_YUV420P, 
      SWS_FAST_BILINEAR, NULL, NULL, NULL
    );

    int linesize[4] = {d->width*2, 0, 0, 0};
    uint8_t *src[4] = {(uint8_t *)d->buffers[buf.index].mem, 0, 0, 0};

    int stride_size = d->width*d->height;
    uint8_t *plane[4] = {(uint8_t *)bin->orig_bytes, (uint8_t *)bin->orig_bytes+stride_size, (uint8_t *)bin->orig_bytes+stride_size+stride_size/4, NULL};
    int stride[4] = {d->width, d->width/2, d->width/2, 0};
    
    sws_scale(d->scale_ctx, (const uint8_t * const*)src, linesize, 0, d->height, plane, stride);
  } else {
    bin = driver_alloc_binary(buf.bytesused + 1024);
    len = add_huffman((uint8_t *)bin->orig_bytes, (uint8_t *)d->buffers[buf.index].mem, buf.bytesused);
  }
  
  
  ErlDrvUInt64 pts = buf.timestamp.tv_sec * 1000 + buf.timestamp.tv_usec / 1000;
  
  ErlDrvTermData reply[] = {
    ERL_DRV_ATOM, driver_mk_atom("uvc"),
    ERL_DRV_PORT, driver_mk_port(d->port),
    ERL_DRV_ATOM, driver_mk_atom(d->pixelformat == V4L2_PIX_FMT_YUYV ? "yuv" : "jpeg"),
    ERL_DRV_UINT64, &pts,
    ERL_DRV_BINARY, (ErlDrvTermData)bin, (ErlDrvTermData)len, 0,
    ERL_DRV_TUPLE, 5
  };


  // fprintf(stderr, "Event in uvc: %lu %u %u\r\n", len, (unsigned)buf.timestamp.tv_sec, (unsigned)buf.timestamp.tv_usec);
  driver_output_term(d->port, reply, sizeof(reply) / sizeof(reply[0]));
  driver_free_binary(bin);
  
  ret = video_queue_buffer(d, buf.index);
  if(ret < 0) {
      driver_failure_posix(d->port, errno);
      return;
  }
}
Beispiel #12
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;
}
Beispiel #13
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);
}
Beispiel #14
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;
    }
}
Beispiel #15
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]);
    }
}
Beispiel #16
0
static void tun_output(ErlDrvData data, char* buf, int len)
{
    struct tun_state *state = (struct tun_state *)data;
    if (write(state->fd, buf, len) < 0)
	driver_failure_posix(state->port, errno);
}