int net_connect_tmt(SOCKET sock, const struct sockaddr *psa, unsigned int mstmt) { int rc = 0; struct timeval tv; fd_set fdsetRd, fdsetWr; char tmp[128]; int try = 0; if(sock == INVALID_SOCKET || !psa) { return -1; } else if(mstmt == 0) { return net_connect(sock, psa); } VSX_DEBUG_NET( LOG(X_DEBUG("NET - net_connect family: %d, fd: %d, trying to %s:%d with timeout %d ms"), psa->sa_family, sock, FORMAT_NETADDR(*psa, tmp, sizeof(tmp)), ntohs(PINET_PORT(psa)), mstmt) ); if((rc = net_setsocknonblock(sock, 1)) < 0) { return rc; } do { if((rc = connect(sock, psa, (socklen_t) INET_SIZE(*psa))) != 0) { if(errno == EINPROGRESS) { tv.tv_sec = (mstmt / 1000); tv.tv_usec = (mstmt % 1000) * 1000; FD_ZERO(&fdsetRd); FD_SET(sock, &fdsetRd); FD_ZERO(&fdsetWr); FD_SET(sock, &fdsetWr); if((rc = select(sock + 1, &fdsetRd, &fdsetWr, NULL, &tv)) > 0) { // call connect again to see if it was succesful try++; rc = -1; } else if(rc == 0) { // timeout expired rc = -1; errno = ETIMEDOUT; break; } else { // select error break; } } else if(errno == EISCONN && try > 0) { // already connected rc = 0; break; } else { // connect failure rc = -1; break; } } // end of if((rc = connect...
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 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_mp4_recv(CAP_ASYNC_DESCR_T *pCfg, NETIO_SOCK_T *pNetSock, const struct sockaddr *psa, FILE_OFFSET_T contentLen, HTTP_PARSE_CTXT_T *pHdrCtxt, const char *outPath) { //CAP_HTTP_MP4_STREAM_T *pCapHttpMp4Stream) { //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; CAP_HTTP_MP4_T capHttpMp4; CAP_HTTP_MP4_STREAM_T *pCapHttpMp4Stream = NULL; unsigned int bytesRead = 0; //unsigned char arena[4096]; if(!pCfg || !pNetSock || !psa || !pHdrCtxt) { return -1; } pCapHttpMp4Stream = (CAP_HTTP_MP4_STREAM_T *) pCfg->pUserData; memset(&capHttpMp4, 0, sizeof(capHttpMp4)); capHttpMp4.common.pCfg = pCfg; capHttpMp4.common.pdata = (unsigned char *) pHdrCtxt->pbuf; capHttpMp4.common.dataoffset = pHdrCtxt->hdrslen; capHttpMp4.common.datasz = pHdrCtxt->idxbuf; capHttpMp4.mp4NetStream.pNetSock = pNetSock; capHttpMp4.mp4NetStream.psa = psa; capHttpMp4.mp4NetStream.rcvTmtMs = 10000; capHttpMp4.mp4NetStream.pCapHttpMp4 = &capHttpMp4; if(net_setsocknonblock(PNETIOSOCK_FD(capHttpMp4.mp4NetStream.pNetSock), 1) < 0) { return -1; } if(outPath) { snprintf(capHttpMp4.rcvState.fStream.filename, sizeof(capHttpMp4.rcvState.fStream.filename), "%s", outPath); } else { // // Create an output filename for the downloaded mp4 file // snprintf(capHttpMp4.rcvState.fStream.filename, sizeof(capHttpMp4.rcvState.fStream.filename), "%s%c%s_%d.mp4", "tmp", DIR_DELIMETER, "dl", getpid()); } capHttpMp4.rcvState.fStream.fp = FILEOPS_INVALID_FP; if(http_mp4_init(&capHttpMp4) < 0) { return -1; } //fprintf(stderr, "MOOF WILL RCV outPath:'%s'\n", outPath); // // Indicate to the stream outupt that this mp4/moof is being downloaded // if(pCapHttpMp4Stream) { mpdpl_add(&pCapHttpMp4Stream->pl, capHttpMp4.rcvState.fStream.filename, PLAYLIST_MPD_STATE_DOWNLOADING); } // // Using the mp4 based file reader will parse all box contents, which will be duplicated // when using the stream_mp4 based file based reader for mp4 transmission // //rc = mp4_read_boxes(capHttpMp4.pMp4FromNet->pStream, capHttpMp4.pMp4FromNet->proot, arena, sizeof(arena)); // // The http mp4 based reader only looks at the first level box nesting // rc = http_mp4_read_boxes(pCfg, &capHttpMp4, contentLen); bytesRead = capHttpMp4.pMp4FromNet->pStream->offset; // // Indicate to the stream outupt that this mp4/moof has been downloaded // if(pCapHttpMp4Stream) { mpdpl_update(&pCapHttpMp4Stream->pl, capHttpMp4.rcvState.fStream.filename, rc >= 0 ? PLAYLIST_MPD_STATE_DOWNLOADED : PLAYLIST_MPD_STATE_ERROR); } fprintf(stderr, "MOOF mp4_read_boxes done rc:%d, bytesRead:%d, contentLen:%llu\n", rc, bytesRead, contentLen); //tm0 = timer_GetTime(); //if(pCfg->pcommon->caprealtime) { // LOG(X_DEBUG("Treating capture as real-time.")); //} //TODO: should signal the transmitter thread //pthread_mutex_lock(&pCfg->mtx); //pCfg->pUserData = NULL; //pthread_mutex_unlock(&pCfg->mtx); http_mp4_close(&capHttpMp4); return bytesRead; }
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; }