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"); }
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; }