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; }
int restrict_hostallowed(struct addrinfo *inf) { struct addrinfo *iter; #if ALLOW_ALL return 1; #endif #define INET_PORT(addr) ((struct sockaddr_in *)addr)->sin_port for(iter = ips; iter; iter = iter->ai_next){ /* * ports must be the same for memcmp * _major_ fixme right here * if the server ever switches to IPv6 */ INET_PORT(iter->ai_addr) = INET_PORT(inf->ai_addr); if(!memcmp(inf->ai_addr, iter->ai_addr, iter->ai_addrlen)) return 1; } return 0; }
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 capture_getdestFromStr(const char *str, struct sockaddr_storage *psa, const char **ppuri, char *hostbuf, uint16_t dfltPort) { char buf[CAPTURE_HTTP_HOSTBUF_MAXLEN]; unsigned int sz = 0; unsigned int idx; const char *p; const char *p2 = NULL; int have_onlyport = 1; int rc = 0; if(!str) { return -1; } if((p = strstr(str, "://"))) { str = p + 3; } p = str; if((p2 = strstr(p, ":")) || (p2 = strstr(p, "/"))) { sz = p2 - p; } else { sz = strlen(str); } for(idx = 0; idx < sz; idx++) { if(p[idx] < '0' || p[idx] > '9') { have_onlyport = 0; break; } } if(have_onlyport) { sz = 0; p2 = p; } if(hostbuf) { hostbuf[0] = '\0'; } if(psa && sz > 0) { if(sz >= sizeof(buf)) { sz = sizeof(buf) - 1; } memcpy(buf, p, sz); buf[sz] = '\0'; if(hostbuf) { memcpy(hostbuf, buf, sz + 1); } memset(psa, 0, sizeof(struct sockaddr_in)); if((rc = net_resolvehost(buf, psa)) != 0) { return rc; } /* psa->sin_family = AF_INET; if((psa->sin_addr.s_addr = net_resolvehost4(buf)) == INADDR_NONE) { return -1; } */ } if(p2 && (*p2 == ':' || have_onlyport)) { if(*p2 == ':') { p2++; } p = p2; if((p2 = strstr(p, "/"))) { sz = p2 - p; } else { sz = strlen(p); } if(psa) { if(sz >= sizeof(buf)) { sz = sizeof(buf) - 1; } memcpy(buf, p, sz); buf[sz] = '\0'; if((PINET_PORT(psa)= htons(atoi(buf))) == 0) { LOG(X_ERROR("Invalid destination port '%s' in '%s'"), buf, str); return -1; } } } else { INET_PORT(*psa) = htons(dfltPort); } if(ppuri) { *ppuri = p2; } //LOG(X_DEBUG("GETDESTFROMSTR str: '%s', have_onlyport: %d, hostbuf: '%s', uri: '%s', inet_ntop: '%s', port: %d"), str, have_onlyport, hostbuf, ppuri ? *ppuri : "", psa ? INET_NTOP(*psa, buf, sizeof(buf)) : "", psa ? htons(PINET_PORT(psa)) : -1); return 0; }
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; }
int rtspsrv_init(STREAM_RTSP_SESSIONS_T *pRtsp) { pthread_t ptdMonitor; struct sockaddr_storage sa; pthread_attr_t attrMonitor; RTSP_MONITOR_CTXT_T startCtxt; const char *s; if(!pRtsp || pRtsp->max <= 0) { return -1; } if(pRtsp->psessions) { avc_free((void *) &pRtsp->psessions); } destroy_rtspgetsessions(pRtsp); if(!(pRtsp->psessions = (RTSP_SESSION_T *) avc_calloc(pRtsp->max, sizeof(RTSP_SESSION_T)))) { return -1; } pRtsp->numRtspGetSessions = pRtsp->max * 2; if(!(pRtsp->pRtspGetSessionsBuf = (RTSP_HTTP_SESSION_T *) avc_calloc(pRtsp->numRtspGetSessions, sizeof(RTSP_HTTP_SESSION_T)))) { avc_free((void *) &pRtsp->psessions); pRtsp->numRtspGetSessions = 0; return -1; } pthread_mutex_init(&pRtsp->mtx, NULL); // // If all UDP / RTP sockets are bound to the same port then establish // the listener of this port prior to any RTSP interaction because some app // gateways may send some UDP polling data to the base port - and returning // an ICMP port unreachable would prevent such app gateways from allocating // UDP proxy ports // pRtsp->sockStaticLocalPort = INVALID_SOCKET; if(pRtsp->staticLocalPort > 0) { memset(&sa, 0, sizeof(sa)); sa.ss_family = AF_INET; ((struct sockaddr_in *) &sa)->sin_addr.s_addr = INADDR_ANY; INET_PORT(sa) = htons(pRtsp->staticLocalPort); if((pRtsp->sockStaticLocalPort = net_opensocket(SOCK_DGRAM, 0, 0, (struct sockaddr *) &sa)) == INVALID_SOCKET) { LOG(X_ERROR("Failed to open RTSP static local RTP port %d"), pRtsp->staticLocalPort); } else { if(net_setsocknonblock(pRtsp->sockStaticLocalPort, 1) < 0) { LOG(X_ERROR("Failed to listen on RTSP static local RTP port %d"), pRtsp->staticLocalPort); net_closesocket(&pRtsp->sockStaticLocalPort); } } //if(pRtsp->sockStaticLocalPort != INVALID_SOCKET) { // sain.sin_addr.s_addr = inet_addr("127.0.0.1"); // rc = sendto(pRtsp->sockStaticLocalPort, &sain, 1, 0, (struct sockaddr *) &sain, sizeof(sain)); // fprintf(stderr, "SENDTO:%d\n", rc); //} } // // Parse any CSV of quoted User-Agent matches which should try to force TCP interleaved mode // pRtsp->rtspForceTcpUAList.count = 0; if(pRtsp->rtspForceTcpUAList.str) { strutil_parse_csv(cbparse_entry_rtspua, pRtsp, pRtsp->rtspForceTcpUAList.str); } pRtsp->runMonitor = 2; memset(&startCtxt, 0, sizeof(startCtxt)); startCtxt.pRtsp = pRtsp; if((s = logutil_tid_lookup(pthread_self(), 0)) && s[0] != '\0') { snprintf(startCtxt.tid_tag, sizeof(startCtxt.tid_tag), "%s-rtspmon", s); } pthread_attr_init(&attrMonitor); pthread_attr_setdetachstate(&attrMonitor, PTHREAD_CREATE_DETACHED); if(pthread_create(&ptdMonitor, &attrMonitor, (void *) rtsp_monitor_proc, (void *) &startCtxt) != 0) { LOG(X_ERROR("Unable to create RTP monitor thread")); pRtsp->runMonitor = 0; if(pRtsp->psessions) { avc_free((void *) &pRtsp->psessions); } destroy_rtspgetsessions(pRtsp); pthread_mutex_destroy(&pRtsp->mtx); } while(pRtsp->runMonitor != 1 && pRtsp->runMonitor != -1) { usleep(5000); } return 0; }
static int streamxmit_retransmitRtp(STREAM_RTP_DEST_T *pDest) { STREAMXMIT_PKT_HDR_T *pktHdr; unsigned int idxRd; unsigned int count = 0; int lastWasExpired = 0; int rc; int haveRequestedRetransmission = 0; const PKTQUEUE_PKT_T *pQPkt = NULL; STREAM_XMIT_QUEUE_T *pAsyncQ = &pDest->asyncQ; TIME_VAL tvNow; struct timeval tv; float kbps; char tmp[128]; tvNow = timer_GetTime(); TV_FROM_TIMEVAL(tv, tvNow); pthread_mutex_lock(&pAsyncQ->mtx); idxRd = pAsyncQ->pQ->idxRd; //LOG(X_DEBUG("NACK streamxmit_iterate ... idxRd:%d, idxWr:%d / %d"), pAsyncQ->pQ->idxRd, pAsyncQ->pQ->idxWr, pAsyncQ->pQ->cfg.maxPkts); while(count++ < pAsyncQ->pQ->cfg.maxPkts) { pQPkt = &pAsyncQ->pQ->pkts[idxRd]; if(!(pQPkt->flags & PKTQUEUE_FLAG_HAVEPKTDATA)) { //LOG(X_DEBUG("NACK streamxmit_iterate break at qid[%d]"), idxRd); break; } //LOG(X_DEBUG("NACK streamxmit_iterate check qid[%d] seqno:%d, %lld ms ago"), idxRd, ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->seqNum, (tvNow - ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->tvxmit)/1000); lastWasExpired = 0; if(!(pktHdr = (STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)) { pAsyncQ->pQ->idxRd = idxRd; fprintf(stderr, "streamxmit_itertate should never get here... idxRd:%d\n", idxRd); } else if(pktHdr->tvXmit + (pAsyncQ->nackHistoryMs * TIME_VAL_MS) < tvNow) { // // The queue slot RTP sequence number came before the NACK starting sequence number // so the current queue content is before the scope of the NACK // if(pktHdr->doRetransmit > 0) { pktHdr->doRetransmit = -1; if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_AGED, .5f); } } pAsyncQ->pQ->idxRd = idxRd; pAsyncQ->pQ->pkts[idxRd].flags = 0; lastWasExpired = 1; //LOG(X_DEBUG("NACK streamxmit_iterate old here marked to -1 ... idxRd:%d, seqNum:%d"), idxRd, pktHdr->seqNum); } else if(pktHdr->doRetransmit > 0 && !pktHdr->rtcp) { if(pktHdr->tvLastRetransmit == 0 || pktHdr->tvLastRetransmit + (RTP_RETRANSMIT_INTERVAL_MS * TIME_VAL_MS) < tvNow) { // // Ensure that the retransmission will not exceed our retransmission bitrate limit // if(pAsyncQ->retransmissionKbpsMax > 0 && burstmeter_updateCounters(&pAsyncQ->retransmissionMeter, &tv) == 0 && (kbps = (burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)/THROUGHPUT_BYTES_IN_KILO_F)) >= pAsyncQ->retransmissionKbpsMax) { LOG(X_WARNING("RTP NACK retransmission bitrate %.3f >= %.3f throttled pt:%d sequence:%d to %s:%d, for original %d ms ago."), kbps, pAsyncQ->retransmissionKbpsMax, pDest->pRtpMulti->init.pt, pktHdr->seqNum, FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)), (tvNow - pktHdr->tvXmit) / TIME_VAL_MS); if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_THROTTLED, .5f); } pktHdr->doRetransmit = 0; pktHdr->tvLastRetransmit = tvNow; } else { burstmeter_AddSample(&pAsyncQ->retransmissionMeter, pQPkt->len, &tv); //LOG(X_DEBUG("RTP NACK Retransmission bitrate: %.3f %s (%.3f bps)"), (float) pAsyncQ->retransmissionMeter.meter.rangeMs/1000, burstmeter_printThroughputStr(buf, sizeof(buf), &pAsyncQ->retransmissionMeter), (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)); // // Retransmit the RTP packet // LOG(X_DEBUG("RTP NACK retransmitting pt:%d sequence:%d, len:%d to %s:%d, original sent %d ms ago. " "Rate: %.3f pkts/s, %.3f b/s"), pDest->pRtpMulti->init.pt, pktHdr->seqNum, pQPkt->len, FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)), (tvNow - pktHdr->tvXmit) / TIME_VAL_MS, (float) burstmeter_getPacketratePs(&pAsyncQ->retransmissionMeter), (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)); if((rc = srtp_sendto(STREAM_RTP_PNETIOSOCK(*pDest), (void *) pQPkt->pData, pQPkt->len, 0, (const struct sockaddr *) &pDest->saDsts, NULL, SENDTO_PKT_TYPE_RTP, 1)) < 0) { pktHdr->doRetransmit = -1; } else { pktHdr->doRetransmit = 0; } pktHdr->tvLastRetransmit = tvNow; if(pDest->pstreamStats) { stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, STREAM_ABR_UPDATE_REASON_NACK_RETRANSMITTED, .5f); } } } else { haveRequestedRetransmission = 1; } } if(++idxRd >= pAsyncQ->pQ->cfg.maxPkts) { idxRd = 0; } if(lastWasExpired) { pAsyncQ->pQ->idxRd = idxRd; } } // end of while... pAsyncQ->haveRequestedRetransmission = haveRequestedRetransmission; pthread_mutex_unlock(&pAsyncQ->mtx); return haveRequestedRetransmission; }
int srv_ctrl_pip(CLIENT_CONN_T *pConn) { int rc = 0; int rcTmp; enum HTTP_STATUS statusCode = HTTP_STATUS_OK; const char *parg; PIP_CFG_T pipCfg; IXCODE_VIDEO_CROP_T crop; IXCODE_PIP_MOTION_T *pipMotion = NULL; int idx = 0; int pip_id = 0; int do_stop = 0; int do_start = 0; int do_update = 0; int do_status = 0; int do_crop = 0; STUN_POLICY_T stunPolicy; int activePipIds[MAX_PIPS]; const char *do_pipconf = NULL; unsigned int idxResp; char tmp[128]; char buf[1024]; char respExtra[512]; STREAMER_CFG_T *pCfg = NULL; char *strxcodebuf = NULL; LOG(X_DEBUG("Received PIP command %s%s from %s:%d"), pConn->httpReq.puri, http_req_dump_uri(&pConn->httpReq, buf, sizeof(buf)), FORMAT_NETADDR(pConn->sd.sa, tmp, sizeof(tmp)), htons(INET_PORT(pConn->sd.sa))); buf[0] = '\0'; respExtra[0] = '\0'; if(pConn->pStreamerCfg0 && pConn->pStreamerCfg0->running >= 0) { pCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg0; } else if(pConn->pStreamerCfg1 && pConn->pStreamerCfg1->running >= 0) { pCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg1; } if(pCfg) { memset(&crop, 0, sizeof(crop)); if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_TOP))) { crop.padTop = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_BOTTOM))) { crop.padBottom = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_LEFT))) { crop.padLeft = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_RGB))) { strutil_read_rgb(parg, crop.padRGB); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_RIGHT))) { crop.padRight = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_TOP))) { crop.cropTop = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_BOTTOM))) { crop.cropBottom = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_LEFT))) { crop.cropLeft = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_RIGHT))) { crop.cropRight = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_ASPECT_RATIO))) { crop.padAspectR = atoi(parg); do_crop = 1; } if(do_crop) { if((rc = xcode_set_crop_pad(&crop, &pCfg->xcode.vid.out[0], crop.padAspectR, pCfg->xcode.vid.out[0].resOutH, pCfg->xcode.vid.out[0].resOutV, 0, 0)) < 0) { LOG(X_ERROR("Invalid picture pad / crop dimensions")); } else { //TODO: updating these params does not work via xcode ipc //TODO: this should be atomic w/ respect to xcoder memcpy(&pCfg->xcode.vid.out[0].crop, &crop, sizeof(pCfg->xcode.vid.out[0].crop)); } } memset(&pipCfg, 0, sizeof(pipCfg)); pipCfg.rtpPktzMode = -1; pipCfg.dtls_handshake_server = -1; if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstatus"))) { do_status = 1; pip_id = atoi(parg); } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstop"))) { do_stop = 1; pip_id = atoi(parg); } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstart"))) { if(atoi(parg) > 0) { do_start = 1; } } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipupdate"))) { // start a PIP which was previously started with 'delaystart' parameter if((pip_id = atoi(parg)) > 0) { do_update = 1; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipconf"))) { do_pipconf = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxcode")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "xcode"))) { pipCfg.strxcode = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pip")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "in")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "input"))) { pipCfg.input = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "out")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "output"))) { pipCfg.output = parg; //pipCfg.output="dtlssrtp://127.0.0.1:5000,5008"; //pipCfg.output="srtp://127.0.0.1:5000,5000"; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "tslive"))) { pipCfg.tsliveaddr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtppayloadtype"))) { pipCfg.output_rtpptstr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtpssrc"))) { pipCfg.output_rtpssrcsstr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "mtu"))) { pipCfg.mtu = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtppktzmode"))) { pipCfg.rtpPktzMode = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtcpports"))) { pipCfg.rtcpPorts = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "srtpkey"))) { pipCfg.srtpKeysBase64 = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtls"))) { pipCfg.use_dtls = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlssrtp"))) { pipCfg.use_dtls = pipCfg.use_srtp = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsserver"))) { pipCfg.dtls_handshake_server = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsclient"))) { pipCfg.dtls_handshake_server = !atoi(parg); } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsoutserverkey"))) { // pipCfg.dtls_xmit_serverkey = atoi(parg); // } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsinserverkey")) || // (parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsserverkey"))) { // pipCfg.dtls_capture_serverkey = atoi(parg); //} if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrespond"))) { if((stunPolicy = atoi(parg)) != STUN_POLICY_ENABLED) { stunPolicy = STUN_POLICY_NONE; } if((pipCfg.stunBindingResponse = stunPolicy) != STUN_POLICY_NONE) { pipCfg.stunRespUseSDPIceufrag = 1; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestuser"))) { pipCfg.stunReqUsername = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestpass"))) { pipCfg.stunReqPass = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestrealm"))) { pipCfg.stunReqRealm = parg; } if(pipCfg.stunBindingRequest == STUN_POLICY_NONE && (pipCfg.stunReqUsername || pipCfg.stunReqPass || pipCfg.stunReqRealm)) { pipCfg.stunBindingRequest = STUN_POLICY_XMIT_IF_RCVD; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequest"))) { stunPolicy = atoi(parg); pipCfg.stunBindingRequest = stunPolicy; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnuser"))) { pipCfg.turnCfg.turnUsername = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnpass"))) { pipCfg.turnCfg.turnPass = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnrealm"))) { pipCfg.turnCfg.turnRealm = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnserver"))) { pipCfg.turnCfg.turnServer = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnpeer"))) { pipCfg.turnCfg.turnPeerRelay = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnsdp"))) { pipCfg.turnCfg.turnSdpOutPath = parg; } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnout"))) { // pipCfg.turnCfg.turnOutput = parg; //} else if(pipCfg.turnCfg.turnServer) { // pipCfg.turnCfg.turnOutput = pipCfg.turnCfg.turnServer; //} if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "delaystart"))) { pipCfg.delayed_output = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "abrself"))) { pipCfg.abrSelf = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "abrauto")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "abr"))) { pipCfg.abrAuto = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "piplayout")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "layout"))) { pipCfg.layoutType = pip_str2layout(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipx")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxleft")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxright"))) { pipCfg.posx = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipy")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipytop")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipybottom"))) { pipCfg.posy = atoi(parg); } // PIP_KEY_ZORDER "zorder" if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipzorder")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "zorder"))) { pipCfg.zorder = atoi(parg); } // PIP_KEY_NOAUDIO if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipnoaudio")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "noaud")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "noaudio"))) { pipCfg.noaud = 1; } // PIP_KEY_NOVIDEO if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipnovideo")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "novid")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "novideo"))) { pipCfg.novid = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "duplicate"))) { pipCfg.allowDuplicate = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "startchime"))) { pipCfg.startChimeFile = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stopchime"))) { pipCfg.stopChimeFile = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtpretransmit"))) { pipCfg.nackRtpRetransmitVideo = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitmaxrate"))) { pipCfg.apprembRtcpSendVideoMaxRateBps = (unsigned int) strutil_read_numeric(optarg, 0, 1000, 0); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitminrate"))) { pipCfg.apprembRtcpSendVideoMinRateBps = (unsigned int) strutil_read_numeric(optarg, 0, 1000, 0); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitforce"))) { pipCfg.apprembRtcpSendVideoForceAdjustment = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipalphamax"))) { pipCfg.alphamax_min1 = atoi(parg) + 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipalphamin"))) { pipCfg.alphamin_min1 = atoi(parg) + 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipbefore"))) { if(atoi(parg) > 0) { pipCfg.flags |= PIP_FLAGS_INSERT_BEFORE_SCALE; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxright"))) { pipCfg.flags |= PIP_FLAGS_POSITION_RIGHT; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipybottom"))) { pipCfg.flags |= PIP_FLAGS_POSITION_BOTTOM; } // // Read the PIP configuration from a fiel // if(do_pipconf) { pipCfg.cfgfile = do_pipconf; //if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0 && idx < MAX_PIPS && pCfg->pStorageBuf) { // strxcodebuf = ((STREAM_STORAGE_T *) pCfg->pStorageBuf)->pipxcodeStrbuf[idx]; if(pCfg->pStorageBuf) { //TODO: if we're all going to use the same buffer (temporarily) we need some locking here... strxcodebuf = ((STREAM_STORAGE_T *) pCfg->pStorageBuf)->pipxcodeStrbuf[0]; } if((pipMotion = pip_read_conf(&pipCfg, pCfg->status.pathFile, strxcodebuf))) { do_start = 1; do_stop = 0; } else { } } if(do_status) { if(pip_id == -1) { if((rc = pip_getActiveIds(pCfg, activePipIds, 1)) > 0) { idxResp = 0; if((rcTmp = snprintf(respExtra, sizeof(respExtra), "&ids=")) > 0) { idxResp += rcTmp; } for(idx = 0; idx < rc; idx++) { if((rcTmp = snprintf(&respExtra[idxResp], sizeof(respExtra) - idxResp, "%s%d", idx > 0 ? "," : "", activePipIds[idx])) > 0) { idxResp += rcTmp; } } } } else if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0) { rc = pip_id; } else { rc = -1; } } else if(do_update) { if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0) { rc = pip_update(&pipCfg, pCfg, pip_id); } else { do_update = 0; } } else if(do_stop) { if((rc = pip_stop(pCfg, pip_id)) < 0) { LOG(X_ERROR("Failed to stop PIP[%d]"), pip_id); } } else if(do_start && rc >= 0) { rc = pip_start(&pipCfg, pCfg, pipMotion); } // // The html body response // snprintf(buf, sizeof(buf), "code=%d%s", rc, respExtra[0] != '\0' ? respExtra : ""); } else { rc = -1; } if(rc < 0) { statusCode = HTTP_STATUS_SERVERERROR; } rc = http_resp_send(&pConn->sd, &pConn->httpReq, statusCode, (unsigned char *) buf, strlen(buf)); LOG(X_DEBUG("Sent PIP response '%s' to %s:%d"), buf, FORMAT_NETADDR(pConn->sd.sa, tmp, sizeof(tmp)), htons(INET_PORT(pConn->sd.sa))); return rc; }