Exemplo n.º 1
0
/*
 *  Discovery thread
 */
static void *
upnp_thread( void *aux )
{
  char *bindaddr = aux;
  tvhpoll_t *poll = tvhpoll_create(2);
  tvhpoll_event_t ev[2];
  upnp_data_t *data;
  udp_connection_t *multicast = NULL, *unicast = NULL;
  udp_connection_t *conn;
  unsigned char buf[16384];
  upnp_service_t *us;
  struct sockaddr_storage ip;
  socklen_t iplen;
  size_t size;
  int r, delay_ms;

  multicast = udp_bind(LS_UPNP, "upnp_thread_multicast",
                       "239.255.255.250", 1900, NULL,
                       NULL, 32*1024, 32*1024);
  if (multicast == NULL || multicast == UDP_FATAL_ERROR)
    goto error;
  unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL,
                     NULL, 32*1024, 32*1024);
  if (unicast == NULL || unicast == UDP_FATAL_ERROR)
    goto error;

  memset(&ev, 0, sizeof(ev));
  ev[0].fd     = multicast->fd;
  ev[0].events = TVHPOLL_IN;
  ev[0].ptr    = multicast;
  ev[1].fd     = unicast->fd;
  ev[1].events = TVHPOLL_IN;
  ev[1].ptr    = unicast;
  tvhpoll_add(poll, ev, 2);

  delay_ms = 0;

  while (atomic_get(&upnp_running) && multicast->fd >= 0) {
    r = tvhpoll_wait(poll, ev, 2, delay_ms ?: 1000);
    if (r == 0) /* timeout */
      delay_ms = 0;

    while (r-- > 0) {
      if ((ev[r].events & TVHPOLL_IN) != 0) {
        conn = ev[r].ptr;
        iplen = sizeof(ip);
        size = recvfrom(conn->fd, buf, sizeof(buf), 0,
                                           (struct sockaddr *)&ip, &iplen);
        if (size > 0 && tvhtrace_enabled()) {
          char tbuf[256];
          inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf));
          tvhtrace(LS_UPNP, "%s - received data from %s:%hu [size=%zi]",
                   conn == multicast ? "multicast" : "unicast",
                   tbuf, (unsigned short) ntohs(IP_PORT(ip)), size);
          tvhlog_hexdump(LS_UPNP, buf, size);
        }
        /* TODO: a filter */
        TAILQ_FOREACH(us, &upnp_services, us_link)
          us->us_received(buf, size, conn, &ip);
      }
    }

    while (delay_ms == 0) {
      tvh_mutex_lock(&upnp_lock);
      data = TAILQ_FIRST(&upnp_data_write);
      if (data) {
        delay_ms = data->delay_ms;
        data->delay_ms = 0;
        if (!delay_ms) {
          TAILQ_REMOVE(&upnp_data_write, data, data_link);
        } else {
          data = NULL;
        }
      }
      tvh_mutex_unlock(&upnp_lock);
      if (data == NULL)
        break;
      upnp_dump_data(data);
      udp_write_queue(data->from_multicast ? multicast : unicast,
                      &data->queue, &data->storage);
      htsbuf_queue_flush(&data->queue);
      free(data);
      delay_ms = 0;
    }
  }

  /* flush the write queue (byebye messages) */
  while (1) {
    tvh_mutex_lock(&upnp_lock);
    data = TAILQ_FIRST(&upnp_data_write);
    if (data)
      TAILQ_REMOVE(&upnp_data_write, data, data_link);
    tvh_mutex_unlock(&upnp_lock);
    if (data == NULL)
      break;
    tvh_safe_usleep((long)data->delay_ms * 1000);
    upnp_dump_data(data);
    udp_write_queue(unicast, &data->queue, &data->storage);
    htsbuf_queue_flush(&data->queue);
    free(data);
  }

error:
  atomic_set(&upnp_running, 0);
  tvhpoll_destroy(poll);
  udp_close(unicast);
  udp_close(multicast);
  return NULL;
}
Exemplo n.º 2
0
/*
 *  Discovery thread
 */
static void *
upnp_thread( void *aux )
{
  char *bindaddr = aux;
  tvhpoll_t *poll = tvhpoll_create(2);
  tvhpoll_event_t ev[2];
  upnp_data_t *data;
  udp_connection_t *multicast = NULL, *unicast = NULL;
  udp_connection_t *conn;
  unsigned char buf[16384];
  upnp_service_t *us;
  struct sockaddr_storage ip;
  socklen_t iplen;
  size_t size;
  int r;

  multicast = udp_bind("upnp", "upnp_thread_multicast",
                       "239.255.255.250", 1900,
                       NULL, 32*1024);
  if (multicast == NULL || multicast == UDP_FATAL_ERROR)
    goto error;
  unicast = udp_bind("upnp", "upnp_thread_unicast", bindaddr, 0,
                     NULL, 32*1024);
  if (unicast == NULL || unicast == UDP_FATAL_ERROR)
    goto error;

  memset(&ev, 0, sizeof(ev));
  ev[0].fd       = multicast->fd;
  ev[0].events   = TVHPOLL_IN;
  ev[0].data.ptr = multicast;
  ev[1].fd       = unicast->fd;
  ev[1].events   = TVHPOLL_IN;
  ev[1].data.ptr = unicast;
  tvhpoll_add(poll, ev, 2);

  while (upnp_running && multicast->fd >= 0) {
    r = tvhpoll_wait(poll, ev, 2, 1000);

    while (r-- > 0) {
      if ((ev[r].events & TVHPOLL_IN) != 0) {
        conn = ev[r].data.ptr;
        iplen = sizeof(ip);
        size = recvfrom(conn->fd, buf, sizeof(buf), 0,
                                           (struct sockaddr *)&ip, &iplen);
#if ENABLE_TRACE
        if (size > 0) {
          char tbuf[256];
          inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf));
          tvhtrace("upnp", "%s - received data from %s:%hu [size=%zi]",
                   conn == multicast ? "multicast" : "unicast",
                   tbuf, (unsigned short) IP_PORT(ip), size);
          tvhlog_hexdump("upnp", buf, size);
        }
#endif
        /* TODO: a filter */
        TAILQ_FOREACH(us, &upnp_services, us_link)
          us->us_received(buf, size, conn, &ip);
      }
    }

    while (1) {
      pthread_mutex_lock(&upnp_lock);
      data = TAILQ_FIRST(&upnp_data_write);
      if (data)
        TAILQ_REMOVE(&upnp_data_write, data, data_link);
      pthread_mutex_unlock(&upnp_lock);
      if (data == NULL)
        break;
      udp_write_queue(unicast, &data->queue, &data->storage);
      htsbuf_queue_flush(&data->queue);
      free(data);
    }
  }

error:
  upnp_running = 0;
  tvhpoll_destroy(poll);
  udp_close(unicast);
  udp_close(multicast);
  return NULL;
}