Пример #1
0
/* length (4), PASS_THROUGH (1), header, message */
int ei_ei_send_reg_encoded(ei_cnode* ec, int fd, const erlang_pid *from,
			   const char *to, const char *msg, int msglen)
{
  char *s, header[1400]; /* see size calculation below */
  erlang_trace *token = NULL;
  int index = 5; /* reserve 5 bytes for control message */
#ifdef HAVE_WRITEV
  struct iovec v[2];
#endif

  /* are we tracing? */
  /* check that he can receive trace tokens first */
  if (ei_distversion(fd) > 0)
    token = ei_trace(0,(erlang_trace *)NULL);

  /* header = REG_SEND, from, cookie, toname         max sizes: */
  ei_encode_version(header,&index);                     /*   1 */
  if (token) { 
    ei_encode_tuple_header(header,&index,5);            /*   2 */
    ei_encode_long(header,&index,ERL_REG_SEND_TT);      /*   2 */
  } else {
    ei_encode_tuple_header(header,&index,4);    
    ei_encode_long(header,&index,ERL_REG_SEND); 
  }
  ei_encode_pid(header,&index,from);                    /* 268 */
  ei_encode_atom(header,&index,"" /*ei_getfdcookie(ec, fd)*/ );       /* 258 */
  ei_encode_atom(header,&index,to);                     /* 268 */

  if (token) ei_encode_trace(header,&index,token);      /* 534 */

  /* control message (precedes header actually) */
  /* length = 1 ('p') + header len + message len */
  s = header;
  put32be(s, index + msglen - 4);                       /*   4 */
  put8(s, ERL_PASS_THROUGH);                                /*   1 */
                                                /*** sum: 1336 */
  
#ifdef DEBUG_DIST
  if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg);
#endif
  
#ifdef HAVE_WRITEV

  v[0].iov_base = (char *)header;
  v[0].iov_len = index;
  v[1].iov_base = (char *)msg;
  v[1].iov_len = msglen;

  if (writev(fd,v,2) != index+msglen) return -1;
  
#else
  
  /* no writev() */
  if (writesocket(fd,header,index) != index) return -1;
  if (writesocket(fd,msg,msglen) != msglen) return -1;

#endif

  return 0;
}
Пример #2
0
ETERM *erl_global_whereis(int fd, const char *name, char *node)
{
  char buf[EISMALLBUF];
  char *bufp=buf;
  char tmpbuf[64];
  int index = 0;
  erlang_pid *self = erl_self();
  erlang_pid epid;
  ETERM *opid;
  erlang_msg msg;
  int i;
  int version,arity,msglen;

  self->num = fd;		/* FIXME looks strange to change something?! */

  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_pid(buf,&index,self);               /* PidFrom */
  ei_encode_tuple_header(buf,&index,5);
  ei_encode_atom(buf,&index,"call");            /* call */
  ei_encode_atom(buf,&index,"global");          /* Mod */
  ei_encode_atom(buf,&index,"whereis_name");    /* Fun */
  ei_encode_list_header(buf,&index,1);          /* Args: [ name ] */
  ei_encode_atom(buf,&index,name);
  ei_encode_empty_list(buf,&index);
  ei_encode_atom(buf,&index,"user");            /* user */

  /* make the rpc call */
  if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return NULL;

  while (1) {
    index = EISMALLBUF;
    if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
    else break;
  }

  if (i != ERL_SEND) return NULL;
    
  /* expecting { rex, pid } */
  index = 0;
  if (ei_decode_version(buf,&index,&version) 
      || ei_decode_tuple_header(buf,&index,&arity) 
      || (arity != 2) 
      || ei_decode_atom(buf,&index,tmpbuf) 
      || strcmp(tmpbuf,"rex")
      || ei_decode_pid(buf,&index,&epid))
    return NULL; /* bad response from other side */

  /* put the pid into a format for the caller */
  index = 0;
  ei_encode_pid(buf,&index,&epid);
  opid = erl_decode((unsigned char*)buf);

  /* extract the nodename for the caller */
  if (node) strcpy(node,epid.node);

  return opid;
}
/**
 * @brief Encode {error, <error_atom>} for the common error response
 * @param buf where to store the atom
 * @param index the index into buf
 * @param error_atom the atom's name
 * @return 0 on success; -1 on error
 */
int erlcmd_encode_error_tuple(char *buf, int *index, const char *error_atom)
{
    if (ei_encode_tuple_header(buf, index, 2) == 0 &&
        ei_encode_atom(buf, index, "error") == 0 &&
        ei_encode_atom(buf, index, error_atom) == 0)
        return 0;
    else
        return -1;
}
Пример #4
0
/**
 * @brief Send a response of the form {:error, reason}
 *
 * @param reason a reason (sent back as an atom)
 */
static void send_error_response(const char *reason)
{
    char resp[256];
    int resp_index = sizeof(uint16_t); // Space for payload size
    ei_encode_version(resp, &resp_index);
    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "error");
    ei_encode_atom(resp, &resp_index, reason);
    erlcmd_send(resp, resp_index);
}
Пример #5
0
static ErlDrvSSizeT encode_error(char* buf, char* error) {
    int index = 0;
    if (ei_encode_version(buf, &index) ||
        ei_encode_tuple_header(buf, &index, 2) ||
        ei_encode_atom(buf, &index, "error") ||
        ei_encode_atom(buf, &index, error)) {
        return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL;
    }
    return index+1;
}
Пример #6
0
static void enumerate_ports()
{
    struct serial_info *port_list = find_serialports();
    int port_list_len = 0;
    for (struct serial_info *port = port_list;
         port != NULL;
         port = port->next)
        port_list_len++;

    debug("Found %d ports", port_list_len);
    char resp[4096];
    int resp_index = sizeof(uint16_t); // Space for payload size
    resp[resp_index++] = response_id;
    ei_encode_version(resp, &resp_index);

    ei_encode_map_header(resp, &resp_index, port_list_len);

    for (struct serial_info *port = port_list;
         port != NULL;
         port = port->next) {
        ei_encode_binary(resp, &resp_index, port->name, strlen(port->name));

        int info_count = (port->description ? 1 : 0) +
                (port->manufacturer ? 1 : 0) +
                (port->serial_number ? 1 : 0) +
                (port->vid > 0 ? 1 : 0) +
                (port->pid > 0 ? 1 : 0);

        ei_encode_map_header(resp, &resp_index, info_count);
        if (port->description) {
            ei_encode_atom(resp, &resp_index, "description");
            ei_encode_binary(resp, &resp_index, port->description, strlen(port->description));
        }
        if (port->manufacturer) {
            ei_encode_atom(resp, &resp_index, "manufacturer");
            ei_encode_binary(resp, &resp_index, port->manufacturer, strlen(port->manufacturer));
        }
        if (port->serial_number) {
            ei_encode_atom(resp, &resp_index, "serial_number");
            ei_encode_binary(resp, &resp_index, port->serial_number, strlen(port->serial_number));
        }
        if (port->vid > 0) {
            ei_encode_atom(resp, &resp_index, "vendor_id");
            ei_encode_ulong(resp, &resp_index, port->vid);
        }
        if (port->pid > 0) {
            ei_encode_atom(resp, &resp_index, "product_id");
            ei_encode_ulong(resp, &resp_index, port->pid);
        }
    }
    erlcmd_send(resp, resp_index);
    serial_info_free_list(port_list);
}
Пример #7
0
static void handle_signals(const char *req, int *req_index)
{
    // No arguments
    (void) req;
    (void) req_index;

    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    struct uart_signals sig;
    if (uart_get_signals(uart, &sig) >= 0) {
        char resp[128];
        int resp_index = sizeof(uint16_t);
        resp[resp_index++] = response_id;
        ei_encode_version(resp, &resp_index);
        ei_encode_tuple_header(resp, &resp_index, 2);
        ei_encode_atom(resp, &resp_index, "ok");
        ei_encode_map_header(resp, &resp_index, 8);
        encode_kv_bool(resp, &resp_index, "dsr", sig.dsr);
        encode_kv_bool(resp, &resp_index, "dtr", sig.dtr);
        encode_kv_bool(resp, &resp_index, "rts", sig.rts);
        encode_kv_bool(resp, &resp_index, "st", sig.st);
        encode_kv_bool(resp, &resp_index, "sr", sig.sr);
        encode_kv_bool(resp, &resp_index, "cts", sig.cts);
        encode_kv_bool(resp, &resp_index, "cd", sig.cd);
        encode_kv_bool(resp, &resp_index, "rng", sig.rng);
        erlcmd_send(resp, resp_index);
    } else
        send_error_response(uart_last_error());
}
Пример #8
0
static int mn_send_delete(int fd, erlang_pid *mnesia, const char *key)
{
  char sbuf[EISMALLBUF];
  char *dbuf = NULL;
  char *msgbuf;
  int index = 0;
  int len = strlen(key) + 32; /* 32 is a slight overestimate */

  if (len > EISMALLBUF)
    if (!(dbuf = malloc(len)))
      return -1;
  msgbuf = (dbuf ? dbuf : sbuf);

  /* set up delete message { delete, Key } */
  ei_encode_version(msgbuf,&index);
  ei_encode_tuple_header(msgbuf,&index,2);
  ei_encode_atom(msgbuf,&index,EI_MNESIA_DELETE);
  ei_encode_string(msgbuf,&index,key);

  /* send it */
  if (ei_send_encoded(fd,mnesia,msgbuf,index)) {
    if (dbuf) free(dbuf);
    return -1;
  }

  if (dbuf) free(dbuf);
  return 0;
}
Пример #9
0
/**
 * @brief Send :ok back to Elixir
 */
static void send_ok_response()
{
    char resp[256];
    int resp_index = sizeof(uint16_t); // Space for payload size
    ei_encode_version(resp, &resp_index);
    ei_encode_atom(resp, &resp_index, "ok");
    erlcmd_send(resp, resp_index);
}
Пример #10
0
/* Called in active mode when there's a read or an error */
static void handle_notify_read(int error_reason, const uint8_t *data, size_t len)
{
    char *resp = malloc(64 + len);
    int resp_index = sizeof(uint16_t);
    ei_encode_version(resp, &resp_index);

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "notif");

    if (error_reason == 0) {
        // Normal receive
        ei_encode_binary(resp, &resp_index, data, len);
    } else {
        // Error notification
        ei_encode_tuple_header(resp, &resp_index, 2);
        ei_encode_atom(resp, &resp_index, "error");
        ei_encode_atom(resp, &resp_index, uart_last_error());
    }
    erlcmd_send(resp, resp_index);
    free(resp);
}
Пример #11
0
static int mn_send_write(int fd, erlang_pid *mnesia, const char *key, ei_reg_obj *obj)
{
  char sbuf[EISMALLBUF];
  char *dbuf = NULL;
  char *msgbuf;
  int index = 0;
  int keylen = strlen(key) + 1;
  int len = 32 + keylen + obj->size;

  if (len > EISMALLBUF)
    if (!(dbuf = malloc(len)))
      return -1;
  msgbuf = (dbuf ? dbuf : sbuf);

  ei_encode_version(msgbuf,&index);
  ei_encode_tuple_header(msgbuf,&index,6);
  ei_encode_atom(msgbuf,&index,EI_MNESIA_WRITE);
  ei_encode_string(msgbuf,&index,key);
  ei_encode_long(msgbuf,&index,keylen);
  ei_encode_long(msgbuf,&index,obj->attr);
  ei_encode_long(msgbuf,&index,obj->size);
					      
  switch (ei_reg_typeof(obj)) {
  case EI_INT:
    ei_encode_long(msgbuf,&index,obj->val.i);
    break;
  case EI_FLT:
    ei_encode_double(msgbuf,&index,obj->val.f);
    break;
  case EI_STR:
    if (obj->size > 0) ei_encode_string(msgbuf,&index,obj->val.s);
    else ei_encode_long(msgbuf,&index, (long)NULL);  /* just the NULL pointer */
    break;
  case EI_BIN:
    if (obj->size > 0) ei_encode_binary(msgbuf,&index,obj->val.p,obj->size);
    else ei_encode_long(msgbuf,&index,(long)(obj->val.p));  /* just the pointer */
    break;
  default:
    if (dbuf) free(dbuf);
    return -1;
  }

  /* send it */
  if (ei_send_encoded(fd,mnesia,msgbuf,index)) {
    if (dbuf) free(dbuf);
    return -1;
  }

  if (dbuf) free(dbuf);
  return 0;
}
/*!
 * Return statistics (amount of calls) for the driver and the currently active
 * thread. This function does not send any arguments to the driver.
 *
 * \param[in]     req       Request
 * \param[in,out] res       Result
 * \param[in,out] drv_state Driver state
 * \param[in,out] trd_state Thread state
 */
static void
handle_stats(gd_req_t *req, gd_res_t *res, gdt_drv_t *drv, gdt_trd_t *trd) {

  /* Encode return tuple header */
  ei_encode_tuple_header(res->buf, &res->index, 2);
  ei_encode_atom(res->buf, &res->index, "ok");

  /* Encode proplist header */
  ei_encode_list_header(res->buf, &res->index, 2);

  /* Encode driver calls */
  ei_encode_tuple_header(res->buf, &res->index, 2);
  ei_encode_atom(res->buf, &res->index, "driver");
  ei_encode_long(res->buf, &res->index, drv->count++);

  /* Encode thread calls */
  ei_encode_tuple_header(res->buf, &res->index, 2);
  ei_encode_atom(res->buf, &res->index, "thread");
  ei_encode_long(res->buf, &res->index, trd->count++);

  /* Encode empty list at the end */
  ei_encode_empty_list(res->buf, &res->index);
}
Пример #13
0
/* Called when uart_read completes or fails */
static void handle_read_completed(int rc, const uint8_t *data, size_t len)
{
    if (rc >= 0) {
        char *resp = malloc(32 + len);
        int resp_index = sizeof(uint16_t);
        ei_encode_version(resp, &resp_index);
        ei_encode_tuple_header(resp, &resp_index, 2);
        ei_encode_atom(resp, &resp_index, "ok");
        ei_encode_binary(resp, &resp_index, data, len);
        erlcmd_send(resp, resp_index);
        free(resp);
    } else
        send_error_response(uart_last_error());
}
Пример #14
0
static int mn_send_commit(int fd, erlang_pid *mnesia, erlang_pid *self)
{
  char buf[EISMALLBUF];
  char *bufp=buf;
  char string[256];
  int index = 0;
  int version,arity;
  int msglen;
  erlang_msg msg;
  int i;
  
  /* set up commit message { commit, self() } */
  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_atom(buf,&index,EI_MNESIA_COMMIT);
  ei_encode_pid(buf,&index,self);

  /* send it */
  if (ei_send_encoded(fd,mnesia,buf,index)) return -1;

  /* get reply */
  while (1) {
    index = EISMALLBUF;
    if (!(i=ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
    else if (i < 0) return -1;
    else break;
  }
  
  if (i == ERL_SEND) {
    index = 0;
    if (ei_decode_version(buf,&index,&version) 
	|| ei_decode_tuple_header(buf,&index,&arity) 
	|| ei_decode_atom(buf,&index,string))
      return -1;

    if (!strcmp(string,"ok")) return 0;
  }
  /* wrong message type */
  return -1;
}
Пример #15
0
static ErlDrvSSizeT syslogdrv_call(ErlDrvData handle, unsigned int command,
                                   char *buf, ErlDrvSizeT len,
                                   char **rbuf, ErlDrvSizeT rlen, unsigned int* flags)
{
    syslogdrv_t* d = (syslogdrv_t*)handle;
    int index = 0;

    if (command != SYSLOGDRV_CLOSE) {
        return (ErlDrvSSizeT)ERL_DRV_ERROR_BADARG;
    }

    if (d->ident) {
        driver_free(d->ident);
    }
    d->ident = NULL;
    d->open = 0;
    if (ei_encode_version(*rbuf, &index) ||
        ei_encode_atom(*rbuf, &index, "ok")) {
        return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL;
    }
    return index+1;
}
/*!
 * Take an arbitrary mixed list of integers and floats and add all numbers,
 * returning the resulting sum.
 *
 * \param[in]     req       Request
 * \param[in,out] res       Result
 * \param[in,out] drv_state Driver state
 * \param[in,out] trd_state Thread state
 */
static void
handle_sum(gd_req_t *req, gd_res_t *res, gdt_drv_t *drv, gdt_trd_t *trd) {
  int type, size;

  /* Determine type and size */
  if (ei_get_type(req->buf, &req->index, &type, &size) || size <= 0)
    return error_set(res, GDE_ERR_TYPE);

  /* Allocate memory for numbers */
  double *values, sum = 0;
  if (!(values = driver_alloc(sizeof(double) * size)))
    return error_set(res, GDE_ERR_MEMORY);

  /* Decode list */
  switch (type) {

    /* Decode integer list interpreted as string */
    case ERL_STRING_EXT: {
      char value[size];
      if (ei_decode_string(req->buf, &req->index, (char *)&value))
        return error_set(res, GDE_ERR_DECODE);
      for (int v = 0; v < size; v++)
        values[v] = (double)value[v];
      break;
    }

    /* Decode ordinary integer/double list */
    case ERL_LIST_EXT: {
      if (ei_decode_list_header(req->buf, &req->index, &size))
        return error_set(res, GDE_ERR_DECODE);
      for (int v = 0, temp; v < size; v++) {
        ei_get_type(req->buf, &req->index, &type, &temp);
        switch (type) {

          /* Decode integer */
          case ERL_SMALL_INTEGER_EXT:
          case ERL_INTEGER_EXT: {
            long value;
            if (ei_decode_long(req->buf, &req->index, &value))
              return error_set(res, GDE_ERR_DECODE);
            values[v] = (double)value;
            break;
          }

          /* Decode double */
          case ERL_FLOAT_EXT: {
            double value;
            if (ei_decode_double(req->buf, &req->index, &value))
              return error_set(res, GDE_ERR_DECODE);
            values[v] = (double)value;
            break;
          }

          /* Unsupported type */
          default:
            return error_set(res, GDE_ERR_TYPE);
        }
      }

      /* A list always contains an empty list at the end */
      if (ei_decode_list_header(req->buf, &req->index, NULL))
        return error_set(res, GDE_ERR_DECODE);
      break;
    }

    /* Unsupported type */
    default:
      return error_set(res, GDE_ERR_TYPE);
  }

  /* Sum up values */
  for (int v = 0; v < size; v++)
    sum += values[v];

  /* Free allocated memory */
  driver_free(values);

  /* Encode resulting sum and return tuple */
  ei_encode_tuple_header(res->buf, &res->index, 2);
  ei_encode_atom(res->buf, &res->index, "ok");
  ei_encode_double(res->buf, &res->index, sum);

  /* Update counters */
  drv->count++;
  trd->count++;
}
Пример #17
0
static int mn_start_restore(int fd, const erlang_pid *self, erlang_pid *mnesia, const char *mntab, long *count, long *maxkey,long *maxobj)
{
  char buf[EISMALLBUF];
  char *bufp=buf;
  char tmpbuf[64];
  int index = 0;
  erlang_msg msg;
  int arity;
  int version;
  int i;
  int needlink;
  int needmsg;
  int msglen;
  
  /* set up rpc arguments */
  /* { PidFrom, { call, Mod, Fun, Args, user }}  */
  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_pid(buf,&index,self);               /* PidFrom */
  ei_encode_tuple_header(buf,&index,5);
  ei_encode_atom(buf,&index,"call");            /* call */
  ei_encode_atom(buf,&index,EI_MNESIA_MODULE);  /* Mod */
  ei_encode_atom(buf,&index,EI_MNESIA_RESTORE); /* Fun */
  ei_encode_list_header(buf,&index,2);          /* Args: [ table, self() ] */
  ei_encode_atom(buf,&index,mntab);
  ei_encode_pid(buf,&index,self); 
  ei_encode_empty_list(buf,&index);
  ei_encode_atom(buf,&index,"user");            /* user */

  /* make the rpc call */
  if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;

  /* get the reply: expect link and message (not sure which will come first though) */
  needlink = needmsg = 1;
  while (needlink || needmsg) {
    /* get message */
    index = EISMALLBUF;
    while (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) index = EISMALLBUF;

    switch (i) {
    case ERL_LINK:
      /* got link */
      if (!needlink) return -1;
      needlink = 0;
      break;
      
    case ERL_SEND:
      /* got message - is it the right one? */
      if (!needmsg) return -1;
      else {
	/* expecting { rex, { size, Pid, Count, MaxKey, MaxObj }} */
	index = 0;
	if (ei_decode_version(buf,&index,&version) 
	    || ei_decode_tuple_header(buf,&index,&arity)
	    || (arity != 2) 
	    || ei_decode_atom(buf,&index,tmpbuf)
	    || strcmp(tmpbuf,"rex")
	    || ei_decode_tuple_header(buf,&index,&arity)
	    || (arity != 5) 
	    || ei_decode_atom(buf,&index,tmpbuf)
	    || strcmp(tmpbuf,EI_MNESIA_SIZE)
	    || ei_decode_pid(buf,&index,mnesia)
	    || ei_decode_long(buf,&index,count)
	    || ei_decode_long(buf,&index,maxkey)
	    || ei_decode_long(buf,&index,maxobj))
	  return -1; /* bad response from other side */
      
	/* got msg */
	needmsg = 0;
      }
      break;
      
    default:
      return -1; /* wasn't link or pid */
    }
  }
  return 0;
}
Пример #18
0
int ei_reg_restore(int fd, ei_reg *reg, const char *mntab)
{
  int i,j;
  char tag[32];
  char sbuf[EISMALLBUF];
  char *dbuf = NULL;
  char *msgbuf = NULL;
  char *keybuf = NULL;
  erlang_pid self;
  erlang_pid mnesia = {"",0,0,0};
  erlang_msg msg;
  int index = 0;
  int len = 0;
  int msglen;
  int version = 0;
  int arity = 0;
  long count = 0;
  long maxkey = 0;
  long maxobj = 0;
  ei_cnode *ec;

  if (!reg || !mntab) return -1; /* return EI_BADARG; */

  /* make a self pid */

  if ((ec = ei_fd_to_cnode(fd)) == NULL) {
      return -1;
  }
  strcpy(self.node,ei_thisnodename(ec));
  self.num = fd;
  self.serial = 0;
  self.creation = ei_thiscreation(ec);

  
  if (mn_start_restore(fd,&self,&mnesia,mntab,&count,&maxkey,&maxobj)) {
    /* send exit *only* if we have pid */
    if (mnesia.node[0]) ei_send_exit(fd,&self,&mnesia,"bad response from rpc start");
    return -1;
  }

  if (count <= 0) {
    ei_send_exit(fd,&self,&mnesia,"nothing to do");
    return 0;
  }
  
  /* make sure receive buffer can handle largest expected message */
  len = maxkey + maxobj + 512; 
  if (len > EISMALLBUF)
    if (!(dbuf = malloc(len))) {
      ei_send_exit(fd,&self,&mnesia,"cannot allocate space for incoming data");
      return -1;
    }
  msgbuf = (dbuf ? dbuf : sbuf);

  /* allocate space for largest key */
  if (!(keybuf = malloc(maxkey+1))) goto restore_failure;
  
  /* get this ball rolling */
  index = 0;
  ei_encode_version(msgbuf,&index);
  ei_encode_tuple_header(msgbuf,&index,2);
  ei_encode_atom(msgbuf,&index,"send_records");
  ei_encode_pid(msgbuf,&index,&self);
  if (ei_send_encoded(fd,&mnesia,msgbuf,index)) goto restore_failure;

  /* read as much as possible, until count or EXIT */
  for (i=0; i<count; i++) {
    index = len;
    while ((j = ei_recv_internal(fd,&msgbuf,&index,&msg,&msglen,1,0)) == 0) index = len;
    if (j<0) goto restore_failure;
    
    /* decode the first part of the message */
    index = 0;
    if ((msg.msgtype != ERL_SEND) 
	|| ei_decode_version(msgbuf,&index,&version) 
	|| ei_decode_tuple_header(msgbuf,&index,&arity) 
	|| (arity != 6) 
	|| ei_decode_atom(msgbuf,&index,tag) 
	|| strcmp(tag,EI_MNESIA_RECV)) 
      goto restore_failure;

    /* decode the rest of the message and insert data into table */
    if (mn_decode_insert(reg,msgbuf,&index,keybuf)) goto restore_failure;
  }
  
  if (keybuf) free(keybuf);
  if (dbuf) free(dbuf);

  /* wait for unlink */
  if (mn_unlink(fd)) return -1;

  /* clear all the dirty bits */
  ei_hash_foreach(reg->tab,clean_obj);

  /* success */
  return 0;

restore_failure:
  ei_send_exit(fd,&self,&mnesia,"restore failure");
  if (keybuf) free(keybuf);
  if (dbuf) free(dbuf);
  return -1;
}
Пример #19
0
static int mn_start_dump(int fd, const erlang_pid *self, 
			 erlang_pid *mnesia, const char *mntab)
{
  char buf[EISMALLBUF];
  char *bufp = buf;
  char tmpbuf[64];
  int index = 0;
  erlang_msg msg;
  int type;
  int arity;
  int version;
  int msglen;
  int i;
  int needlink;
  int needpid;

  /* set up rpc arguments */
  /* { PidFrom, { call, Mod, Fun, Args, user }}  */
  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_pid(buf,&index,self);               /* PidFrom */
  ei_encode_tuple_header(buf,&index,5);
  ei_encode_atom(buf,&index,"call");            /* call */
  ei_encode_atom(buf,&index,EI_MNESIA_MODULE);  /* Mod */
  ei_encode_atom(buf,&index,EI_MNESIA_DUMP);    /* Fun */
  ei_encode_list_header(buf,&index,2);          /* Args: [ table, self() ] */
  ei_encode_atom(buf,&index,mntab);
  ei_encode_pid(buf,&index,self); 
  ei_encode_empty_list(buf,&index);
  ei_encode_atom(buf,&index,"user");            /* user */

  /* make the rpc call */
  if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;

  /* get the reply: expect link and pid (not sure which will come first though) */
  needlink = needpid = 1;
  while (needlink || needpid) {
    /* get message */
    while (1) {
      index = EISMALLBUF;
      if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
      else break;
    }

    switch (i) {
    case ERL_LINK:
      /* got link */
      if (!needlink) return -1;
	needlink = 0;
      break;
      
    case ERL_SEND:
      /* got message - does it contain a pid? */
      if (!needpid) return -1;
      else {
	/* expecting { rex, <pid> } */
	index = 0;
	if (ei_decode_version(buf,&index,&version) 
	    || ei_decode_tuple_header(buf,&index,&arity) 
	    || (arity != 2) 
	    || ei_decode_atom(buf,&index,tmpbuf) 
	    || strcmp(tmpbuf,"rex")
	    || ei_get_type_internal(buf,&index,&type,&arity) 
	    || (type != ERL_PID_EXT))
	  return -1; /* bad response from other side */
      
	if (ei_decode_pid(buf,&index,mnesia)) return -1;

	/* got pid */
	needpid = 0;
      }
      break;
      
    default:
      return -1; /* wasn't link or pid */
    }
  }
  return 0;
}
Пример #20
0
static ErlDrvSSizeT call(ErlDrvData edd, unsigned int cmd, char *buf,
			 ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen,
			 unsigned int *flags) {
  dnssd_drv_t* dd = (dnssd_drv_t*) edd;
  int version, out_len, index, rindex, local_only;
  DNSServiceErrorType err;
  char* out_atom_text;
  ei_term arg, name, type, domain, txt, host, hostport;
  char *name_tmp, *type_tmp, *domain_tmp, *txt_tmp, *host_tmp;

  /* don't allow reuse */
  if (dd->sd_ref) return -1;

  index = 0;
  dd->sd_ref = NULL;

  ei_decode_version(buf, &index, &version);
  ei_decode_ei_term(buf, &index, &arg);

  if (cmd == DNSSD_CMD_ENUM)  {
    if (arg.ei_type == ERL_ATOM_EXT) {
      if (strncmp(arg.value.atom_name, "browse", 6) == 0) {
	// init for enum browse
	err = DNSServiceEnumerateDomains(&dd->sd_ref,
					 kDNSServiceFlagsBrowseDomains,
					 kDNSServiceInterfaceIndexAny,
					 (DNSServiceDomainEnumReply) EnumReply,
					 dd);
      } else if (strncmp(arg.value.atom_name,"reg", 3) == 0) {
	// init for enum reg
	err = DNSServiceEnumerateDomains(&dd->sd_ref,
					 kDNSServiceFlagsRegistrationDomains,
					 kDNSServiceInterfaceIndexAny,
					 (DNSServiceDomainEnumReply) EnumReply,
					 dd);
      } else {
	goto badarg;
      }
    } else {
      goto badarg;
    }
  } else if (cmd == DNSSD_CMD_BROWSE) {
    if (!arg.ei_type == ERL_TUPLE || arg.arity != 2) goto badarg;
    /* decode type */
    ei_decode_ei_term(buf, &index, &type);
    if (type.ei_type != ERL_BINARY_EXT) goto badarg;
    index += 5; // skip tag + 4 byte size
    type_tmp = (char*)driver_alloc(type.size + 1);
    memset(type_tmp, 0, type.size + 1);
    memcpy(type_tmp, buf + index, type.size);
    index += type.size;
    /* decode domain */
    ei_decode_ei_term(buf, &index, &domain);
    if (domain.ei_type != ERL_BINARY_EXT) {
      driver_free(type_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    domain_tmp = (char *) driver_alloc(domain.size + 1);
    memset(domain_tmp, 0, domain.size + 1);
    memcpy(domain_tmp, buf + index, domain.size);
    err = DNSServiceBrowse(&dd->sd_ref,
			   0, // Flags
			   kDNSServiceInterfaceIndexAny,
			   type_tmp,
			   domain_tmp,
			   (DNSServiceBrowseReply) BrowseReply,
			   dd);
    driver_free(type_tmp);
    driver_free(domain_tmp);
  } else if (cmd == DNSSD_CMD_RESOLVE) {
    if (!arg.ei_type == ERL_TUPLE || arg.arity != 3) goto badarg;
    /* decode name */
    ei_decode_ei_term(buf, &index, &name);
    if (name.ei_type != ERL_BINARY_EXT) goto badarg;
    index += 5; // skip tag + 4 byte size
    name_tmp = (char *) driver_alloc(name.size + 1);
    memset(name_tmp, 0, name.size + 1);
    memcpy(name_tmp, buf + index, name.size);
    index += name.size;
    /* decode type */
    ei_decode_ei_term(buf, &index, &type);
    if (type.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    type_tmp = (char *) driver_alloc(type.size + 1);
    memset(type_tmp, 0, type.size + 1);
    memcpy(type_tmp, buf + index, type.size);
    index += type.size;
    /* decode domain */
    ei_decode_ei_term(buf, &index, &domain);
    if (domain.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      driver_free(type_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    domain_tmp = (char *) driver_alloc(domain.size + 1);
    memset(domain_tmp, 0, domain.size + 1);
    memcpy(domain_tmp, buf + index, domain.size);
    /* start op */
    err = DNSServiceResolve(&dd->sd_ref,
			    0, // Flags
			    kDNSServiceInterfaceIndexAny,
			    name_tmp,
			    type_tmp,
			    domain_tmp,
			    (DNSServiceResolveReply) ResolveReply,
			    dd);
    driver_free(name_tmp);
    driver_free(type_tmp);
    driver_free(domain_tmp);
  } else if (cmd == DNSSD_CMD_REGISTER) {
    if (!arg.ei_type == ERL_TUPLE || arg.arity != 6) goto badarg;
    /* decode name */
    ei_decode_ei_term(buf, &index, &name);
    if (name.ei_type != ERL_BINARY_EXT) goto badarg;
    index += 5; // skip tag + 4 byte size
    name_tmp = (char *) driver_alloc(name.size + 1);
    memset(name_tmp, 0, name.size + 1);
    memcpy(name_tmp, buf + index, name.size);
    index += name.size;
    /* decode type */
    ei_decode_ei_term(buf, &index, &type);
    if (type.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    type_tmp = (char *) driver_alloc(type.size + 1);
    memset(type_tmp, 0, type.size + 1);
    memcpy(type_tmp, buf + index, type.size);
    index += type.size;
    /* decode domain */
    ei_decode_ei_term(buf, &index, &domain);
    if (domain.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      driver_free(type_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    domain_tmp = (char *) driver_alloc(domain.size + 1);
    memset(domain_tmp, 0, domain.size + 1);
    memcpy(domain_tmp, buf + index, domain.size);
    index += domain.size;
    /* decode host */
    ei_decode_ei_term(buf, &index, &host);
    if (host.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      driver_free(type_tmp);
      driver_free(domain_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    host_tmp = (char *) driver_alloc(host.size + 1);
    memset(host_tmp, 0, host.size + 1);
    memcpy(host_tmp, buf + index, host.size);
    index += host.size;
    /* decode port */
    ei_decode_ei_term(buf, &index, &hostport);
    if (hostport.ei_type != ERL_INTEGER_EXT &&
	hostport.ei_type != ERL_SMALL_INTEGER_EXT) {
      driver_free(name_tmp);
      driver_free(type_tmp);
      driver_free(domain_tmp);
      driver_free(host_tmp);
      goto badarg;
    }
    /* decode txt */
    ei_decode_ei_term(buf, &index, &txt);
    if (txt.ei_type != ERL_BINARY_EXT) {
      driver_free(name_tmp);
      driver_free(type_tmp);
      driver_free(domain_tmp);
      driver_free(host_tmp);
      goto badarg;
    }
    index += 5; // skip tag + 4 byte size
    txt_tmp = (char *) driver_alloc(txt.size + 1);
    memset(txt_tmp, 0, txt.size + 1);
    memcpy(txt_tmp, buf + index, txt.size);
    local_only = (0 == strcmp("localhost", host_tmp));
    err = DNSServiceRegister(&dd->sd_ref,
			     0, // Flags
			     local_only ? -1 : 0, // Interface: local / any
			     name_tmp,
			     type_tmp,
			     local_only ? "local" : domain_tmp,
			     host_tmp,
			     htons(hostport.value.i_val),
			     txt.size,
			     txt_tmp,
			     (DNSServiceRegisterReply) RegisterReply,
			     dd);
    driver_free(name_tmp);
    driver_free(type_tmp);
    driver_free(domain_tmp);
    driver_free(host_tmp);
    driver_free(txt_tmp);
  } else {
    goto badarg;
  }
  rindex = 0;
  out_len = 0;
  ei_encode_version(NULL, &out_len);
  if (err == kDNSServiceErr_NoError) {
#ifdef __WIN32__
    dd->event = WSACreateEvent();
    WSAEventSelect(DNSServiceRefSockFD(dd->sd_ref), dd->event, FD_READ);
    driver_select(dd->erl_port, dd->event, ERL_DRV_READ, 1);
#else
    driver_select(dd->erl_port,
		  (ErlDrvEvent)(size_t) DNSServiceRefSockFD(dd->sd_ref),
		  ERL_DRV_READ,
		  1);
#endif
    out_atom_text = "ok";
    ei_encode_atom(NULL, &out_len, out_atom_text);
    if(rlen < out_len) {
      *rbuf = driver_alloc(out_len);
      rlen = out_len;
    }
    ei_encode_version(*rbuf, &rindex);
    ei_encode_atom(*rbuf, &rindex, out_atom_text);
    return out_len;
  } else {
    out_atom_text = "error";
    ei_encode_tuple_header(NULL, &out_len, 2);
    ei_encode_atom(NULL, &out_len, out_atom_text);
    ei_encode_long(NULL, &out_len, 1337);
    if(rlen < out_len) {
      *rbuf = driver_alloc(out_len);
      rlen = out_len;
    }
    ei_encode_version(*rbuf, &rindex);
    ei_encode_tuple_header(*rbuf, &rindex, 2);
    ei_encode_atom(*rbuf, &rindex, out_atom_text);
    ei_encode_long(*rbuf, &rindex, (long) err);
    return out_len;
  }
 badarg:
  return -1;
}
Пример #21
0
static void handle_configuration(const char *req, int *req_index)
{
    char resp[256];
    int resp_index = sizeof(uint16_t); // Space for payload size
    resp[resp_index++] = response_id;
    ei_encode_version(resp, &resp_index);

    ei_encode_list_header(resp, &resp_index, 5);

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "speed");
    ei_encode_long(resp, &resp_index, current_config.speed);

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "data_bits");
    ei_encode_long(resp, &resp_index, current_config.data_bits);

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "stop_bits");
    ei_encode_long(resp, &resp_index, current_config.stop_bits);

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "parity");
    switch (current_config.parity) {
    default:
    case UART_PARITY_NONE: ei_encode_atom(resp, &resp_index, "none"); break;
    case UART_PARITY_EVEN: ei_encode_atom(resp, &resp_index, "even"); break;
    case UART_PARITY_ODD: ei_encode_atom(resp, &resp_index, "odd"); break;
    case UART_PARITY_SPACE: ei_encode_atom(resp, &resp_index, "space"); break;
    case UART_PARITY_MARK: ei_encode_atom(resp, &resp_index, "mark"); break;
    case UART_PARITY_IGNORE: ei_encode_atom(resp, &resp_index, "ignore"); break;
    }

    ei_encode_tuple_header(resp, &resp_index, 2);
    ei_encode_atom(resp, &resp_index, "flow_control");
    switch (current_config.parity) {
    default:
    case UART_FLOWCONTROL_NONE: ei_encode_atom(resp, &resp_index, "none"); break;
    case UART_FLOWCONTROL_HARDWARE: ei_encode_atom(resp, &resp_index, "hardware"); break;
    case UART_FLOWCONTROL_SOFTWARE: ei_encode_atom(resp, &resp_index, "software"); break;
    }

    ei_encode_empty_list(resp, &resp_index);

    erlcmd_send(resp, resp_index);
}
Пример #22
0
int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from,
			    const char *to, char *msg, int msglen,
			    unsigned ms)
{
    char *s, header[1400]; /* see size calculation below */
    erlang_trace *token = NULL;
    int index = 5; /* reserve 5 bytes for control message */
    int err;
    ei_socket_callbacks *cbs;
    void *ctx;
    ssize_t len, tot_len;
    unsigned tmo = ms == 0 ? EI_SCLBK_INF_TMO : ms;

    err = EI_GET_CBS_CTX__(&cbs, &ctx, fd);
    if (err) {
        EI_CONN_SAVE_ERRNO__(err);
        return ERL_ERROR;
    }
    
    /* are we tracing? */
    /* check that he can receive trace tokens first */
    if (ei_distversion(fd) > 0)
	token = ei_trace(0,NULL);
    
    /* header = REG_SEND, from, cookie, toname         max sizes: */
    ei_encode_version(header,&index);                     /*   1 */
    if (token) { 
	ei_encode_tuple_header(header,&index,5);            /*   2 */
	ei_encode_long(header,&index,ERL_REG_SEND_TT);      /*   2 */
    } else {
	ei_encode_tuple_header(header,&index,4);    
	ei_encode_long(header,&index,ERL_REG_SEND); 
    }
    ei_encode_pid(header, &index, from);                    /* 268 */
    ei_encode_atom(header, &index, ei_getfdcookie(fd));       /* 258 */
    ei_encode_atom(header, &index, to);                     /* 268 */

    if (token) ei_encode_trace(header,&index,token);      /* 534 */

    /* control message (precedes header actually) */
    /* length = 1 ('p') + header len + message len */
    s = header;
    put32be(s, index + msglen - 4);                       /*   4 */
    put8(s, ERL_PASS_THROUGH);                                /*   1 */
                                                /*** sum: 1336 */
    if (ei_tracelevel >= 4) 
	ei_show_sendmsg(stderr,header,msg);

#ifdef EI_HAVE_STRUCT_IOVEC__
    if (ei_socket_callbacks_have_writev__(cbs)) {
        struct iovec v[2];

        v[0].iov_base = (char *)header;
        v[0].iov_len = index;
        v[1].iov_base = (char *)msg;
        v[1].iov_len = msglen;
    
        len = tot_len = (ssize_t) index+msglen;
        err = ei_writev_fill_ctx_t__(cbs, ctx, v, 2, &len, tmo);
        if (!err && len != tot_len)
            err = EIO;
        if (err) {
            EI_CONN_SAVE_ERRNO__(err);
            return -1;
        }
        return 0;
    }
#endif /* EI_HAVE_STRUCT_IOVEC__ */

    /* no writev() */
    len = tot_len = (ssize_t) index;
    err = ei_write_fill_ctx_t__(cbs, ctx, header, &len, tmo);
    if (!err && len != tot_len)
        err = EIO;
    if (err) {
        EI_CONN_SAVE_ERRNO__(err);
        return -1;
    }

    len = tot_len = (ssize_t) msglen;
    err = ei_write_fill_ctx_t__(cbs, ctx, msg, &len, tmo);
    if (!err && len != tot_len)
        err = EIO;
    if (err) {
        EI_CONN_SAVE_ERRNO__(err);
        return -1;
    }
    
    return 0;
}
Пример #23
0
/*
This function is called from erlang:port_call/3. It works a lot like the control call-back,
but uses the external term format for input and output.
- command is an integer, obtained from the call from erlang (the second argument to erlang:port_call/3).
- buf and len provide the arguments to the call (the third argument to erlang:port_call/3). They're decoded using ei.
- rbuf points to a return buffer, rlen bytes long.

The return data (written to *rbuf) should be a valid erlang term in the external term format. This is converted to an
erlang term and returned by erlang:port_call/3 to the caller. If more space than rlen bytes is needed to return data,
*rbuf can be set to memory allocated with driver_alloc. This memory will be freed automatically after call has returned.
The return value (of this callback function) is the number of bytes returned in *rbuf. If ERL_DRV_ERROR_GENERAL is returned
(or in fact, anything < 0), erlang:port_call/3 will throw a BAD_ARG.

THIS IMPLEMENTATION of the callback handles two kinds of commands, INIT_COMMAND and ENGINE_COMMAND. An INIT_COMMAND should
only be issued once during the lifecycle of the driver, *before* any data is sent to the port using port_command/port_control.
The INIT_COMMAND causes the driver to load the specified shared library and call a predefined entry point (see the
erlxsl_driver header file for details) to initialize an XslEngine structure.

TODO: document ENGINE_COMMAND.
TODO: locking during ENGINE_COMMAND calls
TODO: support the transform command here as well - small binaries (which we can't/won't share/refcount) can be passed and copied...
*/
static int
call(ErlDrvData drv_data, unsigned int command, char *buf,
    int len, char **rbuf, int rlen, unsigned int *flags) {

    int i;
    int type;
    int size;
    int index = 0;
    int rindex = 0;
    /*int arity;
     *
    char cmd[MAXATOMLEN];*/
    char *data;
    DriverState state;
    DriverHandle *d = (DriverHandle*)drv_data;

    ei_decode_version(buf, &index, &i);
    if (command == INIT_COMMAND) {
        ei_get_type(buf, &index, &type, &size);
        INFO("ei_get_type %s of size = %i\n", ((char*)&type), size);
        // TODO: pull options tuple instead
        data = ALLOC(size + 1);
        ei_decode_string(buf, &index, data);
        INFO("Driver received data %s\n", data);
        state = init_provider(d, data);
    } else if (command == ENGINE_COMMAND) {
        DriverContext *ctx = ALLOC(sizeof(DriverContext));
        // ErlDrvPort port = (ErlDrvPort)d->port;
        // XslEngine *engine = (XslEngine*)d->engine;
        // ErlDrvTermData callee_pid = driver_caller(port);
        Command *cmd = init_command(NULL, ctx, NULL, init_iov(Text, 0, NULL));

        state = decode_ei_cmd(cmd, buf, &index);
        if (state == Success) {
            XslEngine *engine = (XslEngine*)d->engine;
            if (engine->command != NULL) {
                EngineState enstate = engine->command(cmd);
                if (enstate == Ok) {
                    state = Success;
                }
            }
        }
        /*ei_get_type(buf, &index, &type, &size);
        INFO("ei_get_type %s of size = %i\n", ((char*)&type), size);
        data = ALLOC(size + 1);
        ei_decode_string(buf, &index, data);*/
    } else {
        state = UnknownCommand;
    }

    ei_encode_version(*rbuf, &rindex);
    if (state == InitOk) {
        INFO("Provider configured with library %s\n", d->loader->name);
#ifdef _DRV_SASL_LOGGING
        // TODO: pull the logging_port and install it....
#endif
        ei_encode_atom(*rbuf, &rindex, "configured");
    } else if (state == Success) {
        ei_encode_tuple_header(*rbuf, &rindex, 2);
        ei_encode_atom(*rbuf, &rindex, "ok");
        if (state == OutOfMemory) {
            ei_encode_string(*rbuf, &rindex, heap_space_exhausted);
        } else if (state == UnknownCommand) {
            ei_encode_string(*rbuf, &rindex, unknown_command);
        } else {
            const char *err = (d->loader)->error_message;
            ei_encode_string_len(*rbuf, &rindex, err, strlen(err));
        }
    } else {
        ei_encode_tuple_header(*rbuf, &rindex, 2);
        ei_encode_atom(*rbuf, &rindex, "error");
        if (state == OutOfMemory) {
            ei_encode_string(*rbuf, &rindex, heap_space_exhausted);
        } else if (state == UnknownCommand) {
            ei_encode_string(*rbuf, &rindex, unknown_command);
        } else {
            const char *err = (d->loader)->error_message;
            ei_encode_string_len(*rbuf, &rindex, err, strlen(err));
        }
    }
    DRV_FREE(data);
    return(rindex);
};
Пример #24
0
static void i2c_handle_request(const char *req, void *cookie)
{
    struct i2c_info *i2c = (struct i2c_info *) cookie;

    // Commands are of the form {Command, Arguments}:
    // { atom(), term() }
    int req_index = sizeof(uint16_t);
    if (ei_decode_version(req, &req_index, NULL) < 0)
        errx(EXIT_FAILURE, "Message version issue?");

    int arity;
    if (ei_decode_tuple_header(req, &req_index, &arity) < 0 ||
            arity != 2)
        errx(EXIT_FAILURE, "expecting {cmd, args} tuple");

    char cmd[MAXATOMLEN];
    if (ei_decode_atom(req, &req_index, cmd) < 0)
        errx(EXIT_FAILURE, "expecting command atom");

    char resp[256];
    int resp_index = sizeof(uint16_t); // Space for payload size
    ei_encode_version(resp, &resp_index);
    if (strcmp(cmd, "read") == 0) {
        long int len;
        if (ei_decode_long(req, &req_index, &len) < 0 ||
                len < 1 ||
                len > I2C_SMBUS_BLOCK_MAX)
            errx(EXIT_FAILURE, "read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX);

        char data[I2C_SMBUS_BLOCK_MAX];

        if (i2c_transfer(i2c, 0, 0, data, len))
            ei_encode_binary(resp, &resp_index, data,len);
        else {
            ei_encode_tuple_header(resp, &resp_index, 2);
            ei_encode_atom(resp, &resp_index, "error");
            ei_encode_atom(resp, &resp_index, "i2c_read_failed");
        }
    } else if (strcmp(cmd, "write") == 0) {
        char data[I2C_SMBUS_BLOCK_MAX];
        int len;
        int type;
        long llen;
        if (ei_get_type(req, &req_index, &type, &len) < 0 ||
                type != ERL_BINARY_EXT ||
                len < 1 ||
                len > I2C_SMBUS_BLOCK_MAX ||
                ei_decode_binary(req, &req_index, &data, &llen) < 0)
            errx(EXIT_FAILURE, "write: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX);

        if (i2c_transfer(i2c, data, len, 0, 0))
            ei_encode_atom(resp, &resp_index, "ok");
        else {
            ei_encode_tuple_header(resp, &resp_index, 2);
            ei_encode_atom(resp, &resp_index, "error");
            ei_encode_atom(resp, &resp_index, "i2c_write_failed");
        }
    } else if (strcmp(cmd, "wrrd") == 0) {
        char write_data[I2C_SMBUS_BLOCK_MAX];
        char read_data[I2C_SMBUS_BLOCK_MAX];
        int write_len;
        long int read_len;
        int type;
        long llen;

        if (ei_decode_tuple_header(req, &req_index, &arity) < 0 ||
            arity != 2)
            errx(EXIT_FAILURE, "wrrd: expecting {write_data, read_count} tuple");

        if (ei_get_type(req, &req_index, &type, &write_len) < 0 ||
                type != ERL_BINARY_EXT ||
                write_len < 1 ||
                write_len > I2C_SMBUS_BLOCK_MAX ||
                ei_decode_binary(req, &req_index, &write_data, &llen) < 0)
            errx(EXIT_FAILURE, "wrrd: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX);
        if (ei_decode_long(req, &req_index, &read_len) < 0 ||
                read_len < 1 ||
                read_len > I2C_SMBUS_BLOCK_MAX)
            errx(EXIT_FAILURE, "wrrd: read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX);

        if (i2c_transfer(i2c, write_data, write_len, read_data, read_len))
            ei_encode_binary(resp, &resp_index, read_data, read_len);
        else {
            ei_encode_tuple_header(resp, &resp_index, 2);
            ei_encode_atom(resp, &resp_index, "error");
            ei_encode_atom(resp, &resp_index, "i2c_wrrd_failed");
        }
    } else
        errx(EXIT_FAILURE, "unknown command: %s", cmd);

    debug("sending response: %d bytes", resp_index);
    erlcmd_send(resp, resp_index);
}
Пример #25
0
int main(void)
#endif
{
  ErlConnect conp;
  Erl_IpAddr thisipaddr = (Erl_IpAddr)0;
  FILE *fp = (FILE *)0;
  char* charp = "foo";
  double *doublep = NULL;
  double doublex = 0.0;
  ei_cnode xec;
  ei_reg *ei_regp = NULL;
  ei_term eterm;
  ei_x_buff eix;
  erlang_big *bigp = NULL;
  erlang_fun efun;
  erlang_msg *msgp = NULL;
  erlang_msg emsg;
  erlang_pid *pidp = NULL;
  erlang_pid epid;
  erlang_port eport;
  erlang_ref eref;
  erlang_trace etrace;
  int *intp = NULL;
  int intx = 0;
  long *longp = NULL;
  long longx = 0;
  short creation = 0;
  struct ei_reg_stat *ei_reg_statp = NULL;
  struct ei_reg_tabstat *ei_reg_tabstatp = NULL;
  struct hostent *hostp = NULL;
  unsigned char * ucharp = (unsigned char *)"foo";
  unsigned long *ulongp = NULL;
  unsigned long ulongx = 0;
  void *voidp = NULL;
#ifndef VXWORKS
  EI_LONGLONG *longlongp = (EI_LONGLONG*)NULL;
  EI_LONGLONG longlongx = 0;
  EI_ULONGLONG *ulonglongp = (EI_ULONGLONG*)NULL;
  EI_ULONGLONG ulonglongx = 0;
#endif
  enum erlang_char_encoding enc;

  intx = erl_errno;

  ei_connect_init(&xec, charp, charp, creation);
  ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation);

  ei_connect(&xec, charp);
  ei_xconnect (&xec, thisipaddr, charp);

  ei_receive(intx, ucharp, intx);
  ei_receive_msg(intx, &emsg, &eix);
  ei_xreceive_msg(intx, &emsg, &eix);

  ei_send(intx, &epid, charp, intx);
  ei_reg_send(&xec, intx, charp, charp, intx);

  ei_rpc(&xec, intx, charp, charp, charp, intx, &eix);
  ei_rpc_to(&xec, intx, charp, charp, charp, intx);
  ei_rpc_from(&xec, intx, intx, &emsg, &eix);

  ei_publish(&xec, intx);
  ei_accept(&xec, intx, &conp);
  ei_unpublish(&xec);

  ei_thisnodename(&xec);
  ei_thishostname(&xec);
  ei_thisalivename(&xec);

  ei_self(&xec);

  ei_gethostbyname(charp);
  ei_gethostbyaddr(charp, intx, intx);
  ei_gethostbyname_r(charp, hostp, charp, intx, intp);
  ei_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp);

  ei_encode_version(charp, intp);
  ei_x_encode_version(&eix);
  ei_encode_long(charp, intp, longx);
  ei_x_encode_long(&eix, longx);
  ei_encode_ulong(charp, intp, ulongx);
  ei_x_encode_ulong(&eix, ulongx);
  ei_encode_double(charp, intp, doublex);
  ei_x_encode_double(&eix, doublex);
  ei_encode_boolean(charp, intp, intx);
  ei_x_encode_boolean(&eix, intx);
  ei_encode_char(charp, intp, 'a');
  ei_x_encode_char(&eix, 'a');
  ei_encode_string(charp, intp, charp);
  ei_encode_string_len(charp, intp, charp, intx);
  ei_x_encode_string(&eix, charp);
  ei_x_encode_string_len(&eix, charp, intx);
  ei_encode_atom(charp, intp, charp);
  ei_encode_atom_as(charp, intp, charp, ERLANG_LATIN1, ERLANG_UTF8);
  ei_encode_atom_len(charp, intp, charp, intx);
  ei_encode_atom_len_as(charp, intp, charp, intx, ERLANG_ASCII, ERLANG_LATIN1);
  ei_x_encode_atom(&eix, charp);
  ei_x_encode_atom_as(&eix, charp, ERLANG_LATIN1, ERLANG_UTF8);
  ei_x_encode_atom_len(&eix, charp, intx);
  ei_x_encode_atom_len_as(&eix, charp, intx, ERLANG_LATIN1, ERLANG_UTF8);
  ei_encode_binary(charp, intp, (void *)0, longx);
  ei_x_encode_binary(&eix, (void*)0, intx);
  ei_encode_pid(charp, intp, &epid);
  ei_x_encode_pid(&eix, &epid);
  ei_encode_fun(charp, intp, &efun);
  ei_x_encode_fun(&eix, &efun);
  ei_encode_port(charp, intp, &eport);
  ei_x_encode_port(&eix, &eport);
  ei_encode_ref(charp, intp, &eref);
  ei_x_encode_ref(&eix, &eref);
  ei_encode_trace(charp, intp, &etrace);
  ei_x_encode_trace(&eix, &etrace);
  ei_encode_tuple_header(charp, intp, intx);
  ei_x_encode_tuple_header(&eix, longx);
  ei_encode_list_header(charp, intp, intx);
  ei_x_encode_list_header(&eix, longx);
/* #define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) */
  ei_x_encode_empty_list(&eix);

  ei_get_type(charp, intp, intp, intp);
  ei_get_type_internal(charp, intp, intp, intp);

  ei_decode_version(charp, intp, intp);
  ei_decode_long(charp, intp, longp);
  ei_decode_ulong(charp, intp, ulongp);
  ei_decode_double(charp, intp, doublep);
  ei_decode_boolean(charp, intp, intp);
  ei_decode_char(charp, intp, charp);
  ei_decode_string(charp, intp, charp);
  ei_decode_atom(charp, intp, charp);
  ei_decode_atom_as(charp, intp, charp, MAXATOMLEN_UTF8, ERLANG_WHATEVER, &enc, &enc);
  ei_decode_binary(charp, intp, (void *)0, longp);
  ei_decode_fun(charp, intp, &efun);
  free_fun(&efun);
  ei_decode_pid(charp, intp, &epid);
  ei_decode_port(charp, intp, &eport);
  ei_decode_ref(charp, intp, &eref);
  ei_decode_trace(charp, intp, &etrace);
  ei_decode_tuple_header(charp, intp, intp);
  ei_decode_list_header(charp, intp, intp);

  ei_decode_ei_term(charp, intp, &eterm);

  ei_print_term(fp, charp, intp);
  ei_s_print_term(&charp, charp, intp);

  ei_x_format(&eix, charp);
  ei_x_format_wo_ver(&eix, charp);

  ei_x_new(&eix);
  ei_x_new_with_version(&eix);
  ei_x_free(&eix);
  ei_x_append(&eix, &eix);
  ei_x_append_buf(&eix, charp, intx);
  ei_skip_term(charp, intp);

  ei_reg_open(intx);
  ei_reg_resize(ei_regp, intx);
  ei_reg_close(ei_regp);

  ei_reg_setival(ei_regp, charp, longx);
  ei_reg_setfval(ei_regp, charp, doublex);
  ei_reg_setsval(ei_regp, charp, charp);
  ei_reg_setpval(ei_regp, charp, voidp, intx);

  ei_reg_setval(ei_regp, charp, intx);

  ei_reg_getival(ei_regp, charp);
  ei_reg_getfval(ei_regp, charp);
  ei_reg_getsval(ei_regp, charp);
  ei_reg_getpval(ei_regp, charp, intp);

  ei_reg_getval(ei_regp, charp, intx);

  ei_reg_markdirty(ei_regp, charp);

  ei_reg_delete(ei_regp, charp);

  ei_reg_stat(ei_regp, charp, ei_reg_statp);

  ei_reg_tabstat(ei_regp, ei_reg_tabstatp);

  ei_reg_dump(intx, ei_regp, charp, intx);
  ei_reg_restore(intx, ei_regp, charp);
  ei_reg_purge(ei_regp);

#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP)
  {
      mpz_t obj;
      ei_decode_bignum(charp, intp, obj);
      ei_encode_bignum(charp, intp, obj);
      ei_x_encode_bignum(&eix, obj);
  }
#endif /* HAVE_GMP_H && HAVE_LIBGMP */

#ifndef VXWORKS

  ei_decode_longlong(charp, intp, longlongp);
  ei_decode_ulonglong(charp, intp, ulonglongp);
  ei_encode_longlong(charp, intp, longlongx);
  ei_encode_ulonglong(charp, intp, ulonglongx);
  ei_x_encode_longlong(&eix, longlongx);
  ei_x_encode_ulonglong(&eix, ulonglongx);

#endif

#ifdef USE_EI_UNDOCUMENTED

  ei_decode_intlist(charp, intp, longp, intp);

  ei_receive_encoded(intx, &charp, intp, msgp, intp);
  ei_send_encoded(intx, pidp, charp, intx);
  ei_send_reg_encoded(intx, pidp, charp, charp, intx);

  ei_decode_big(charp, intp, bigp);
  ei_big_comp(bigp, bigp);
  ei_big_to_double(bigp, doublep);
  ei_small_to_big(intx, bigp);
  ei_alloc_big(intx);
  ei_free_big(bigp);

#endif /* USE_EI_UNDOCUMENTED */

  return
      BUFSIZ +
      EAGAIN +
      EHOSTUNREACH +
      EIO +
      EI_BIN +
      EI_DELET +
      EI_DIRTY +
      EI_FLT +
      EI_FORCE +
      EI_INT +
      EI_NOPURGE +
      EI_STR +
      EMSGSIZE +
      ENOMEM +
      ERL_ERROR +
      ERL_EXIT +
      ERL_LINK +
      ERL_MSG +
      ERL_NO_TIMEOUT +
      ERL_REG_SEND +
      ERL_SEND +
      ERL_TICK +
      ERL_TIMEOUT +
      ERL_UNLINK +
      ETIMEDOUT +
      MAXATOMLEN;
}
Пример #26
0
/* global:unregister_name(name) -> ok */
int erl_global_unregister(int fd, const char *name)
{
  char buf[EISMALLBUF];
  char *bufp=buf;
  char tmpbuf[64];
  int index = 0;
  erlang_pid *self = erl_self();
  erlang_msg msg;
  int i;
  int version,arity,msglen;
  int needunlink, needatom, needdemonitor;

  /* make a self pid */
  self->num = fd;
  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_pid(buf,&index,self);               /* PidFrom */
  ei_encode_tuple_header(buf,&index,5);
  ei_encode_atom(buf,&index,"call");            /* call */
  ei_encode_atom(buf,&index,"global");          /* Mod */
  ei_encode_atom(buf,&index,"unregister_name_external");    /* Fun */
  ei_encode_list_header(buf,&index,1);          /* Args: [ name ] */
  ei_encode_atom(buf,&index,name);
  ei_encode_empty_list(buf,&index);
  ei_encode_atom(buf,&index,"user");            /* user */

  /* make the rpc call */
  if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;

  /* get the reply: expect unlink and an atom, or just an atom */
  needunlink = needatom = needdemonitor = 1;
  while (1) {
    /* get message */
    while (1) {
      index = EISMALLBUF;
      if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
      else break;
    }

    switch (i) {
    case ERL_UNLINK:
      /* got unlink */
      if (!needunlink) return -1;
      needunlink = 0;
      break;

    case ERL_DEMONITOR_P-10:
      /* got demonitor */
      if (!needdemonitor) return -1;
      needdemonitor = 0;
      break;

    case ERL_SEND:
      /* got message - does it contain our atom? */
      if (!needatom) return -1;
      else {
	/* expecting { rex, ok } */
	index = 0;
	if (ei_decode_version(buf,&index,&version) 
	    || ei_decode_tuple_header(buf,&index,&arity) 
	    || (arity != 2) 
	    || ei_decode_atom(buf,&index,tmpbuf) 
	    || strcmp(tmpbuf,"rex")
	    || ei_decode_atom(buf,&index,tmpbuf) 
	    || strcmp(tmpbuf,"ok"))
	  return -1; /* bad response from other side */

	/* we're done here */
	return 0;
      }
      break;

    default:
      return -1;
    }
  }

  return 0;
}
Пример #27
0
int ei_send_encoded_tmo(int fd, const erlang_pid *to, 
			char *msg, int msglen, unsigned ms) 
{
    char *s, header[1200]; /* see size calculation below */
    erlang_trace *token = NULL;
    int index = 5; /* reserve 5 bytes for control message */
    int res;
#ifdef HAVE_WRITEV
    struct iovec v[2];
#endif

    /* are we tracing? */
    /* check that he can receive trace tokens first */
    if (ei_distversion(fd) > 0) token = ei_trace(0,NULL);
    
    /* header = SEND, cookie, to                      max sizes: */
    ei_encode_version(header,&index);		      /*   1 */
    if (token) {
	ei_encode_tuple_header(header,&index,4);      /*   2 */
	ei_encode_long(header,&index,ERL_SEND_TT);    /*   2 */
    } else {
	ei_encode_tuple_header(header,&index,3);
	ei_encode_long(header,&index,ERL_SEND); 
    }
    ei_encode_atom(header,&index,ei_getfdcookie(fd)); /* 258 */
    ei_encode_pid(header,&index,to);		      /* 268 */
    
    if (token) ei_encode_trace(header,&index,token);  /* 534 */
    
    /* control message (precedes header actually) */
    /* length = 1 ('p') + header len + message len */
    s = header;
    put32be(s, index + msglen - 4);		      /*   4 */
    put8(s, ERL_PASS_THROUGH);			      /*   1 */
				/*** sum: 1070 */

    if (ei_tracelevel >= 4)
	ei_show_sendmsg(stderr,header,msg);

#ifdef HAVE_WRITEV
    
    v[0].iov_base = (char *)header;
    v[0].iov_len = index;
    v[1].iov_base = (char *)msg;
    v[1].iov_len = msglen;
    
    if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) {
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }
  
#else  /* !HAVE_WRITEV */
  
    if ((res = ei_write_fill_t(fd,header,index,ms)) != index) { 
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }
    if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) { 
	erl_errno = (res == -2) ? ETIMEDOUT : EIO;
	return -1;
    }

#endif  /* !HAVE_WRITEV */

    return 0;
}
Пример #28
0
static void encode_kv_bool(char *resp, int *resp_index, const char *key, int value)
{
    ei_encode_atom(resp, resp_index, key);
    ei_encode_boolean(resp, resp_index, value);
}
Пример #29
0
int erl_global_register(int fd, const char *name, ETERM *pid)
{
  char buf[EISMALLBUF];
  char *bufp=buf;
  char tmpbuf[64];
  int index = 0;
  erlang_pid self;
  erlang_msg msg;
  int needlink, needatom, needmonitor;
  int arity;
  int version;
  int msglen;
  int i;

  /* get that pid into a better format */
  if (!erl_encode(pid,(unsigned char*)buf)) return -1;
  if (ei_decode_version(buf,&index,&version)
      || ei_decode_pid(buf,&index,&self)) return -1;
  
  /* set up rpc arguments */
  /* { PidFrom, { call, Mod, Fun, Args, user }}  */
  index = 0;
  ei_encode_version(buf,&index);
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_pid(buf,&index,&self);               /* PidFrom */
  ei_encode_tuple_header(buf,&index,5);
  ei_encode_atom(buf,&index,"call");            /* call */
  ei_encode_atom(buf,&index,"global");          /* Mod */
  ei_encode_atom(buf,&index,"register_name_external");    /* Fun */
  ei_encode_list_header(buf,&index,3);     /* Args: [ name, self(), cnode ] */
  ei_encode_atom(buf,&index,name);
  ei_encode_pid(buf,&index,&self); 
  ei_encode_tuple_header(buf,&index,2);
  ei_encode_atom(buf,&index,"global"); /* special "resolve" treatment */ 
  ei_encode_atom(buf,&index,"cnode");  /* i.e. we get a SEND when conflict */
  ei_encode_empty_list(buf,&index);
  ei_encode_atom(buf,&index,"user");            /* user */

  /* make the rpc call */
  if (ei_send_reg_encoded(fd,&self,"rex",buf,index)) return -1;

  /* get the reply: expect link and an atom, or just an atom */
  needlink = needatom = needmonitor = 1;
  while (1) {
    /* get message */
    while (1) {
      index = EISMALLBUF;
      if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
      else break;
    }

    switch (i) {
    case ERL_LINK:
      /* got link */
      if (!needlink) return -1;
      needlink = 0;
      break;
      
    case ERL_MONITOR_P-10:
      /* got monitor */
	if (!needmonitor) { return -1;}
	needmonitor = 0;
      break;

    case ERL_SEND:
      /* got message - does it contain our atom? */
      if (!needatom) return -1;
      else {
	/* expecting { rex, yes } */
	index = 0;
	if (ei_decode_version(buf,&index,&version) 
	    || ei_decode_tuple_header(buf,&index,&arity) 
	    || (arity != 2) 
	    || ei_decode_atom(buf,&index,tmpbuf) 
	    || strcmp(tmpbuf,"rex")
	    || ei_decode_atom(buf,&index,tmpbuf) 
	    || strcmp(tmpbuf,"yes"))
	  return -1; /* bad response from other side */

	/* we're done */
	return 0;
      }
      break;
      
    default:
      return -1; /* something else */
    }
  }
  return 0;
}
Пример #30
0
int32_t spawn(char protocol, uint32_t * ports, uint32_t ports_len,
              char * filename, uint32_t /*filename_len*/,
              char * argv, uint32_t argv_len,
              char * env, uint32_t env_len)
{
    int type;
    if (protocol == 't') // tcp
    {
        type = SOCK_STREAM;
    }
    else if (protocol == 'u') // udp
    {
        type = SOCK_DGRAM;
    }
    else
    {
        return spawn_status::invalid_input;
    }
    int fds_stdout[2] = {-1, -1};
    int fds_stderr[2] = {-1, -1};
    if (::pipe(fds_stdout) == -1)
        return spawn_status::errno_pipe();
    if (::pipe(fds_stderr) == -1)
        return spawn_status::errno_pipe();
    pid_t const pid = fork();
    if (pid == -1)
    {
        return spawn_status::errno_fork();
    }
    else if (pid == 0)
    {
        for (size_t i = 0; i < GEPD::nfds; ++i)
        {
            if (::close(GEPD::fds[i].fd) == -1)
                ::_exit(spawn_status::errno_close());
        }
        if (::dup2(fds_stdout[1], 1) == -1)
            ::_exit(spawn_status::errno_dup());
        if (::close(fds_stdout[0]) == -1 || close(fds_stdout[1]) == -1)
            ::_exit(spawn_status::errno_close());
        if (::dup2(fds_stderr[1], 2) == -1)
            ::_exit(spawn_status::errno_dup());
        if (::close(fds_stderr[0]) == -1 || close(fds_stderr[1]) == -1)
            ::_exit(spawn_status::errno_close());

        char pid_message[1024];
        int pid_message_index = 0;
        unsigned long const pid_child = ::getpid();
        if (ei_encode_version(pid_message, &pid_message_index))
            ::_exit(GEPD::ExitStatus::ei_encode_error);
        if (ei_encode_tuple_header(pid_message, &pid_message_index, 2))
            ::_exit(GEPD::ExitStatus::ei_encode_error);
        if (ei_encode_atom(pid_message, &pid_message_index, "pid"))
            ::_exit(GEPD::ExitStatus::ei_encode_error);
        if (ei_encode_ulong(pid_message, &pid_message_index, pid_child))
            ::_exit(GEPD::ExitStatus::ei_encode_error);

        for (size_t i = 0; i < ports_len; ++i)
        {
            int sockfd = ::socket(AF_INET, type, 0);
            if (sockfd == -1)
                ::_exit(spawn_status::errno_socket());
            if (type == SOCK_STREAM)
            {
                int tcp_nodelay_flag = 1;
                // set TCP_NODELAY to turn off Nagle's algorithm
                if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
                               (char *) &tcp_nodelay_flag, sizeof(int)) == -1)
                    ::_exit(spawn_status::socket_unknown);
            }

            if (static_cast<size_t>(sockfd) != i + 3)
            {
                if (::dup2(sockfd, i + 3) == -1)
                    ::_exit(spawn_status::errno_dup());
                sockfd = i + 3;
            }
            
            struct sockaddr_in localhost;
            localhost.sin_family = AF_INET;
            localhost.sin_port = htons(ports[i]);
            localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

            if (::connect(sockfd,
                          reinterpret_cast<struct sockaddr *>(&localhost),
                          sizeof(localhost)) == -1)
                ::_exit(spawn_status::errno_connect());

            if (i == 0)
            {
                // let the first connection get a pid message for attempting
                // to kill the OS process when the Erlang process terminates
                if (::write(sockfd, pid_message, pid_message_index) == -1)
                    ::_exit(spawn_status::errno_write());
            }
        }

        int argv_count = 2;
        {
            assert(argv[argv_len - 1] == '\0');
            for (size_t i = 1; i < argv_len; ++i)
            {
                if (argv[i] == '\0')
                    ++argv_count;
            }
        }
        char * execve_argv[argv_count];
        {
            int index = 0;
            execve_argv[index++] = filename;
            if (argv_count == 2)
            {
                execve_argv[index++] = 0;
            }
            else
            {
                execve_argv[index++] = argv;
                for (size_t i = 0; i < argv_len - 1; ++i)
                {
                    if (argv[i] == '\0')
                        execve_argv[index++] = &(argv[i + 1]);
                }
                execve_argv[index++] = 0;
                assert(index == argv_count);
            }
        }

        int env_count = 1;
        {
            assert(env[env_len - 1] == '\0');
            for (size_t i = 1; i < env_len; ++i)
            {
                if (env[i] == '\0')
                    ++env_count;
            }
        }
        char * execve_env[env_count];
        {
            if (env_count == 1)
            {
                execve_env[0] = 0;
            }
            else
            {
                int index = 0;
                execve_env[index++] = env;
                for (size_t i = 0; i < env_len - 1; ++i)
                {
                    if (env[i] == '\0')
                        execve_env[index++] = &(env[i + 1]);
                }
                execve_env[index++] = 0;
                assert(index == env_count);
            }
        }

        ::execve(filename, execve_argv, execve_env);
        ::_exit(spawn_status::errno_exec());
    }
    else
    {
        if (::close(fds_stdout[1]) == -1)
            return spawn_status::errno_close();
        if (::close(fds_stderr[1]) == -1)
            return spawn_status::errno_close();

        if (GEPD::fds.reserve(GEPD::nfds + 2) == false)
            ::exit(spawn_status::out_of_memory);
        size_t const index_stdout = GEPD::nfds;
        size_t const index_stderr = GEPD::nfds + 1;
        GEPD::fds[index_stdout].fd = fds_stdout[0];
        GEPD::fds[index_stdout].events = POLLIN | POLLPRI;
        GEPD::fds[index_stdout].revents = 0;
        GEPD::fds[index_stderr].fd = fds_stderr[0];
        GEPD::fds[index_stderr].events = POLLIN | POLLPRI;
        GEPD::fds[index_stderr].revents = 0;
        GEPD::nfds += 2;

        copy_ptr<process_data> P(new process_data(pid,
                                                  index_stdout,
                                                  index_stderr));
        processes.push_back(P);
    }
    return pid;
}