예제 #1
0
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...
예제 #2
0
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;
}
예제 #3
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}
예제 #6
0
파일: procdb.c 프로젝트: mmashimaro/openvcx
//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;
}