static void srvlisten_rtmplive_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; int rc = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_INFO("rtmp %sserver available at rtmp://%s:%d max:%d"), ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL) " : ""), net_inet_ntoa(sa.sin_addr, buf), ntohs(sa.sin_port), pListenCfg->max); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_rtmp_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("rtmp listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
void thread_func_wrapper(void *pArg) { THREAD_FUNC_WRAPPER_ARG_T wrap; char tmp[128]; int rc = 0; memcpy(&wrap, pArg, sizeof(THREAD_FUNC_WRAPPER_ARG_T)); ((THREAD_FUNC_WRAPPER_ARG_T *)pArg)->flags = 0; logutil_tid_add(pthread_self(), wrap.tid_tag); //pthread_cond_broadcast(((THREAD_FUNC_WRAPPER_ARG_T *) pArg)->pcond); //fprintf(stderr, "%u THREAD_FUNC pConn:0x%x inuse:%d\n", pthread_self(), wrap.pConn, wrap.pConn->pool.inuse); // // Handle any SSL handshaking on the connection thread, to avoid blocking the accept loop // if((wrap.pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS)) { if((rc = netio_acceptssl(&wrap.pConn->sd.netsocket)) < 0) { LOG(X_ERROR("Closing non-SSL connection on port %d from %s:%d"), htons(INET_PORT(wrap.pConn->pListenCfg->sa)), FORMAT_NETADDR(wrap.pConn->sd.sa, tmp, sizeof(tmp)), htons(INET_PORT(wrap.pConn->sd.sa))); } } if(rc == 0) { // // Call the wrapper's thread procedure // wrap.thread_func(wrap.pConn); } //fprintf(stderr, "%d THREAD_FUNC DONE pConn:0x%x inuse:%d\n", pthread_self(), wrap.pConn, wrap.pConn->pool.inuse); netio_closesocket(&wrap.pConn->sd.netsocket); pool_return(wrap.pConnPool, &wrap.pConn->pool); logutil_tid_remove(pthread_self()); //fprintf(stderr, "%u THREAD_FUNC DONE pConn:0x%x inuse:%d\n", pthread_self(), wrap.pConn, wrap.pConn->pool.inuse); }
int srv_rtsp_proc(CLIENT_CONN_T *pConn, const unsigned char *prebuf, unsigned int prebufsz) { int rc = 0; RTSP_REQ_CTXT_T rtspCtxt; char tmps[2][128]; if(!pConn) { return -1; } if(!(pConn->pListenCfg->urlCapabilities & URL_CAP_RTSPLIVE)) { LOG(X_ERROR("Listener %s:%d not enabled for rtsp%s stream to %s:%d"), FORMAT_NETADDR(pConn->pListenCfg->sa, tmps[1], sizeof(tmps[1])), ntohs(INET_PORT(pConn->pListenCfg->sa)), (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return -1; } memset(&rtspCtxt, 0, sizeof(rtspCtxt)); rtspCtxt.pSd = &pConn->sd; rtspCtxt.pListenCfg = pConn->pListenCfg; if(pConn->pStreamerCfg0 && pConn->pStreamerCfg0->running >= 0) { rtspCtxt.pStreamerCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg0; } else if(pConn->pStreamerCfg1 && pConn->pStreamerCfg1->running >= 0) { rtspCtxt.pStreamerCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg1; } rtspCtxt.prebufdata = (unsigned char *) prebuf; rtspCtxt.prebufsz = prebufsz; if(rtspCtxt.pStreamerCfg && ((STREAMER_CFG_T *)rtspCtxt.pStreamerCfg)->pRtspSessions) { rtsp_handle_conn(&rtspCtxt); } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTSP connection thread ended %s:%d"), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return rc; }
static void srv_rtsp_proc(void *pfuncarg) { CLIENT_CONN_T *pConn = (CLIENT_CONN_T *) pfuncarg; char buf[SAFE_INET_NTOA_LEN_MAX]; RTSP_REQ_CTXT_T rtspCtxt; memset(&rtspCtxt, 0, sizeof(rtspCtxt)); rtspCtxt.pSd = &pConn->sd; rtspCtxt.pListenCfg = pConn->pListenCfg; if(pConn->pStreamerCfg0 && pConn->pStreamerCfg0->running >= 0) { rtspCtxt.pStreamerCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg0; } else if(pConn->pStreamerCfg1 && pConn->pStreamerCfg1->running >= 0) { rtspCtxt.pStreamerCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg1; } if(rtspCtxt.pStreamerCfg && ((STREAMER_CFG_T *)rtspCtxt.pStreamerCfg)->pRtspSessions) { rtsp_handle_conn(&rtspCtxt); } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTSP connection thread ended %s:%d"), net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); }
int srvlisten_loop(SRV_LISTENER_CFG_T *pListenCfg, void *thread_func) { int salen; THREAD_FUNC_WRAPPER_ARG_T wrapArg; CLIENT_CONN_T *pConn; SOCKET_DESCR_T sdclient; int rc = -1; const char *s; //pthread_cond_t cond; pthread_mutex_t mtx; TIME_VAL tv0, tv1; char tmp[128]; #if defined(__APPLE__) int sockopt = 0; #endif // __APPLE__ if(!pListenCfg || !pListenCfg->pnetsockSrv || !pListenCfg->pConnPool || !thread_func || pListenCfg->pConnPool->numElements <= 0) { return -1; } //memset(&saSrv, 0, sizeof(saSrv)); memset(&sdclient.netsocket, 0, sizeof(sdclient.netsocket)); //salen = sizeof(saSrv); //if(getsockname(pListenCfg->pnetsockSrv->sock, (struct sockaddr *) &saSrv, (socklen_t *) &salen) != 0) { // LOG(X_ERROR("getsockopt failed on server socket")); //} pthread_mutex_init(&mtx, NULL); //pthread_cond_init(&cond, NULL); while(!g_proc_exit) { salen = sizeof(sdclient.sa); if((NETIOSOCK_FD(sdclient.netsocket) = accept(PNETIOSOCK_FD(pListenCfg->pnetsockSrv), (struct sockaddr *) &sdclient.sa, (socklen_t *) &salen)) == INVALID_SOCKET) { if(!g_proc_exit) { LOG(X_ERROR("%saccept failed on %s:%d"), ((pListenCfg->pnetsockSrv->flags & NETIO_FLAG_SSL_TLS) ? "SSL " : ""), //inet_ntoa(saSrv.sin_addr), ntohs(saSrv.sin_port)); FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa))); } break; } if(g_proc_exit) { break; } sdclient.netsocket.flags = pListenCfg->pnetsockSrv->flags; // // Find an available client thread to process the client request // if((pConn = (CLIENT_CONN_T *) pool_get(pListenCfg->pConnPool)) == NULL) { LOG(X_WARNING("No available connection for %s:%d (max:%d) on port %d"), FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)), ntohs(INET_PORT(sdclient.sa)), pListenCfg->pConnPool->numElements, ntohs(INET_PORT(pListenCfg->sa))); netio_closesocket(&sdclient.netsocket); continue; } #if defined(__APPLE__) sockopt = 1; if(setsockopt(NETIOSOCK_FD(sdclient.netsocket), SOL_SOCKET, SO_NOSIGPIPE, (char*) &sockopt, sizeof(sockopt)) != 0) { LOG(X_ERROR("Failed to set SO_NOSIGPIPE")); } #endif // __APPLE__ //pConn->psrvsaListen = &saSrv; //memcpy(&pConn->srvsaListen, &saSrv, sizeof(pConn->srvsaListen)); LOG(X_DEBUG("Accepted connection on port %d from %s:%d"), htons(INET_PORT(pListenCfg->sa)), FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)), htons(INET_PORT(sdclient.sa))); pthread_attr_init(&pConn->attr); pthread_attr_setdetachstate(&pConn->attr, PTHREAD_CREATE_DETACHED); memset(&pConn->sd.netsocket, 0, sizeof(pConn->sd.netsocket)); NETIO_SET(pConn->sd.netsocket, sdclient.netsocket); memcpy(&pConn->sd.sa, &sdclient.sa, INET_SIZE(sdclient)); pConn->pListenCfg = pListenCfg; NETIOSOCK_FD(sdclient.netsocket) = INVALID_SOCKET; wrapArg.thread_func = thread_func; wrapArg.pConnPool = pListenCfg->pConnPool; wrapArg.pConn = pConn; wrapArg.flags = 1; wrapArg.tid_tag[0] = '\0'; if((s = logutil_tid_lookup(pthread_self(), 0)) && s[0] != '\0') { snprintf(wrapArg.tid_tag, sizeof(wrapArg.tid_tag), "%s-%u", s, pConn->pool.id); } //wrapArg.pcond = &cond; //fprintf(stderr, "%d CALLING wrap: 0x%x pConn:0x%x\n", pthread_self(), &wrapArg, wrapArg.pConn); if((rc = pthread_create(&pConn->ptd, &pConn->attr, (void *) thread_func_wrapper, (void *) &wrapArg)) != 0) { LOG(X_ERROR("Unable to create connection handler thread on port %d from %s:%d (%d %s)"), htons(INET_PORT(pListenCfg->sa)), FORMAT_NETADDR(sdclient.sa, tmp, sizeof(tmp)), htons(INET_PORT(sdclient.sa)), rc, strerror(rc)); netio_closesocket(&pConn->sd.netsocket); pool_return(pListenCfg->pConnPool, &pConn->pool); wrapArg.flags = 0; //pthread_cond_broadcast(&cond); break; } pthread_attr_destroy(&pConn->attr); // // be careful not to reuse the same wrapArg instance // since the stack variable arguments could get // overwritten by the next loop iteration, before the thread proc is // invoked // //fprintf(stderr, "wait start\n"); tv0 = timer_GetTime(); //if(wrapArg.flags == 1) { // // It seems that calling pthread_cond_wait here to check if the thread creation is // complete is not completely reliable and portable, so we do the lame way // of sleeping and polling. // //pthread_cond_wait(&cond, &mtx); while(wrapArg.flags == 1) { usleep(100); if(((tv1 = timer_GetTime()) - tv0) / TIME_VAL_MS > 1000) { LOG(X_WARNING("Abandoning wait for connection thread start on port %d from %s:%d"), htons(INET_PORT(pListenCfg->sa)), FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa))); break; } } //fprintf(stderr, "THREAD STARTED AFTER %lld ns\n", (timer_GetTime() - tv0)); //} //fprintf(stderr, "wait done\n"); //while(wrapArg.flag == 1) { // usleep(10000); //} } //pthread_cond_destroy(&cond); pthread_mutex_destroy(&mtx); return rc; }
static void srvlisten_media_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_storage sa; CLIENT_CONN_T *pConnTmp; char tmp[128]; char bufses[32]; const int backlog = NET_BACKLOG_DEFAULT; unsigned int tsMax = 0; unsigned int flvMax = 0; unsigned int mkvMax = 0; unsigned int rtmpMax = 0; unsigned int rtspMax = 0; int haveAuth = 0; int haveRtmpAuth = 0; int haveRtspAuth = 0; int haveToken = 0; int rc = 0; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE | URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE | URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST | URL_CAP_RTMPLIVE | URL_CAP_RTMPTLIVE | URL_CAP_RTSPLIVE)) == 0) { LOG(X_WARNING("Server listener exiting because no capabilities enabled on %s:%d"), FORMAT_NETADDR(pListenCfg->sa, tmp, sizeof(tmp)), ntohs(INET_PORT(pListenCfg->sa))); logutil_tid_remove(pthread_self()); return; } else if(!(pConnTmp = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements)) { return; } memset(&netsocksrv, 0, sizeof(netsocksrv)); memcpy(&sa, &pListenCfg->sa, sizeof(pListenCfg->sa)); netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen((const struct sockaddr *) &sa, backlog)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) { haveAuth = 1; } if(pListenCfg->pAuthTokenId && pListenCfg->pAuthTokenId[0] != '\0') { haveToken = 1; } tsMax = pConnTmp->pStreamerCfg0->liveQs[0].max; flvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max; mkvMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max; rtmpMax = pConnTmp->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].max; rtspMax = pConnTmp->pStreamerCfg0->pRtspSessions->max; if(HAVE_URL_CAP_RTMP(pListenCfg->urlCapabilities)) { if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTMP].stores[pListenCfg->idxCfg])) { // // RTMP server streaming credentials not implemented // //haveRtmpAuth = 1; } LOG(X_INFO("rtmp %s%s available at "URL_RTMP_FMT_STR"%s max:%d"), ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " : ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""), ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) && !(pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE) ? "(tunneled only) " : ((pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE) ? "(tunneled) " : "")), URL_PROTO_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)), (haveRtmpAuth ? " (Using auth)" : ""), rtmpMax); } if(pListenCfg->urlCapabilities & URL_CAP_RTSPLIVE) { if(IS_AUTH_CREDENTIALS_SET(&pConnTmp->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTSP].stores[pListenCfg->idxCfg])) { haveRtspAuth = 1; } if(pListenCfg->pCfg->prtspsessiontimeout && *pListenCfg->pCfg->prtspsessiontimeout != 0) { snprintf(bufses, sizeof(bufses), ", timeout:%u sec", *pListenCfg->pCfg->prtspsessiontimeout); } else { bufses[0] = '\0'; } LOG(X_INFO("rtsp %s available at "URL_RTSP_FMT_STR"%s max:%d%s"), ((pListenCfg->netflags & NETIO_FLAG_PLAINTEXT) && (pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ) ? "(SSL) " : ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL only) " : ""), URL_PROTO_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), FORMAT_NETADDR(sa, tmp, sizeof(tmp))), ntohs(INET_PORT(sa)), (haveRtspAuth ? " (Using auth)" : ""), rtspMax, bufses); } if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) { LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_ROOT_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) { LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_LIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) { LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_TSLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax); } if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) { LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_HTTPLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) { LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_FLVLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) { LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_MKVLIVE_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) { LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_DASH_URL, (haveAuth ? " (Using auth)" : ""), (haveToken ? " (Using token)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) { LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_STATUS_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_PIP)) { LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_PIP_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) { LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, FORMAT_NETADDR(sa, tmp, sizeof(tmp))), VSX_CONFIG_URL, (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_cmd_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
int srv_rtmp_proc(CLIENT_CONN_T *pConn, const unsigned char *prebuf, unsigned int prebufsz, int istunneled) { int rc = 0; STREAMER_CFG_T *pStreamerCfg = NULL; STREAMER_OUTFMT_T *pLiveFmt = NULL; STREAM_STATS_T *pstats = NULL; RTMP_CTXT_T rtmpCtxt; unsigned int numQFull = 0; char tmps[2][128]; OUTFMT_CFG_T *pOutFmt = NULL; if(!pConn) { return -1; } if(!HAVE_URL_CAP_RTMP(pConn->pListenCfg->urlCapabilities)) { LOG(X_ERROR("Listener %s:%d not enabled for rtmp%s%s stream to %s:%d"), FORMAT_NETADDR(pConn->pListenCfg->sa, tmps[1], sizeof(tmps[1])), ntohs(INET_PORT(pConn->pListenCfg->sa)), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return -1; } pStreamerCfg = GET_STREAMER_FROM_CONN(pConn); if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) { pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP]; if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) { if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor, (const struct sockaddr *) &pConn->sd.sa, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) { } } // // Add a livefmt cb // pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 1, pStreamerCfg->frameThin, &numQFull); } if(pOutFmt) { memset(&rtmpCtxt, 0, sizeof(rtmpCtxt)); rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen)); rtmpCtxt.pSd = &pConn->sd; rtmpCtxt.novid = pStreamerCfg->novid; rtmpCtxt.noaud = pStreamerCfg->noaud; rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg; rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg; rtmpCtxt.pAuthTokenId = pConn->pListenCfg->pAuthTokenId; if(pstats) { rtmpCtxt.pStreamMethod = &pstats->method; } rtmpCtxt.pOutFmt = pOutFmt; rtmpCtxt.prebufdata = (unsigned char *) prebuf; rtmpCtxt.prebufsz = prebufsz; if(!(pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPLIVE)) { rtmpCtxt.donotunnel = 1; } if((pConn->pListenCfg->urlCapabilities & URL_CAP_RTMPTLIVE)) { rtmpCtxt.dohttptunnel = 1; } // // Unpause the outfmt callback mechanism now that rtmp_init was called // outfmt_pause(pOutFmt, 0); LOG(X_INFO("Starting rtmp%s%s stream[%d] %d/%d to %s:%d"), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, numQFull + 1, pLiveFmt->max, FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); rtmp_handle_conn(&rtmpCtxt); LOG(X_INFO("Ending rtmp%s%s stream[%d] to %s:%d"), istunneled > 0 ? "t" : "", (pConn->sd.netsocket.flags & NETIO_FLAG_SSL_TLS) ? "s" : "", pOutFmt->cbCtxt.idx, FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); // // Remove the livefmt cb // outfmt_removeCb(pOutFmt); rtmp_close(&rtmpCtxt); } else { if(pstats) { // // Destroy automatically detaches the stats from the monitor linked list // stream_stats_destroy(&pstats, NULL); } LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), (pLiveFmt ? pLiveFmt->max : 0), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); rc = -1; } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTMP connection thread ended %s:%d"), FORMAT_NETADDR(pConn->sd.sa, tmps[0], sizeof(tmps[0])), ntohs(INET_PORT(pConn->sd.sa))); return rc; }
static void srvlisten_rtsplive_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; CLIENT_CONN_T *pConn = NULL; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; int haveRtspAuth = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; char bufses[32]; int rc = 0; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pConn = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements; if(pConn) { if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_RTSP].stores[pListenCfg->idxCfg])) { haveRtspAuth = 1; } } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pCfg->prtspsessiontimeout && *pListenCfg->pCfg->prtspsessiontimeout != 0) { snprintf(bufses, sizeof(bufses), ", timeout:%u sec", *pListenCfg->pCfg->prtspsessiontimeout); } else { bufses[0] = '\0'; } LOG(X_INFO("rtsp %sserver available at "URL_RTSP_FMT_STR"%s max:%d%s"), ((pListenCfg->netflags & NETIO_FLAG_SSL_TLS) ? "(SSL) " : ""), URL_RTSP_FMT2_ARGS( (pListenCfg->netflags & NETIO_FLAG_SSL_TLS), net_inet_ntoa(sa.sin_addr, buf)), ntohs(sa.sin_port), (haveRtspAuth ? " (Using auth)" : ""), pListenCfg->max, bufses); // // Service any client connections on the rtsp listening port // rc = srvlisten_loop(pListenCfg, srv_rtsp_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_DEBUG("rtsp listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return ; }
static void srvlisten_http_proc(void *pArg) { SRV_LISTENER_CFG_T *pListenCfg = (SRV_LISTENER_CFG_T *) pArg; NETIO_SOCK_T netsocksrv; struct sockaddr_in sa; CLIENT_CONN_T *pConn; unsigned int tsMax = 0; unsigned int flvMax = 0; unsigned int mkvMax = 0; /* int haveMkvAuth = 0; int haveFlvAuth = 0; int haveTsliveAuth = 0; int haveHttpliveAuth = 0; int haveMoofAuth = 0; int haveConfigAuth = 0; int havePipAuth = 0; int haveStatusAuth = 0; int haveRootAuth = 0; */ int haveAuth = 0; int rc = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; logutil_tid_add(pthread_self(), pListenCfg->tid_tag); if((pListenCfg->urlCapabilities & (URL_CAP_TSLIVE | URL_CAP_TSHTTPLIVE | URL_CAP_FLVLIVE | URL_CAP_MKVLIVE | URL_CAP_LIVE | URL_CAP_STATUS | URL_CAP_MOOFLIVE | URL_CAP_PIP | URL_CAP_CONFIG | URL_CAP_BROADCAST)) == 0) { LOG(X_WARNING("http listener exiting because no capabilities enabled on %s:%d"), inet_ntoa(pListenCfg->sain.sin_addr), ntohs(pListenCfg->sain.sin_port)); logutil_tid_remove(pthread_self()); return; } memset(&sa, 0, sizeof(sa)); memset(&netsocksrv, 0, sizeof(netsocksrv)); sa.sin_family = PF_INET; sa.sin_addr = pListenCfg->sain.sin_addr; sa.sin_port = pListenCfg->sain.sin_port; netsocksrv.flags = pListenCfg->netflags; if((NETIOSOCK_FD(netsocksrv) = net_listen(&sa, 5)) == INVALID_SOCKET) { logutil_tid_remove(pthread_self()); return; } pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = &netsocksrv; pthread_mutex_unlock(&pListenCfg->mtx); if(pListenCfg->pAuthStore && IS_AUTH_CREDENTIALS_SET(pListenCfg->pAuthStore)) { haveAuth = 1; } pConn = (CLIENT_CONN_T *) pListenCfg->pConnPool->pElements; if(pConn) { tsMax = pConn->pStreamerCfg0->liveQs[0].max; flvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_FLV].max; mkvMax = pConn->pStreamerCfg0->action.liveFmts.out[STREAMER_OUTFMT_IDX_MKV].max; /* if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_FLV].stores[pListenCfg->idxCfg])) { haveFlvAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MKV].stores[pListenCfg->idxCfg])) { haveMkvAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_TSLIVE].stores[pListenCfg->idxCfg])) { haveTsliveAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_HTTPLIVE].stores[pListenCfg->idxCfg])) { haveHttpliveAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_MOOFLIVE].stores[pListenCfg->idxCfg])) { haveMoofAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_CONFIG].stores[pListenCfg->idxCfg])) { haveConfigAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_PIP].stores[pListenCfg->idxCfg])) { havePipAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_STATUS].stores[pListenCfg->idxCfg])) { haveStatusAuth = 1; } if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds[STREAMER_AUTH_IDX_ROOT].stores[pListenCfg->idxCfg])) { haveRootAuth = 1; } */ //if(IS_AUTH_CREDENTIALS_SET(&pConn->pStreamerCfg0->creds.auths[STREAMER_AUTH_IDX_ROOT])) { // LOG(X_DEBUG("LIVE/ROOT AUTH ON")); //} } if((pListenCfg->urlCapabilities & URL_CAP_ROOTHTML)) { LOG(X_INFO("broadcast interface available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_ROOT_URL, //(haveRootAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_LIVE)) { LOG(X_INFO("live available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_LIVE_URL, //(haveRootAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_TSLIVE)) { LOG(X_INFO("tslive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_TSLIVE_URL, //(haveTsliveAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), tsMax); } if((pListenCfg->urlCapabilities & URL_CAP_TSHTTPLIVE)) { LOG(X_INFO("httplive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_HTTPLIVE_URL, //(haveHttpliveAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_FLVLIVE)) { LOG(X_INFO("flvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_FLVLIVE_URL, //(haveFlvAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), flvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MKVLIVE)) { LOG(X_INFO("mkvlive available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_MKVLIVE_URL, //(haveMkvAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), mkvMax); } if((pListenCfg->urlCapabilities & URL_CAP_MOOFLIVE)) { LOG(X_INFO("dash available at "URL_HTTP_FMT_STR"%s%s%s max:%d"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_DASH_URL, // (haveMoofAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : ""), pListenCfg->max); } if((pListenCfg->urlCapabilities & URL_CAP_STATUS)) { LOG(X_INFO("status available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_STATUS_URL, //(haveStatusAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_PIP)) { LOG(X_INFO("pip available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_PIP_URL, //(havePipAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } if((pListenCfg->urlCapabilities & URL_CAP_CONFIG)) { LOG(X_INFO("config available at "URL_HTTP_FMT_STR"%s%s%s"), URL_HTTP_FMT_ARGS2(pListenCfg, net_inet_ntoa(sa.sin_addr, buf)), VSX_CONFIG_URL, //(haveConfigAuth ? " (Using auth)" : ""), (haveAuth ? " (Using auth)" : ""), (pListenCfg->pCfg->cfgShared.livepwd ? " (Using password)" : "")); } //fprintf(stderr, "LISTENER THREAD %s %s:%d active:%d cap: 0x%x\n", pListenCfg->netflags & NETIO_FLAG_SSL_TLS ? "SSL" : "", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), pListenCfg->active, pListenCfg->urlCapabilities); // // Service any client connections on the live listening port // rc = srvlisten_loop(pListenCfg, srv_cmd_proc); pthread_mutex_lock(&pListenCfg->mtx); pListenCfg->pnetsockSrv = NULL; netio_closesocket(&netsocksrv); pthread_mutex_unlock(&pListenCfg->mtx); LOG(X_WARNING("HTTP listener thread exiting with code: %d"), rc); logutil_tid_remove(pthread_self()); return; }
static void srv_rtmp_proc(void *pfuncarg) { CLIENT_CONN_T *pConn = (CLIENT_CONN_T *) pfuncarg; STREAMER_CFG_T *pStreamerCfg = NULL; STREAMER_OUTFMT_T *pLiveFmt = NULL; STREAM_STATS_T *pstats = NULL; RTMP_CTXT_T rtmpCtxt; unsigned int numQFull = 0; char buf[SAFE_INET_NTOA_LEN_MAX]; OUTFMT_CFG_T *pOutFmt = NULL; pStreamerCfg = GET_STREAMER_FROM_CONN(pConn); if(pStreamerCfg && pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP].do_outfmt) { pLiveFmt = &pStreamerCfg->action.liveFmts.out[STREAMER_OUTFMT_IDX_RTMP]; if(pStreamerCfg->pMonitor && pStreamerCfg->pMonitor->active) { if(!(pstats = stream_monitor_createattach(pStreamerCfg->pMonitor, &pConn->sd.sain, STREAM_METHOD_RTMP, STREAM_MONITOR_ABR_NONE))) { } } // // Add a livefmt cb // pOutFmt = outfmt_setCb(pLiveFmt, rtmp_addFrame, &rtmpCtxt, &pLiveFmt->qCfg, pstats, 1, pStreamerCfg->frameThin, &numQFull); } if(pOutFmt) { memset(&rtmpCtxt, 0, sizeof(rtmpCtxt)); rtmp_init(&rtmpCtxt, MAX(pLiveFmt->qCfg.maxPktLen, pLiveFmt->qCfg.growMaxPktLen)); rtmpCtxt.pSd = &pConn->sd; rtmpCtxt.novid = pStreamerCfg->novid; rtmpCtxt.noaud = pStreamerCfg->noaud; rtmpCtxt.av.vid.pStreamerCfg = pStreamerCfg; rtmpCtxt.av.aud.pStreamerCfg = pStreamerCfg; // // Unpause the outfmt callback mechanism now that rtmp_init was called // outfmt_pause(pOutFmt, 0); LOG(X_INFO("Starting rtmp stream[%d] %d/%d to %s:%d"), pOutFmt->cbCtxt.idx, numQFull + 1, pLiveFmt->max, net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); rtmp_handle_conn(&rtmpCtxt); LOG(X_INFO("Ending rtmp stream[%d] to %s:%d"), pOutFmt->cbCtxt.idx, net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); // // Remove the livefmt cb // outfmt_removeCb(pOutFmt); rtmp_close(&rtmpCtxt); } else { if(pstats) { // // Destroy automatically detaches the stats from the monitor linked list // stream_stats_destroy(&pstats, NULL); } LOG(X_WARNING("No rtmp resource available (max:%d) for %s:%d"), (pLiveFmt ? pLiveFmt->max : 0), net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); } netio_closesocket(&pConn->sd.netsocket); LOG(X_DEBUG("RTMP connection thread ended %s:%d"), net_inet_ntoa(pConn->sd.sain.sin_addr, buf), ntohs(pConn->sd.sain.sin_port)); }
int http_gethttplive(CAP_ASYNC_DESCR_T *pCfg, CAPTURE_CBDATA_T *pStreamsOut, CAPTURE_STREAM_T *pStream, const char *puri, HTTP_RESP_T *pHttpResp, HTTP_PARSE_CTXT_T *pHdrCtxt) { int rc = 0; char *path; const char *pbuf = pHdrCtxt->pbuf; unsigned int szbuf = pHdrCtxt->szbuf; const char *pm3ubuf; pthread_t ptd; pthread_attr_t attr; HTTPLIVE_CLIENT_T client; int highestIdx, lowestIdx, firstIdx; memset(&client, 0, sizeof(client)); client.pCfg = pCfg; NETIOSOCK_FD(client.netsock) = INVALID_SOCKET; client.netsock.flags = pCfg->pSockList->netsockets[0].flags; client.pStreamsOut = pStreamsOut; client.pStream = pStream; client.running = -1; pthread_mutex_init(&client.mtx, NULL); do { //fprintf(stderr, "HTTP_GETHTTPLIVE sock: %d\n", NETIOSOCK_FD(pCfg->pSockList->netsockets[0])); if(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]) == INVALID_SOCKET) { //fprintf(stderr, "GOING TO CONNECT FOR M3U...\n"); if((rc = httpcli_connect(&pCfg->pSockList->netsockets[0], &pCfg->pSockList->salist[0], "HTTPLive playlist thread")) < 0) { break; } memset(pHdrCtxt, 0, sizeof(HTTP_PARSE_CTXT_T)); memset(pHttpResp, 0, sizeof(HTTP_RESP_T)); pHdrCtxt->pnetsock = &pCfg->pSockList->netsockets[0]; pHdrCtxt->pbuf = pbuf; pHdrCtxt->szbuf = szbuf; pHdrCtxt->tmtms = 0; } if((rc = mediadb_getdirlen(puri)) > 0) { if(rc >= sizeof(client.uriprefix)) { rc = sizeof(client.uriprefix) - 1; } memcpy(client.uriprefix, puri, rc); } if((pm3ubuf = get_m3u8(pCfg, puri, pHttpResp, pHdrCtxt, (unsigned char *) pbuf, szbuf))) { m3u_free(&client.pl, 0); memset(&client.pl, 0, sizeof(client.pl)); /* pm3ubuf="#EXTM3U\r\n" "#EXT-X-VERSION:3\r\n" "#EXT-X-ALLOW-CACHE:NO\r\n" "#EXT-X-TARGETDURATION:14\r\n" "#EXT-X-MEDIA-SEQUENCE:2699\r\n" "#EXTINF:10,\r\n" "media_2699.ts?wowzasessionid=1144297750\r\n" "#EXTINF:10,\r\n" "media_2700.ts?wowzasessionid=1144297750\r\n" "#EXTINF:7,\r\n" "media_2701.ts?wowzasessionid=1144297750\r\n"; */ VSX_DEBUGLOG("Got m3u contents '%s'", pm3ubuf); //fprintf(stderr, "Got m3u contents '%s'\n", pm3ubuf); pthread_mutex_lock(&client.mtx); rc = m3u_create_buf(&client.pl, pm3ubuf); pthread_mutex_unlock(&client.mtx); if(rc > 0) { path = NULL; lowestIdx = find_lowest_idx(&client.pl, NULL); highestIdx = find_highest_idx(&client.pl, NULL); if(!client.insession) { if(highestIdx < 0) { LOG(X_WARNING("Unable to find httplive starting index from %s"), puri); } else { // // Some segmentors may write the last chunk to the playlist file even though // the chunk is still being appended on disk // //if(highestIdx > lowestIdx) { // firstIdx = highestIdx - 1; //} else { firstIdx = highestIdx; //} client.curidx = firstIdx; client.nextidx = client.curidx; client.insession = 1; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); client.running = 1; if(pthread_create(&ptd, &attr, (void *) httplive_mediaproc, &client) != 0) { LOG(X_ERROR("Unable to create httplive media download thread")); rc = -1; client.running = -1; } } } else { // client.insession //fprintf(stderr, "check playlist falling behind curidx:%d nextidx:%d, lowestIdx:%d, highestIdx:%d\n", client.curidx, client.nextidx, lowestIdx, highestIdx); // // Prevent falling behind playlist, a warning will be printed in the ts get thread // pthread_mutex_lock(&client.mtx); if(client.nextidx < lowestIdx) { client.nextidx = lowestIdx; } pthread_mutex_unlock(&client.mtx); } //if(rc >= 0) { // m3u_dump(&client.pl); //} } } else { // get_m3u8 rc = -1; } netio_closesocket(&pCfg->pSockList->netsockets[0]); if(rc >= 0) { //fprintf(stderr, "M3U SLEEPING FOR %d\n", client.pl.targetDuration); if(client.pl.targetDuration > 0) { sleep(client.pl.targetDuration); } else { sleep(9); } } } while(rc >= 0); client.insession = 0; while(client.running != -1) { usleep(20000); } m3u_free(&client.pl, 0); pthread_mutex_destroy(&client.mtx); return rc; }
static void httplive_mediaproc(void *pArg) { HTTPLIVE_CLIENT_T *pClient = (HTTPLIVE_CLIENT_T *) pArg; int rc = 0; const char *p; const char *puri = NULL; char path[VSX_MAX_PATH_LEN]; pClient->running = 0; LOG(X_DEBUG("Starting HTTPLive client media thread")); path[sizeof(path) - 1] = '\0'; while(rc >= 0 && pClient->pCfg->running == 0 && pClient->insession) { path[0] = '\0'; pthread_mutex_lock(&pClient->mtx); if(pClient->nextidx > pClient->curidx) { LOG(X_WARNING("HTTPLive skipping playlist media chunk index %d - %d"), pClient->curidx, pClient->nextidx - 1); pClient->curidx = pClient->nextidx; //pClient->nextidx++; } if((p = find_path(&pClient->pl, pClient->curidx))) { strncpy(path, p, sizeof(path) - 1); } else { } pthread_mutex_unlock(&pClient->mtx); if(!(puri = get_uri_from_path(pClient, path))) { rc = -1; break; } if(puri && puri[0] != '\0') { // TODO: create httplive retrieval flag forcing new socket... lame if(NETIOSOCK_FD(pClient->netsock) != INVALID_SOCKET && net_issockremotelyclosed(NETIOSOCK_FD(pClient->netsock), 1)) { LOG(X_DEBUG("HTTPLive media socket has been closed")); netio_closesocket(&pClient->netsock); } if(NETIOSOCK_FD(pClient->netsock) == INVALID_SOCKET) { //fprintf(stderr, "----MEDIA GET for '%s' '%s'\n", path, puri); if((rc = httpcli_connect(&pClient->netsock, &pClient->sa, "HTTPLive media thread")) < 0) { break; } } //fprintf(stderr, "may call get_ts puri:'%s', idx:%d, next:%d\n", puri, pClient->curidx, pClient->nextidx); if((rc = get_ts(pClient, puri)) >= 0) { //fprintf(stderr, "HTTPLive ts retrieval '%s' returned %d\n", puri, rc); pthread_mutex_lock(&pClient->mtx); pClient->nextidx++; pClient->curidx = pClient->nextidx; pthread_mutex_unlock(&pClient->mtx); } } // end of if(puri && puri[0] != '\0' ... sleep(1); } netio_closesocket(&pClient->netsock); pClient->insession = 0; pClient->running = -1; LOG(X_DEBUG("HTTPLive media download thread exiting with code %d"), rc); }
//TODO: move this to http files int http_getpage(const char *addr, uint16_t port, const char *uri, char *buf, unsigned int szbuf, unsigned int tmtms) { int rc = 0; NETIO_SOCK_T netsock; struct sockaddr_in sa; HTTP_PARSE_CTXT_T hdrCtxt; HTTP_RESP_T httpResp; unsigned int contentLen = 0; const char *p; unsigned int consumed = 0; struct timeval tv0, tv1; char hdr[1024]; if(!addr || !buf || szbuf <= 0) { return -1; } if(!uri) { uri = "/"; } memset(&netsock, 0, sizeof(netsock)); if((NETIOSOCK_FD(netsock) = net_opensocket(SOCK_STREAM, 0, 0, NULL)) == INVALID_SOCKET) { return -1; } memset(&sa, 0, sizeof(sa)); sa.sin_addr.s_addr = inet_addr(addr); sa.sin_port = htons(port); if((rc = net_connect(NETIOSOCK_FD(netsock), &sa)) != 0) { return rc; } gettimeofday(&tv0, NULL); memset(&hdrCtxt, 0, sizeof(hdrCtxt)); memset(&httpResp, 0, sizeof(httpResp)); hdrCtxt.pnetsock = &netsock; hdrCtxt.pbuf = hdr; hdrCtxt.szbuf = sizeof(hdr); hdrCtxt.tmtms = tmtms; VSX_DEBUG_MGR(LOG(X_DEBUG("MGR - Sending local status command: '%s' to: %d"), uri, htons(sa.sin_port))); if((httpcli_gethdrs(&hdrCtxt, &httpResp, &sa, uri, NULL, 0, 0, NULL, NULL)) < 0) { return -1; } if(rc >= 0 && (p = conf_find_keyval(httpResp.hdrPairs, HTTP_HDR_CONTENT_LEN))) { contentLen = atoi(p); } if(rc >= 0) { if(contentLen <= 0) { LOG(X_ERROR("Content-Length not found in response")); rc = -1; } else if(contentLen > szbuf) { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); rc = -1; } else if(hdrCtxt.idxbuf > hdrCtxt.hdrslen) { if((consumed = hdrCtxt.idxbuf - hdrCtxt.hdrslen) < szbuf) { memcpy(buf, &hdr[hdrCtxt.hdrslen], consumed); } else { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); rc = -1; } } } if(rc >= 0 && net_setsocknonblock(NETIOSOCK_FD(netsock), 1) < 0) { rc = -1; } //fprintf(stderr, "GET PAGE OK idx:%d hdrs:%d conentlen:%d\n", hdrCtxt.idxbuf, hdrCtxt.hdrslen, contentLen); while(rc >= 0 && consumed < contentLen) { if((rc = netio_recvnb(&netsock, (unsigned char *) &buf[consumed], contentLen - consumed, 500)) > 0) { consumed += rc; } gettimeofday(&tv1, NULL); if(tmtms > 0 && consumed < contentLen && TIME_TV_DIFF_MS(tv1, tv0) > tmtms) { LOG(X_WARNING("HTTP %s:%d%s timeout %d ms exceeded"), net_inet_ntoa(sa.sin_addr, hdr), ntohs(sa.sin_port), uri, tmtms); break; rc = -1; } } if(contentLen > 0 && consumed >= contentLen) { rc = consumed; } else { rc = -1; } netio_closesocket(&netsock); return rc; }