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; }
int capture_parseLocalAddr(const char *localAddrStr, SOCKET_LIST_T *pSockList) { int numPorts = 0; struct sockaddr_storage localAddr; unsigned short localPorts[SOCKET_LIST_MAX]; size_t idx; int rc = -1; if(!localAddrStr || !pSockList) { return -1; } memset(pSockList, 0, sizeof(SOCKET_LIST_T)); memset(&localAddr, 0, sizeof(localAddr)); if((numPorts = parseIpPortStr(localAddrStr, &localAddr, localPorts, SOCKET_LIST_MAX, 1)) > 0) { for(idx = 0; idx < sizeof(pSockList->netsockets) / sizeof(pSockList->netsockets[0]); idx++) { memset(&pSockList->salist[idx], 0, sizeof(pSockList->salist[idx])); NETIOSOCK_FD(pSockList->netsockets[idx]) = INVALID_SOCKET; if(idx < (size_t) numPorts) { memcpy(&pSockList->salist[idx], &localAddr, sizeof(pSockList->salist[idx])); INET_PORT(pSockList->salist[idx]) = htons(localPorts[idx]); //if(rtcp) { // memcpy(&pSockList->salistRtcp[idx], &pSockList->salist[idx], sizeof(pSockList->salistRtcp[idx])); // pSockList->salistRtcp[idx].sin_port = // RTCP_PORT_FROM_RTP(htons(pSockList->salistRtcp[idx].sin_port)); //} } } pSockList->numSockets = numPorts; rc = 1; } else if(numPorts == 0) { // The given localAddrStr string could be a name of a local interface rc = 0; } return rc; }
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; }
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 ; }
RTSP_HTTP_SESSION_T *rtspsrv_newHttpSession(STREAM_RTSP_SESSIONS_T *pRtsp, const char *sessionCookie, const struct sockaddr *psa) { RTSP_HTTP_SESSION_T *pRtspGetSession = NULL; size_t szCookie; unsigned int idx; if(!pRtsp || !pRtsp->pRtspGetSessionsBuf || !sessionCookie || sessionCookie[0] == '\0') { return NULL; } if((szCookie = strlen(sessionCookie)) > RTSP_HTTP_SESSION_COOKIE_MAX - 1) { LOG(X_ERROR("Client RTSP HTTP session cookie length %d exceeds %d"), szCookie, RTSP_HTTP_SESSION_COOKIE_MAX - 1); return NULL; } pthread_mutex_lock(&pRtsp->mtx); for(idx = 0; idx < pRtsp->numRtspGetSessions; idx++) { if(!pRtsp->pRtspGetSessionsBuf[idx].inuse) { pRtspGetSession = &pRtsp->pRtspGetSessionsBuf[idx]; if(!pRtspGetSession->pRequestBufWr) { if(!(pRtspGetSession->pRequestBufWr = (char *) avc_calloc(2, RTSP_HTTP_POST_BUFFER_SZ))) { pthread_mutex_unlock(&pRtsp->mtx); return NULL; } pRtspGetSession->pRequestBufRd = pRtspGetSession->pRequestBufWr + RTSP_HTTP_POST_BUFFER_SZ; pthread_mutex_init(&pRtspGetSession->cond.mtx, NULL); pthread_cond_init(&pRtspGetSession->cond.cond, NULL); pthread_mutex_init(&pRtspGetSession->mtx, NULL); } pRtspGetSession->inuse = 1; memset(&pRtspGetSession->netsocketPost, 0, sizeof(pRtspGetSession->netsocketPost)); NETIOSOCK_FD(pRtspGetSession->netsocketPost) = INVALID_SOCKET; pRtspGetSession->expired = 0; strncpy(pRtspGetSession->cookie.sessionCookie, sessionCookie, RTSP_HTTP_SESSION_COOKIE_MAX - 1); if(psa) { memcpy(&pRtspGetSession->cookie.sa, psa, INET_SIZE(*psa)); } gettimeofday(&pRtspGetSession->tvCreate, NULL); pRtspGetSession->tvLastMsg.tv_sec = 0; pRtspGetSession->requestSz = 0; pRtspGetSession->requestIdxWr = 0; pRtspGetSession->pRequestBufWr[0] = '\0'; pRtspGetSession->pRequestBufRd[0] = '\0'; pRtspGetSession->pnext = NULL; if(pRtsp->pRtspGetSessionsTail) { pRtsp->pRtspGetSessionsTail->pnext = pRtspGetSession; } else { pRtsp->pRtspGetSessionsHead = pRtspGetSession; } pRtsp->pRtspGetSessionsTail = pRtspGetSession; break; } } pthread_mutex_unlock(&pRtsp->mtx); return pRtspGetSession; }
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 const char *get_m3u8(CAP_ASYNC_DESCR_T *pCfg, const char *puri, HTTP_RESP_T *pHttpResp, HTTP_PARSE_CTXT_T *pHdrCtxt, unsigned char *pbuf, unsigned int szbuf) { int sz = 0; struct timeval tv0, tv1; unsigned int consumed = 0; unsigned int contentLen = 0; unsigned int tmtms = 0; unsigned char *pdata = NULL; gettimeofday(&tv0, NULL); //fprintf(stderr, "GET M3U... puri:'%s', hdrslen:%d\n", puri, pHdrCtxt->hdrslen); if(pHdrCtxt->hdrslen == 0) { if((httpcli_gethdrs(pHdrCtxt, pHttpResp, &pCfg->pSockList->salist[0], puri, http_getConnTypeStr(HTTP_CONN_TYPE_CLOSE), 0, 0, pCfg->pcommon->addrsExtHost[0], NULL)) < 0) { return NULL; } } if((pdata = http_get_contentlen_start(pHttpResp, pHdrCtxt, pbuf, szbuf, 1, &contentLen))) { consumed = pHdrCtxt->idxbuf - pHdrCtxt->hdrslen; } if(pdata && net_setsocknonblock(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]), 1) < 0) { pdata = NULL; } //fprintf(stderr, "NET_RECV in m3u... %d < %d idxbuf:%d hdrslen:%d pdata:0x%x\n", consumed, contentLen, pHdrCtxt->idxbuf, pHdrCtxt->hdrslen, pdata); while(pdata && consumed < contentLen && !g_proc_exit) { if((sz = netio_recvnb(&pCfg->pSockList->netsockets[0], (unsigned char *) &pdata[consumed], contentLen - consumed, 500)) > 0) { consumed += sz; } //fprintf(stderr, "NET REceiving... %d < %d, %d tmtms:%d\n", consumed, contentLen, sz, tmtms); gettimeofday(&tv1, NULL); if(tmtms > 0 && consumed < contentLen && TIME_TV_DIFF_MS(tv1, tv0) > (unsigned int) tmtms) { LOG(X_WARNING("HTTP %s:%d%s timeout %d ms exceeded"), inet_ntoa(pCfg->pSockList->salist[0].sin_addr), ntohs(pCfg->pSockList->salist[0].sin_port), puri, tmtms); pdata = NULL; break; } } if(pdata && contentLen > 0 && consumed >= contentLen) { pdata[consumed] = '\0'; } else { pdata = NULL; } //fprintf(stderr, "GOT m3u...0x%x %d < %d\n", pdata, consumed, contentLen);avc_dumpHex(stderr, pdata, consumed, 1); return (const char *) pdata; }
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); }
int http_flv_recvloop(CAP_ASYNC_DESCR_T *pCfg, unsigned int offset, int sz, FILE_OFFSET_T contentLen, unsigned char *pbuf, unsigned int szbuf, CAPTURE_STREAM_T *pStream) { CAP_HTTP_FLV_T ctxt; FLV_TAG_HDR_T *pTagHdr; unsigned char *pdata; unsigned int ts0 = 0; unsigned int ts; unsigned int tsoffset = 0; int havets0 = 0; TIME_VAL tm0, tm; unsigned int msElapsed; int do_sleep; int rc; memset(&ctxt, 0, sizeof(ctxt)); ctxt.common.pCfg = pCfg; ctxt.common.pdata = pbuf; ctxt.common.dataoffset = offset; ctxt.common.datasz = offset + sz; ctxt.pStream = pStream; //if(sz > 0) { // LOG(X_WARNING("Partial FLV HTTP Content-Header read offset %d not implemented. (offset:%d)"), sz, offset); //} if(net_setsocknonblock(NETIOSOCK_FD(pCfg->pSockList->netsockets[0]), 1) < 0) { return -1; } if(http_flv_init(&ctxt) < 0) { return -1; } // // Read 'FLV' 9 byte header // if(!(pdata = read_net_flv(&ctxt, 9))) { http_flv_close(&ctxt); return -1; } memcpy(&ctxt.flvhdr, pdata, 9); if(!(ctxt.flvhdr.type[0] == 'F' && ctxt.flvhdr.type[1] == 'L' && ctxt.flvhdr.type[2] == 'V' && ctxt.flvhdr.ver == FLV_HDR_VER_1)) { LOG(X_ERROR("Invalid HTTP FLV start sequence 0x%x 0x%x 0x%x 0x%x"), pdata[0], pdata[1], pdata[2], pdata[3]); http_flv_close(&ctxt); return -1; } if((FLV_HDR_HAVE_VIDEO((&ctxt.flvhdr)) && !ctxt.client.pQVid) || (FLV_HDR_HAVE_AUDIO((&ctxt.flvhdr)) && !ctxt.client.pQAud)) { LOG(X_ERROR("FLV capture input queue(s) not propery configured: video: %d, audio: %d"), ctxt.client.pQVid ? 1 : 0, ctxt.client.pQAud ? 1 : 0); http_flv_close(&ctxt); return -1; } tm0 = timer_GetTime(); if(pCfg->pcommon->caprealtime) { LOG(X_DEBUG("Treating capture as real-time.")); } do { if(!(pTagHdr = (FLV_TAG_HDR_T *) read_net_flv(&ctxt, FLV_TAG_HDR_SZ))) { return -1; } ctxt.taghdr.szprev = htonl(pTagHdr->szprev); ctxt.taghdr.type = pTagHdr->type; memcpy(&ctxt.taghdr.size32, &pTagHdr->size, 3); ctxt.taghdr.size32 = htonl(ctxt.taghdr.size32 << 8); memcpy(&ctxt.taghdr.timestamp32, &pTagHdr->timestamp, 3); ctxt.taghdr.timestamp32 = htonl(ctxt.taghdr.timestamp32 << 8); ctxt.taghdr.timestamp32 |= (pTagHdr->tsext << 24); // // For live content, initial timestamp may not always begin at 0 // if(!havets0) { if((ts0 = ctxt.taghdr.timestamp32) > 0) { havets0 = 1; } } else if(ctxt.taghdr.timestamp32 < ts0) { LOG(X_WARNING("HTTP FLV timestamp anamoly ts:%u, initial ts:%u (offset:%u)"), ctxt.taghdr.timestamp32, ts0, tsoffset); tsoffset += ts0; ts0 = ctxt.taghdr.timestamp32; } ts = ctxt.taghdr.timestamp32 - ts0 + tsoffset; //fprintf(stderr, "flv hdr type:0x%x sz:%d ts:%u(ts0:%u+%u) pkt_ts:%u\n", ctxt.taghdr.type, ctxt.taghdr.size32, ts, ts0, tsoffset, ctxt.taghdr.timestamp32); if(!(pdata = read_net_flv(&ctxt, ctxt.taghdr.size32))) { return -1; } // // For non-live content, throttle download rate inline with timestamps for real-time // restreaming // if(pCfg->pcommon->caprealtime) { do { do_sleep = 0; tm = timer_GetTime(); msElapsed = (unsigned int) (tm - tm0) / TIME_VAL_MS; //fprintf(stderr, "msElapsed:%d ts:%d %lld %lld\n", msElapsed, ctxt.taghdr.timestamp32, tm, tm0); if(msElapsed < ts) { if((do_sleep = ts - msElapsed) > 500) { do_sleep = 500; } //fprintf(stderr, "zzzz %d ms\n", do_sleep); usleep(do_sleep * 1000); } } while(do_sleep); } rc = 0; switch(ctxt.taghdr.type) { case FLV_TAG_VIDEODATA: rc = rtmp_handle_vidpkt(&ctxt.client, pdata, ctxt.taghdr.size32, ts); break; case FLV_TAG_AUDIODATA: rc = rtmp_handle_audpkt(&ctxt.client, pdata, ctxt.taghdr.size32, ts); case FLV_TAG_SCRIPTDATA: break; default: rc = -1; break; } if(rc < 0) { LOG(X_ERROR("Failed to process FLV packet type: 0x%x, len:%d"), ctxt.taghdr.type, ctxt.taghdr.size32); break; } } while(pCfg->running == 0 && (contentLen == 0 || ctxt.client.ctxt.bytesRead < contentLen) && !g_proc_exit); http_flv_close(&ctxt); return ctxt.client.ctxt.bytesRead; }
//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; }