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; }
static int control_control(ErlDrvData port, unsigned command, char* buf, int count, char** res, int res_size) { switch (command) { case 'e': if (count > res_size) { *res = (char *) driver_alloc(count); } memcpy(*res, buf, count); return count; case 'b': set_busy_port(erlang_port, buf[0]); return 0; case 'i': driver_output(erlang_port, buf, count); return 0; default: if (command < 256) { return -1; } else { char* p = *res; int i; for (i = 3; i >= 0; i--) { p[i] = command; command >>= 8; } return 4; } } }
void gen_http_drv_schedule_write(ErlDrvData handle, ErlIOVec *ev) { HTTP* d = (HTTP *)handle; driver_enqv(d->port, ev, 0); //fprintf(stderr, "Queue %d bytes, %d\r\n", ev->size, driver_sizeq(d->port)); activate_write(d); if(driver_sizeq(d->port) > d->buffer_limit) { set_busy_port(d->port, 1); } }
void gen_http_drv_ready_output(ErlDrvData handle, ErlDrvEvent event) { HTTP* d = (HTTP*) handle; if(d->mode == REQUEST_MODE && d->state == CONNECTING_STATE) { accept_connection(d); return; } SysIOVec* vec; int vlen = 0; size_t written; vec = driver_peekq(d->port, &vlen); if(!vec || !vlen) { deactivate_write(d); return; } written = writev(d->socket, (const struct iovec *)vec, vlen > IOV_MAX ? IOV_MAX : vlen); if(vlen > IOV_MAX) { fprintf(stderr, "Buffer overloaded: %d, %d\r\n", vlen, (int)(driver_sizeq(d->port) - written)); } if(written == -1) { if((errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN)) { // fprintf(stderr, "Error in writev: %s, %d bytes left\r\n", strerror(errno), (int)driver_sizeq(d->port)); tcp_exit(d); return; } } else { ErlDrvSizeT rest = driver_deq(d->port, written); if(rest == 0) { ErlDrvTermData reply[] = { ERL_DRV_ATOM, atom_http, ERL_DRV_PORT, driver_mk_port(d->port), ERL_DRV_ATOM, atom_empty, ERL_DRV_TUPLE, 3 }; pid_list_send(d->exhausted, d->port, reply, sizeof(reply) / sizeof(reply[0])); pid_list_free(&d->exhausted); set_busy_port(d->port, 0); } // fprintf(stderr, "Network write: %d (%d)\r\n", (int)written, (int)rest); } }
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); }