diff --git a/rtsp.c b/rtsp.c index 31cef80d..136612bc 100644 --- a/rtsp.c +++ b/rtsp.c @@ -62,6 +62,8 @@ typedef struct { int fd; stream_cfg stream; SOCKADDR remote; + int running; + pthread_t thread; } rtsp_conn_info; static inline int rtsp_playing(void) { @@ -84,6 +86,32 @@ void rtsp_shutdown_stream(void) { pthread_mutex_unlock(&playing_mutex); } +// keep track of the threads we have spawned so we can join() them +static rtsp_conn_info **conns = NULL; +static int nconns = 0; +static void track_thread(rtsp_conn_info *conn) { + conns = realloc(conns, sizeof(rtsp_conn_info*) * (nconns + 1)); + conns[nconns] = conn; + nconns++; +} + +static void cleanup_threads(void) { + void *retval; + int i; + debug(2, "culling threads.\n"); + for (i=0; irunning == 0) { + pthread_join(conns[i]->thread, &retval); + free(conns[i]); + debug(2, "one joined\n"); + nconns--; + if (nconns) + conns[i] = conns[nconns]; + } else { + i++; + } + } +} // park a null at the line ending, and return the next line pointer // accept \r, \n, or \r\n @@ -684,7 +712,7 @@ respond: } if (auth_nonce) free(auth_nonce); - free(conn); + conn->running = 0; debug(2, "terminating RTSP thread\n"); return NULL; } @@ -766,7 +794,6 @@ void rtsp_listen_loop(void) { fd_set fds; FD_ZERO(&fds); for (i=0; i maxfd) maxfd = sockfd[i]; } @@ -784,20 +811,32 @@ void rtsp_listen_loop(void) { printf("Listening for connections.\n"); int acceptfd; + struct timeval tv; while (1) { - ret = select(maxfd+1, &fds, 0, 0, 0); + tv.tv_sec = 300; + tv.tv_usec = 0; + + for (i=0; ifd = accept(acceptfd, (struct sockaddr *)&conn->remote, &slen); if (conn->fd < 0) { perror("failed to accept connection"); + free(conn); } else { - // for now, we do not track these and let them die of natural causes. - // XXX: this leaks threads; they need to be culled with pthread_tryjoin_np. pthread_t rtsp_conversation_thread; - pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn); - } + ret = pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn); + if (ret) + die("Failed to create RTSP receiver thread!"); - for (i=0; ithread = rtsp_conversation_thread; + conn->running = 1; + track_thread(conn); + } } perror("select"); die("fell out of the RTSP select loop");