Exemplo n.º 1
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;
}
Exemplo n.º 2
0
Arquivo: send.c Projeto: Dasudian/otp
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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
Arquivo: send_reg.c Projeto: HansN/otp
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;
}
Exemplo n.º 6
0
int my_encode_tuple_header(char *buf, int *index, struct my_obj* obj)
{
    return ei_encode_tuple_header(buf, index, obj->u.arity);
}
/*!
 * 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++;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
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);
}
Exemplo n.º 10
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);
};
Exemplo n.º 11
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;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
//Write the current contents of the values list to disk as a node
//and add the resulting pointer to the pointers list.
int flush_mr(couchfile_modify_result *res)
{
    int nbufpos = 0;
    long long subtreesize = 0;
    eterm_buf reduce_value;
    //default reduce value []
    reduce_value.buf = "\x6A"; //NIL_EXT
    reduce_value.size = 1;
    int reduced = 0;
    int errcode = 0;

    if(res->values_end == res->values || !res->modified)
    {
        //Empty
        return 0;
    }

    res->node_len += 19; //tuple header and node type tuple, list header and tail
    nif_writerq *wrq = nif_writerq_alloc(res->node_len);
    char *nodebuf = wrq->buf;

    //External term header; tuple header arity 2;
    ei_encode_version(nodebuf, &nbufpos);
    ei_encode_tuple_header(nodebuf, &nbufpos, 2);
    switch(res->node_type)
    {
        case KV_NODE:
            ei_encode_atom_len(nodebuf, &nbufpos, "kv_node", 7);
            if(res->rq->reduce)
            {
                (*res->rq->reduce)(&reduce_value, res->values->next, res->count);
                reduced = 1;
            }
        break;
        case KP_NODE:
            ei_encode_atom_len(nodebuf, &nbufpos, "kp_node", 7);
            if(res->rq->rereduce)
            {
                (*res->rq->rereduce)(&reduce_value, res->values->next, res->count);
                reduced = 1;
            }
        break;
    }

    ei_encode_list_header(nodebuf, &nbufpos, res->count);

    nodelist* i = res->values->next;

    eterm_buf last_key;
    while(i != NULL)
    {
        if(res->node_type == KV_NODE) //writing value in a kv_node
        {
            append_buf(nodebuf, &nbufpos, i->value.leaf->term.buf, i->value.leaf->term.size);
            if(i->next == NULL)
            {
                int pos = 0;
                term_to_buf(&last_key, i->value.leaf->term.buf+2, &pos);
            }
        }
        else if (res->node_type == KP_NODE) //writing value in a kp_node
        {
            if(wait_pointer(res->rq, i->value.pointer) < 0)
            {
                errcode = ERROR_WRITER_DEAD;
                goto cleanup;
            }
            subtreesize += i->value.pointer->subtreesize;
            ei_encode_tuple_header(nodebuf, &nbufpos, 2); //tuple arity 2
            append_buf(nodebuf, &nbufpos, i->value.pointer->key.buf, i->value.pointer->key.size);
            ei_encode_tuple_header(nodebuf, &nbufpos, 3); //tuple arity 3
            //pointer
            // v- between 2 and 10 bytes (ERL_SMALL_INTEGER_EXT to ERL_SMALL_BIG_EXT/8)
            ei_encode_ulonglong(nodebuf, &nbufpos, i->value.pointer->pointer);
            //reduce_value
            append_buf(nodebuf, &nbufpos, i->value.pointer->reduce_value.buf,
                    i->value.pointer->reduce_value.size);
            //subtreesize
            // v- between 2 and 10 bytes (ERL_SMALL_INTEGER_EXT to ERL_SMALL_BIG_EXT/8)
            ei_encode_ulonglong(nodebuf, &nbufpos, i->value.pointer->subtreesize);
            if(i->next == NULL)
            {
                last_key = i->value.pointer->key;
            }
        }
        i = i->next;
    }

    //NIL_EXT (list tail)
    ei_encode_empty_list(nodebuf, &nbufpos);

    couchfile_pointer_info* ptr = malloc(sizeof(couchfile_pointer_info) +
            last_key.size + reduce_value.size);

    ptr->pointer = 0;

    nif_write(res->rq, ptr, wrq, nbufpos);

    ptr->key.buf = ((char*)ptr) + sizeof(couchfile_pointer_info);
    ptr->reduce_value.buf = ((char*)ptr) + sizeof(couchfile_pointer_info) + last_key.size;

    ptr->key.size = last_key.size;
    ptr->reduce_value.size = reduce_value.size;

    memcpy(ptr->key.buf, last_key.buf, last_key.size);
    memcpy(ptr->reduce_value.buf, reduce_value.buf, reduce_value.size);

    ptr->subtreesize = subtreesize;

    nodelist* pel = make_nodelist();
    pel->value.pointer = ptr;
    res->pointers_end->next = pel;
    res->pointers_end = pel;

    res->node_len = 0;
    res->count = 0;

    res->values_end = res->values;
    free_nodelist(res->values->next);
    res->values->next = NULL;
cleanup:

    if(errcode < 0)
    {
        enif_release_resource(wrq);
    }

    if(reduced)
    {
        free(reduce_value.buf);
    }
    return errcode;
}