Пример #1
0
// Get the particle set
int playerc_localize_get_particles(playerc_localize_t *device)
{
  int len;
  int i;
  player_localize_get_particles_t* req;

  assert(req = calloc(1,sizeof(player_localize_get_particles_t)));

  req->subtype = PLAYER_LOCALIZE_GET_PARTICLES_REQ;
    
  len = playerc_client_request(device->info.client, &device->info,
                               req, sizeof(req), req, 
                               sizeof(player_localize_get_particles_t));

  if (len < 0)
  {
    free(req);
    return -1;
  }

  // TODO: better length checking here

  // byteswap
  device->mean[0] = ((int32_t)ntohl(req->mean[0])) / 1e3;
  device->mean[1] = ((int32_t)ntohl(req->mean[1])) / 1e3;
  device->mean[2] = (((int32_t)ntohl(req->mean[2])) / 3600.0) * M_PI/180.0;

  device->variance = ((uint64_t)ntohll(req->variance)) / (1e3 * 1e3);

  device->num_particles = (int32_t)ntohl(req->num_particles);

  for(i=0;i<device->num_particles;i++)
  {
    if(i >= PLAYER_LOCALIZE_PARTICLES_MAX)
    {
      device->num_particles = i;
      PLAYERC_WARN("too many particles");
      break;
    }

    device->particles[i].pose[0] = 
            ((int32_t)ntohl(req->particles[i].pose[0])) / 1e3;
    device->particles[i].pose[1] = 
            ((int32_t)ntohl(req->particles[i].pose[1])) / 1e3;
    device->particles[i].pose[2] = 
            (((int32_t)ntohl(req->particles[i].pose[2])) / 3600.0) * 
            M_PI / 180.0;
    device->particles[i].weight = 
            ((uint32_t)ntohl(req->particles[i].alpha)) / 1e6;
  }

  free(req);

  return 0;
}
Пример #2
0
// Test to see if there is pending data. Don't send a data request.
int playerc_client_internal_peek(playerc_client_t *client, int timeout)
{
  int count;
  struct pollfd fd;

  if (client->sock < 0)
  {
    PLAYERC_WARN("no socket to peek at");
    return -1;
  }

  fd.fd = client->sock;
  //fd.events = POLLIN | POLLHUP;
  fd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
  fd.revents = 0;

  // Wait for incoming data
  count = poll(&fd, 1, timeout);
  if (count < 0)
  {
    if(errno == EINTR)
      return(0);
    else
    {
      PLAYERC_ERR1("poll returned error [%s]", strerror(errno));
      //playerc_client_disconnect(client);
      return(playerc_client_disconnect_retry(client));
    }
  }
  if (count > 0 && (fd.revents & POLLHUP))
  {
    PLAYERC_ERR("socket disconnected");
    //playerc_client_disconnect(client);
    return(playerc_client_disconnect_retry(client));
  }
  return count;
}
Пример #3
0
// Read and process a packet (nonblocking), fills in pointer to proxy that got data
// returns 0 if no data recieved, 1 if data recieved and -1 on error
int playerc_client_read_nonblock_withproxy(playerc_client_t *client, void ** proxy)
{
  player_msghdr_t header;
  int ret;

  while (true)
  {
    // See if there is any queued data.
    if (playerc_client_pop (client, &header, client->data) < 0)
    {
      // If there is no queued data, peek at the socket
      if((ret = playerc_client_internal_peek(client,0)) <= 0)
      {
        // If we haven't requested sata there will be no SYNCH message to wait further for, thus if we have got data from the internal queue this time
        // We need to return true
        if (!client->data_requested && client->data_received)
        {
          client->data_received = 0;
          if (proxy)
            *proxy = client->id;
          return 1;
        }
        else
          return 0;
      }
      // There's data on the socket, so read a packet (blocking).
      if((ret = playerc_client_readpacket (client, &header, client->data)) < 0)
        return ret;
    }
    // One way or another, we got a new packet into (header,client->data),
    // so process it
    switch(header.type)
    {
      case PLAYER_MSGTYPE_RESP_ACK:
        PLAYERC_WARN ("Discarding unclaimed ACK");
        playerxdr_cleanup_message(client->data, header.addr.interf, header.type, header.subtype);
        break;
      case PLAYER_MSGTYPE_SYNCH:
        client->data_requested = 0;
        if (header.subtype == PLAYER_PLAYER_SYNCH_OVERFLOW)
        {
          client->overflow_count += *((uint32_t*)client->data);
        }
        if(!client->data_received)
        {
          PLAYERC_WARN ("No data recieved with SYNC");
          ret = -1;
        }
        else
        {
          if (proxy)
            *proxy = client->id;
          ret = 1;
        }
        playerxdr_cleanup_message(client->data, header.addr.interf, header.type, header.subtype);
        return ret;
      case PLAYER_MSGTYPE_DATA:
        client->lasttime = client->datatime;
        client->datatime = header.timestamp;
        if (client->mode == PLAYER_DATAMODE_PUSH)
        {
          // If in push mode, handle and return
          void *result = playerc_client_dispatch (client, &header, client->data);
          // Need to ensure that any dynamic data made during unpacking is cleaned up
          playerxdr_cleanup_message(client->data, header.addr.interf, header.type, header.subtype);
          if (proxy)
            *proxy = result;
          return 1;
        }
        else  // PULL mode, so keep on going
        {
          void *result = playerc_client_dispatch (client, &header, client->data);
          playerxdr_cleanup_message(client->data, header.addr.interf, header.type, header.subtype);
          client->data_received = 1;
          if (result == NULL)
          {
          	PLAYERC_WARN1 ("Failed to dispatch data message: subtype %d", header.subtype);
            printf("address: %u:%u:%s:%u\nsize: %u",
                   header.addr.host,
                   header.addr.robot,
                   interf_to_str(header.addr.interf),
                   header.addr.index,
                   header.size);
            return -1;
          }
          break;
        }
      default:
        playerxdr_cleanup_message(client->data, header.addr.interf, header.type, header.subtype);
        PLAYERC_WARN1 ("unexpected message type [%s]", msgtype_to_str(header.type));
        PLAYERC_WARN5 ("address: %u:%u:%s:%u\nsize: %u",
               header.addr.host,
               header.addr.robot,
               interf_to_str(header.addr.interf),
               header.addr.index,
               header.size);
        return -1;
    }
  }
}
Пример #4
0
// Disconnect from the server, with potential retry
int playerc_client_disconnect_retry(playerc_client_t *client)
{
  int retval;
  int i;
  int j;
  struct timespec sleeptime;

  sleeptime.tv_sec = (long) client->retry_time;
  sleeptime.tv_nsec = 0;

  /* Disconnect */
  if((retval = playerc_client_disconnect(client)) != 0)
    PLAYERC_WARN("playerc_client_disconnect() failed");

  for(j=0; (client->retry_limit < 0) || (j<client->retry_limit); j++)
  {
    PLAYERC_WARN1("Reconnecting, attempt %d", j);
    /* Reconnect */
    if((retval = playerc_client_connect(client)) != 0)
      PLAYERC_WARN("playerc_client_connect() failed");
    else
    {
      /* Clean out buffers */
      client->read_xdrdata_len = 0;

      /* TODO: re-establish replacement rules, delivery modes, etc. */

      /* Re-subscribe to devices */
      for(i=0;i<client->device_count;i++)
      {
        if(client->device[i]->subscribed)
        {
          // TODO: what should access be here?
          if((retval = playerc_device_subscribe(client->device[i],
                                                PLAYERC_OPEN_MODE)) != 0)
          {
            PLAYERC_WARN2("playerc_device_subscribe() failed for %d:%d",
                         client->device[i]->addr.interf,
                         client->device[i]->addr.index);

            // TODO: Subscription failed for one device; should we give up?
            if(playerc_client_disconnect(client) != 0)
              PLAYERC_WARN("playerc_client_disconnect() failed");
            break;
          }
        }
      }
      // Did we get all of them?
      if(i == client->device_count)
        break;
    }

    nanosleep(&sleeptime,NULL);
  }

  if((client->retry_limit < 0) || (j < client->retry_limit))
  {
    PLAYERC_WARN("successfully reconnected");
    return(0);
  }
  else
  {
    PLAYERC_WARN("failed to reconnect");
    return(-1);
  }
}
Пример #5
0
// Connect to the server
int playerc_client_connect(playerc_client_t *client)
{
#if defined(HAVE_GETADDRINFO)
  struct addrinfo* addr_ptr = NULL;
#else
  struct hostent* entp = NULL;
#endif
  char banner[PLAYER_IDENT_STRLEN];
  int ret;
  //double t;
  /*
  struct timeval last;
  struct timeval curr;
  */
#if defined (WIN32)
  unsigned long setting = 0;
#else
  int old_flags;
  struct itimerval timer;
  struct sigaction sigact;
#endif
  struct sockaddr_in clientaddr;

  // Construct socket
  if(client->transport == PLAYERC_TRANSPORT_UDP)
  {
#if defined (WIN32)
    if((client->sock = socket(PF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
#else
    if((client->sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
#endif
    {
      STRERROR(PLAYERC_ERR2, "socket() failed with error [%d: %s]");
      return -1;
    }
    /*
     * INADDR_ANY indicates that any network interface (IP address)
     * for the local host may be used (presumably the OS will choose the
     * right one).
     *
     * Specifying sin_port = 0 allows the system to choose the port.
     */
    clientaddr.sin_family = AF_INET;
    clientaddr.sin_addr.s_addr = INADDR_ANY;
    clientaddr.sin_port = 0;

    if(bind(client->sock,
            (struct sockaddr*)&clientaddr, sizeof(clientaddr)) < -1)
    {
      STRERROR(PLAYERC_ERR2, "bind() failed with error [%d: %s]");
      return -1;
    }
  }
  else
  {
#if defined (WIN32)
    if((client->sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
#else
    if((client->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
#endif
    {
      STRERROR(PLAYERC_ERR2, "socket() failed with error [%d: %s]");
      return -1;
    }
  }

#if ENABLE_TCP_NODELAY
  // Disable Nagel's algorithm for lower latency
  {
    int yes = 1;
    if(setsockopt(client->sock, IPPROTO_TCP, TCP_NODELAY, &yes,
                  sizeof(int)) == -1)
    {
      PLAYERC_ERR("failed to enable TCP_NODELAY - setsockopt failed");
      return -1;
    }
  }
#endif

  // Construct server address
  memset(&client->server, 0, sizeof(client->server));
  client->server.sin_family = AF_INET;
  client->server.sin_port = htons(client->port);
#if defined(HAVE_GETADDRINFO)
  if (getaddrinfo(client->host, NULL, NULL, &addr_ptr) != 0)
  {
    playerc_client_disconnect(client);
    PLAYERC_ERR("getaddrinfo() failed with error");
    return -1;
  }
  assert(addr_ptr);
  assert(addr_ptr->ai_addr);
#ifdef AF_INET6
  if (((addr_ptr->ai_addr->sa_family) != AF_INET) &&
      ((addr_ptr->ai_addr->sa_family) != AF_INET6))
#else
  if ((addr_ptr->ai_addr->sa_family) != AF_INET)
#endif
  {
    playerc_client_disconnect(client);
    PLAYERC_ERR("unsupported internet address family");
    return -1;
  }
  client->server.sin_addr.s_addr = ((struct sockaddr_in *)(addr_ptr->ai_addr))->sin_addr.s_addr;
  freeaddrinfo(addr_ptr);
  addr_ptr = NULL;
#else
  entp = gethostbyname(client->host);
  if (entp == NULL)
  {
    playerc_client_disconnect(client);
    STRERROR(PLAYERC_ERR2, "gethostbyname() failed with error [%d: %s]");
    return -1;
  }
  assert(entp->h_length <= sizeof (client->server.sin_addr));
  memcpy(&(client->server.sin_addr), entp->h_addr_list[0], entp->h_length);
#endif
  // Connect the socket
  /*
  t = client->request_timeout;
  do
  {
    if (t <= 0)
    {
      PLAYERC_ERR2("connect call on [%s:%d] timed out",
                   client->host, client->port);
      return -1;
    }
    gettimeofday(&last,NULL);
    puts("calling connect");
    ret = connect(client->sock, (struct sockaddr*)&client->server,
                  sizeof(client->server));
    gettimeofday(&curr,NULL);
    t -= ((curr.tv_sec + curr.tv_usec/1e6) -
          (last.tv_sec + last.tv_usec/1e6));
  } while (ret == -1 && (errno == EALREADY || errno == EAGAIN || errno == EINPROGRESS));
  */

  // In Windows, the connect timeout is (apparently) a registry setting.
#if !defined (WIN32)
  /* Set up a timer to interrupt the connection process */
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = 0;
  timer.it_value.tv_sec = (int)floor(client->request_timeout);
  timer.it_value.tv_usec =
          (int)rint(fmod(client->request_timeout,timer.it_value.tv_sec)*1e6);
  if(setitimer(ITIMER_REAL, &timer, NULL) != 0)
    PLAYERC_WARN("failed to set up connection timer; "
                "indefinite hang may result");

  /* Turn off system call restart so that connect() will terminate when the
   * alarm goes off */
  if(sigaction(SIGALRM, NULL, &sigact) != 0)
    PLAYERC_WARN("failed to get SIGALRM action data; "
                "unexpected exit may result");
  else
  {
#ifdef SA_RESTART
    sigact.sa_handler = dummy;
    sigact.sa_flags &= ~SA_RESTART;
    if(sigaction(SIGALRM, &sigact, NULL) != 0)
#endif
      PLAYERC_WARN("failed to set SIGALRM action data; "
                  "unexpected exit may result");
  }
#endif

  ret = connect(client->sock, (struct sockaddr*)&client->server,
                sizeof(client->server));

#if !defined (WIN32)
  /* Turn off timer */
  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = 0;
  if(setitimer(ITIMER_REAL, &timer, NULL) != 0)
    PLAYERC_WARN("failed to turn off connection timer; "
                "unexpected exit may result");

  /* Restore normal SIGALRM behavior */
#ifdef SA_RESTART
  sigact.sa_handler = SIG_DFL;
  sigact.sa_flags |= SA_RESTART;
  if(sigaction(SIGALRM, &sigact, NULL) != 0)
#endif
    PLAYERC_WARN("failed to reset SIGALRM action data; "
                "unexpected behavior may result");
#endif

  if (ret < 0)
  {
    playerc_client_disconnect(client);
#if defined (WIN32)
    FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                   ErrNo, 0, (LPTSTR) &errBuffer, 0, NULL);
    PLAYERC_ERR4 ("connect call on [%s:%d] failed with error [%d:%s]",
                 client->host, client->port, ErrNo, (LPTSTR) errBuffer);
    LocalFree (errBuffer);
#else
    PLAYERC_ERR4("connect call on [%s:%d] failed with error [%d:%s]",
                 client->host, client->port, errno, strerror(ErrNo));
#endif
    return -1;
  }

  // For UDP, send an empty msg to get things going
  if(client->transport == PLAYERC_TRANSPORT_UDP)
  {
    if(send(client->sock, NULL, 0, 0) < 0)
    {
      STRERROR(PLAYERC_ERR2, "send() failed with error [%d: %s]");
      return -1;
    }
  }

  // set socket to be blocking
#if defined (WIN32)
  if (ioctlsocket (client->sock, FIONBIO, &setting) == SOCKET_ERROR)
  {
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                   ErrNo, 0, (LPTSTR) &errBuffer, 0, NULL);
    PLAYERC_ERR1("error getting socket flags [%s]", (LPTSTR) errBuffer);
    LocalFree(errBuffer);
  }
#else
  if ((old_flags = fcntl(client->sock, F_GETFL)) < 0)
  {
    PLAYERC_ERR1("error getting socket flags [%s]", strerror(errno));
    return -1;
  }
  if (fcntl(client->sock, F_SETFL, old_flags & ~O_NONBLOCK) < 0)
  {
    PLAYERC_ERR1("error setting socket non-blocking [%s]", strerror(errno));
    return -1;
  }
#endif


  // Get the banner
  if (timed_recv(client->sock, banner, sizeof(banner), 0, 2000) < sizeof(banner))
  {
    playerc_client_disconnect(client);
    PLAYERC_ERR("incomplete initialization string");
    return -1;
  }

  //set the datamode to pull
  playerc_client_datamode(client, PLAYER_DATAMODE_PULL);

  PLAYERC_WARN4("[%s] connected on [%s:%d] with sock %d\n", banner, client->host, client->port, client->sock);

  client->connected = 1;
  return 0;
}
Пример #6
0
// Write a raw packet
int playerc_client_writepacket(playerc_client_t *client,
                               player_msghdr_t *header, const char *data)
{
  int bytes, ret, length;
  player_pack_fn_t packfunc;
  int encode_msglen;
  struct timeval curr;

  if (client->sock < 0)
  {
    PLAYERC_WARN("no socket to write to");
    return -1;
  }

  // Encode the body first, if it's non-NULL
  if(data)
  {
    // Locate the appropriate packing function for the message body
    if(!(packfunc = playerxdr_get_packfunc(header->addr.interf,
                                       header->type,
                                       header->subtype)))
    {
      // TODO: Allow the user to register a callback to handle unsupported
      // messages
      PLAYERC_ERR4("skipping message to %s:%u with unsupported type %s:%u",
                   interf_to_str(header->addr.interf), header->addr.index, msgtype_to_str(header->type), header->subtype);
      return(-1);
    }

    if((encode_msglen =
        (*packfunc)(client->write_xdrdata + PLAYERXDR_MSGHDR_SIZE,
                    PLAYER_MAX_MESSAGE_SIZE - PLAYERXDR_MSGHDR_SIZE,
                    (void*) data, PLAYERXDR_ENCODE)) < 0)
    {
      PLAYERC_ERR4("encoding failed on message from %s:%u with type %s:%u",
                   interf_to_str(header->addr.interf), header->addr.index, msgtype_to_str(header->type), header->subtype);
      return(-1);
    }
  }
  else
    encode_msglen = 0;

  // Write in the encoded size and current time
  header->size = encode_msglen;
  gettimeofday(&curr,NULL);
  header->timestamp = curr.tv_sec + curr.tv_usec / 1e6;
  // Pack the header
  if(player_msghdr_pack(client->write_xdrdata, PLAYERXDR_MSGHDR_SIZE,
                        header, PLAYERXDR_ENCODE) < 0)
  {
    PLAYERC_ERR("failed to pack header");
    return -1;
  }

  // Send the message
  length = PLAYERXDR_MSGHDR_SIZE + encode_msglen;
  bytes = PLAYERXDR_MSGHDR_SIZE + encode_msglen;
  do
  {
    ret = send(client->sock, &client->write_xdrdata[length-bytes],
               bytes, 0);
    if (ret > 0)
    {
      bytes -= ret;
    }
#if defined (WIN32)
    else if (ret < 0 && (errno != ERRNO_EAGAIN && errno != WSAEINPROGRESS))
#else
    else if (ret < 0 && (errno != ERRNO_EAGAIN && errno != EINPROGRESS && errno != EWOULDBLOCK))
#endif
    {
      STRERROR (PLAYERC_ERR2, "send on body failed with error [%d: %s]");
      //playerc_client_disconnect(client);
      return(playerc_client_disconnect_retry(client));
    }
  } while (bytes);

  return 0;
}
Пример #7
0
// Read a raw packet
int playerc_client_readpacket(playerc_client_t *client,
                              player_msghdr_t *header,
                              char *data)
{
  int nbytes;
  player_pack_fn_t packfunc;
  int decode_msglen;

  if (client->sock < 0)
  {
    PLAYERC_WARN("no socket to read from");
    return -1;
  }

  while(client->read_xdrdata_len < PLAYERXDR_MSGHDR_SIZE)
  {
    nbytes = timed_recv(client->sock,
                        client->read_xdrdata + client->read_xdrdata_len,
                        PLAYERXDR_MSGHDR_SIZE - client->read_xdrdata_len,
                        0, (int) client->request_timeout * 1000);
    if (nbytes <= 0)
    {
      if(nbytes == 0)
        return -1;
      if(errno == EINTR)
        continue;
      else
      {
        STRERROR (PLAYERC_ERR2, "recv failed with error [%d: %s]");
        //playerc_client_disconnect(client);
        if(playerc_client_disconnect_retry(client) < 0)
          return(-1);
        else
          continue;
      }
    }
    client->read_xdrdata_len += nbytes;
  }

  // Unpack the header
  if(player_msghdr_pack(client->read_xdrdata,
                        PLAYERXDR_MSGHDR_SIZE,
                        header, PLAYERXDR_DECODE) < 0)
  {
    PLAYERC_ERR("failed to unpack header");
    return -1;
  }
  if (header->size > PLAYERXDR_MAX_MESSAGE_SIZE - PLAYERXDR_MSGHDR_SIZE)
  {
    PLAYERC_WARN1("packet is too large, %d bytes", header->size);
  }

  // Slide over the header
  memmove(client->read_xdrdata,
          client->read_xdrdata + PLAYERXDR_MSGHDR_SIZE,
          client->read_xdrdata_len - PLAYERXDR_MSGHDR_SIZE);
  client->read_xdrdata_len -= PLAYERXDR_MSGHDR_SIZE;

  while(client->read_xdrdata_len < header->size)
  {
    nbytes = timed_recv(client->sock,
                        client->read_xdrdata + client->read_xdrdata_len,
                        header->size - client->read_xdrdata_len,
                        0, (int) client->request_timeout*1000);
    if (nbytes <= 0)
    {
      if(errno == EINTR)
        continue;
      {
        STRERROR (PLAYERC_ERR2, "recv failed with error [%d: %s]");
        //playerc_client_disconnect(client);
        if(playerc_client_disconnect_retry(client) < 0)
          return(-1);
        else
        {
          /* Need to start over; the easiest way is to recursively call
           * myself.  Might be problematic... */
          return(playerc_client_readpacket(client,header,data));
        }
      }
    }
    client->read_xdrdata_len += nbytes;
  }

  if (header->size)
  {
  // Locate the appropriate unpacking function for the message body
    if(!(packfunc = playerxdr_get_packfunc(header->addr.interf, header->type,
                                         header->subtype)))
    {
      // TODO: Allow the user to register a callback to handle unsupported
      // messages
      PLAYERC_ERR4("skipping message from %s:%u with unsupported type %s:%u",
                 interf_to_str(header->addr.interf), header->addr.index, msgtype_to_str(header->type), header->subtype);

      // Slide over the body
      memmove(client->read_xdrdata,
            client->read_xdrdata + header->size,
            client->read_xdrdata_len - header->size);
      client->read_xdrdata_len -= header->size;

      return(-1);
    }

    // Unpack the body
    if((decode_msglen = (*packfunc)(client->read_xdrdata,
                                  header->size, data, PLAYERXDR_DECODE)) < 0)
    {
      PLAYERC_ERR4("decoding failed on message from %s:%u with type %s:%u",
                 interf_to_str(header->addr.interf), header->addr.index, msgtype_to_str(header->type), header->subtype);
      return(-1);
    }
  }
  else
  {
    decode_msglen = 0;
  }
  // Slide over the body
  memmove(client->read_xdrdata,
          client->read_xdrdata + header->size,
          client->read_xdrdata_len - header->size);
  client->read_xdrdata_len -= header->size;

  // Rewrite the header with the decoded message length
  header->size = decode_msglen;

  return 0;
}