Esempio n. 1
0
void rtsp_listen_loop(void) {
    struct addrinfo hints, *info, *p;
    char portstr[6];
    int *sockfd = NULL;
    int nsock = 0;
    int i, ret;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    snprintf(portstr, 6, "%d", config.port);

    ret = getaddrinfo(NULL, portstr, &hints, &info);
    if (ret) {
        die("getaddrinfo failed: %s", gai_strerror(ret));
    }

    for (p=info; p; p=p->ai_next) {
        int fd = socket(p->ai_family, p->ai_socktype, IPPROTO_TCP);
        int yes = 1;

        ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

#ifdef IPV6_V6ONLY
        // some systems don't support v4 access on v6 sockets, but some do.
        // since we need to account for two sockets we might as well
        // always.
        if (p->ai_family == AF_INET6)
            ret |= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes));
#endif

        if (!ret)
            ret = bind(fd, p->ai_addr, p->ai_addrlen);

        // one of the address families will fail on some systems that
        // report its availability. do not complain.
        if (ret) {
            debug(1, "Failed to bind to address %s\n", format_address(p->ai_addr));
            continue;
        }
        debug(1, "Bound to address %s\n", format_address(p->ai_addr));

        listen(fd, 5);
        nsock++;
        sockfd = realloc(sockfd, nsock*sizeof(int));
        sockfd[nsock-1] = fd;
    }

    freeaddrinfo(info);

    if (!nsock)
        die("could not bind any listen sockets!");


    int maxfd = -1;
    fd_set fds;
    FD_ZERO(&fds);
    for (i=0; i<nsock; i++) {
        if (sockfd[i] > maxfd)
            maxfd = sockfd[i];
    }

    mdns_register();

    printf("Listening for connections.\n");
    shairport_startup_complete();

    int acceptfd;
    struct timeval tv;
    while (1) {
        tv.tv_sec = 300;
        tv.tv_usec = 0;

        for (i=0; i<nsock; i++)
            FD_SET(sockfd[i], &fds);

        ret = select(maxfd+1, &fds, 0, 0, &tv);
        if (ret<0) {
            if (errno==EINTR)
                continue;
            break;
        }

        cleanup_threads();

        acceptfd = -1;
        for (i=0; i<nsock; i++) {
            if (FD_ISSET(sockfd[i], &fds)) {
                acceptfd = sockfd[i];
                break;
            }
        }
        if (acceptfd < 0) // timeout
            continue;

        rtsp_conn_info *conn = malloc(sizeof(rtsp_conn_info));
        memset(conn, 0, sizeof(rtsp_conn_info));
        socklen_t slen = sizeof(conn->remote);

        debug(1, "new RTSP connection\n");
        conn->fd = accept(acceptfd, (struct sockaddr *)&conn->remote, &slen);
        if (conn->fd < 0) {
            perror("failed to accept connection");
            free(conn);
        } else {
            pthread_t rtsp_conversation_thread;
            ret = pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn);
            if (ret)
                die("Failed to create RTSP receiver thread!");

            conn->thread = rtsp_conversation_thread;
            conn->running = 1;
            track_thread(conn);
        }
    }
    perror("select");
    die("fell out of the RTSP select loop");
}
Esempio n. 2
0
static int
register_services(char *ffid, int no_rsp, int no_daap)
{
  cfg_t *lib;
  char *libname;
  char *password;
  char *txtrecord[10];
  char records[9][128];
  int port;
  uint32_t hash;
  int i;
  int ret;

  srand((unsigned int)time(NULL));

  lib = cfg_getsec(cfg, "library");

  libname = cfg_getstr(lib, "name");
  hash = djb_hash(libname, strlen(libname));

  for (i = 0; i < (sizeof(records) / sizeof(records[0])); i++)
    {
      memset(records[i], 0, 128);
      txtrecord[i] = records[i];
    }

  txtrecord[9] = NULL;

  snprintf(txtrecord[0], 128, "txtvers=1");
  snprintf(txtrecord[1], 128, "Database ID=%0X", hash);
  snprintf(txtrecord[2], 128, "Machine ID=%0X", hash);
  snprintf(txtrecord[3], 128, "Machine Name=%s", libname);
  snprintf(txtrecord[4], 128, "mtd-version=%s", VERSION);
  snprintf(txtrecord[5], 128, "iTSh Version=131073"); /* iTunes 6.0.4 */
  snprintf(txtrecord[6], 128, "Version=196610");      /* iTunes 6.0.4 */

  password = cfg_getstr(lib, "password");
  snprintf(txtrecord[7], 128, "Password=%s", (password) ? "true" : "false");

  if (ffid)
    snprintf(txtrecord[8], 128, "ffid=%s", ffid);
  else
    snprintf(txtrecord[8], 128, "ffid=%08x", rand());

  DPRINTF(E_INFO, L_MAIN, "Registering rendezvous names\n");

  port = cfg_getint(lib, "port");

  /* Register web server service */
  ret = mdns_register(libname, "_http._tcp", port, txtrecord);
  if (ret < 0)
    return ret;

  /* Register RSP service */
  if (!no_rsp)
    {
      ret = mdns_register(libname, "_rsp._tcp", port, txtrecord);
      if (ret < 0)
	return ret;
    }

  /* Register DAAP service */
  if (!no_daap)
    {
      ret = mdns_register(libname, "_daap._tcp", port, txtrecord);
      if (ret < 0)
	return ret;
    }

  for (i = 0; i < (sizeof(records) / sizeof(records[0])); i++)
    {
      memset(records[i], 0, 128);
    }

  snprintf(txtrecord[0], 128, "txtvers=1");
  snprintf(txtrecord[1], 128, "DbId=%016" PRIX64, libhash);
  snprintf(txtrecord[2], 128, "DvTy=iTunes");
  snprintf(txtrecord[3], 128, "DvSv=2306"); /* Magic number! Yay! */
  snprintf(txtrecord[4], 128, "Ver=131073"); /* iTunes 6.0.4 */
  snprintf(txtrecord[5], 128, "OSsi=0x1F5"); /* Magic number! Yay! */
  snprintf(txtrecord[6], 128, "CtlN=%s", libname);

  /* Terminator */
  txtrecord[7] = NULL;

  /* The group name for the touch-able service advertising is a 64bit hash
   * but is different from the DbId in iTunes. For now we'll use a hash of
   * the library name for both, and we'll change that if needed.
   */

  /* Use as scratch space for the hash */
  snprintf(records[7], 128, "%016" PRIX64, libhash);

  /* Register touch-able service, for Remote.app */
  ret = mdns_register(records[7], "_touch-able._tcp", port, txtrecord);
  if (ret < 0)
    return ret;

  return 0;
}