rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth,
  char *username, char *password) {

  char *description=NULL;
  char *session_id=NULL;
  rmff_header_t *h = NULL;
  char *challenge1 = NULL;
  char challenge2[41];
  char checksum[9];
  char *subscribe = NULL;
  char *buf = xbuffer_init(256);
  char *mrl=rtsp_get_mrl(rtsp_session);
  unsigned int size;
  int status;
  uint32_t maxbandwidth = bandwidth;
  char* authfield = NULL;
  int i;

  /* get challenge */
  challenge1=rtsp_search_answers(rtsp_session,"RealChallenge1");
  if (!challenge1)
      goto out;
  challenge1=strdup(challenge1);
#ifdef LOG
  printf("real: Challenge1: %s\n", challenge1);
#endif

  /* set a reasonable default to get the best stream, unless bandwidth given */
  if (!bandwidth)
      bandwidth = 10485800;

  /* request stream description */
rtsp_send_describe:
  rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
  sprintf(buf, "Bandwidth: %u", bandwidth);
  rtsp_schedule_field(rtsp_session, buf);
  rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
  rtsp_schedule_field(rtsp_session, "RegionData: 0");
  rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
  rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
  rtsp_schedule_field(rtsp_session, "Language: en-US");
  rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
  if(authfield)
    rtsp_schedule_field(rtsp_session, authfield);
  status=rtsp_request_describe(rtsp_session,NULL);

  if (status == 401) {
    int authlen, b64_authlen;
    char *authreq;
    char* authstr = NULL;

    if (authfield) {
      mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: authorization failed, check your credentials\n");
      goto autherr;
    }
    if (!(authreq = rtsp_search_answers(rtsp_session,"WWW-Authenticate"))) {
      mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: 401 but no auth request, aborting\n");
      goto autherr;
    }
    if (!username) {
      mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: auth required but no username supplied\n");
      goto autherr;
    }
    if (!strstr(authreq, "Basic")) {
      mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: authenticator not supported (%s)\n", authreq);
      goto autherr;
    }
    authlen = strlen(username) + (password ? strlen(password) : 0) + 2;
    authstr = malloc(authlen);
    sprintf(authstr, "%s:%s", username, password ? password : "");
    authfield = malloc(authlen*2+22);
    strcpy(authfield, "Authorization: Basic ");
    b64_authlen = base64_encode(authstr, authlen, authfield+21, authlen*2);
    free(authstr);
    if (b64_authlen < 0) {
      mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: base64 output overflow, this should never happen\n");
      goto autherr;
    }
    authfield[b64_authlen+21] = 0;
    goto rtsp_send_describe;
  }
autherr:

  if (authfield)
     free(authfield);

  if ( status<200 || status>299 )
  {
    char *alert=rtsp_search_answers(rtsp_session,"Alert");
    if (alert) {
      mp_msg(MSGT_STREAM, MSGL_WARN, "realrtsp: got message from server:\n%s\n",
        alert);
    }
    rtsp_send_ok(rtsp_session);
    goto out;
  }

  /* receive description */
  size=0;
  if (!rtsp_search_answers(rtsp_session,"Content-length"))
    mp_msg(MSGT_STREAM, MSGL_WARN, "real: got no Content-length!\n");
  else
    size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));

  // as size is unsigned this also catches the case (size < 0)
  if (size > MAX_DESC_BUF) {
    mp_msg(MSGT_STREAM, MSGL_ERR, "realrtsp: Content-length for description too big (> %uMB)!\n",
            MAX_DESC_BUF/(1024*1024) );
    goto out;
  }

  if (!rtsp_search_answers(rtsp_session,"ETag"))
    mp_msg(MSGT_STREAM, MSGL_WARN, "realrtsp: got no ETag!\n");
  else
    session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));

#ifdef LOG
  printf("real: Stream description size: %u\n", size);
#endif

  description=malloc(size+1);

  if( rtsp_read_data(rtsp_session, description, size) <= 0) {
    goto out;
  }
  description[size]=0;

  /* parse sdp (sdpplin) and create a header and a subscribe string */
  subscribe = xbuffer_init(256);
  strcpy(subscribe, "Subscribe: ");
  h=real_parse_sdp(description, &subscribe, bandwidth);
  if (!h) {
    goto out;
  }
  rmff_fix_header(h);

#ifdef LOG
  printf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
    h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
#endif

  /* setup our streams */
  real_calc_response_and_checksum (challenge2, checksum, challenge1);
  buf = xbuffer_ensure_size(buf, strlen(challenge2) + strlen(checksum) + 32);
  sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
  rtsp_schedule_field(rtsp_session, buf);
  buf = xbuffer_ensure_size(buf, strlen(session_id) + 32);
  sprintf(buf, "If-Match: %s", session_id);
  rtsp_schedule_field(rtsp_session, buf);
  rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
  buf = xbuffer_ensure_size(buf, strlen(mrl) + 32);
  sprintf(buf, "%s/streamid=0", mrl);
  rtsp_request_setup(rtsp_session,buf,NULL);

  /* Do setup for all the other streams we subscribed to */
  for (i = 1; i < h->prop->num_streams; i++) {
    rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
    buf = xbuffer_ensure_size(buf, strlen(session_id) + 32);
    sprintf(buf, "If-Match: %s", session_id);
    rtsp_schedule_field(rtsp_session, buf);

    buf = xbuffer_ensure_size(buf, strlen(mrl) + 32);
    sprintf(buf, "%s/streamid=%d", mrl, i);
    rtsp_request_setup(rtsp_session,buf,NULL);
  }
  /* set stream parameter (bandwidth) with our subscribe string */
  rtsp_schedule_field(rtsp_session, subscribe);
  rtsp_request_setparameter(rtsp_session,NULL);

  /* set delivery bandwidth */
  if (maxbandwidth) {
      sprintf(buf, "SetDeliveryBandwidth: Bandwidth=%u;BackOff=0", maxbandwidth);
      rtsp_schedule_field(rtsp_session, buf);
      rtsp_request_setparameter(rtsp_session,NULL);
  }

  {
    int s_ss = 0, s_ms = 0, e_ss = 0, e_ms = 0;
    char *str;
    if ((str = rtsp_get_param(rtsp_session, "start"))) {
      convert_timestamp(str, &s_ss, &s_ms);
      free(str);
    }
    if ((str = rtsp_get_param(rtsp_session, "end"))) {
      convert_timestamp(str, &e_ss, &e_ms);
      free(str);
    }
    str = buf + sprintf(buf, s_ms ? "%s%d.%d-" : "%s%d-", "Range: npt=", s_ss, s_ms);
    if (e_ss || e_ms)
      sprintf(str, e_ms ? "%d.%d" : "%d", e_ss, e_ms);
  }
  rtsp_schedule_field(rtsp_session, buf);
  /* and finally send a play request */
  rtsp_request_play(rtsp_session,NULL);

out:
  subscribe = xbuffer_free(subscribe);
  buf = xbuffer_free(buf);
  free(description);
  free(session_id);
  free(challenge1);
  return h;
}
예제 #2
0
파일: access.c 프로젝트: 371816210/vlc_vlc
/*****************************************************************************
 * Open: open the rtsp connection
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    access_t *p_access = (access_t *)p_this;
    access_sys_t *p_sys;
    char* psz_server = NULL;
    int i_result;

    if( !p_access->psz_access || (
        strncmp( p_access->psz_access, "rtsp", 4 ) &&
        strncmp( p_access->psz_access, "pnm", 3 )  &&
        strncmp( p_access->psz_access, "realrtsp", 8 ) ))
    {
            return VLC_EGENERIC;
    }

    p_access->pf_read = NULL;
    p_access->pf_block = BlockRead;
    p_access->pf_seek = Seek;
    p_access->pf_control = Control;
    p_access->info.i_pos = 0;
    p_access->info.b_eof = false;
    p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
    if( !p_sys )
        return VLC_ENOMEM;
    p_sys->p_rtsp = malloc( sizeof( rtsp_client_t) );
    if( !p_sys->p_rtsp )
    {
        free( p_sys );
        return VLC_ENOMEM;
    }

    p_sys->p_header = NULL;
    p_sys->p_rtsp->p_userdata = p_access;
    p_sys->p_rtsp->pf_connect = RtspConnect;
    p_sys->p_rtsp->pf_disconnect = RtspDisconnect;
    p_sys->p_rtsp->pf_read = RtspRead;
    p_sys->p_rtsp->pf_read_line = RtspReadLine;
    p_sys->p_rtsp->pf_write = RtspWrite;

    i_result = rtsp_connect( p_sys->p_rtsp, p_access->psz_location, 0 );
    if( i_result )
    {
        msg_Dbg( p_access, "could not connect to: %s", p_access->psz_location );
        free( p_sys->p_rtsp );
        p_sys->p_rtsp = NULL;
        goto error;
    }

    msg_Dbg( p_access, "rtsp connected" );

    /* looking for server type */
    if( rtsp_search_answers( p_sys->p_rtsp, "Server" ) )
        psz_server = strdup( rtsp_search_answers( p_sys->p_rtsp, "Server" ) );
    else
    {
        if( rtsp_search_answers( p_sys->p_rtsp, "RealChallenge1" ) )
            psz_server = strdup("Real");
        else
            psz_server = strdup("unknown");
    }

    if( strstr( psz_server, "Real" ) || strstr( psz_server, "Helix" ) )
    {
        uint32_t bandwidth = 10485800;
        rmff_header_t *h;

        msg_Dbg( p_access, "found a real/helix rtsp server" );

        if( !(h = real_setup_and_get_header( p_sys->p_rtsp, bandwidth )) )
        {
            /* Check if we got a redirect */
            if( rtsp_search_answers( p_sys->p_rtsp, "Location" ) )
            {
                msg_Dbg( p_access, "redirect: %s",
                         rtsp_search_answers(p_sys->p_rtsp, "Location") );
                msg_Warn( p_access, "redirect not supported" );
                goto error;
            }


            msg_Err( p_access, "rtsp session can not be established" );
            dialog_Fatal( p_access, _("Session failed"), "%s",
                    _("The requested RTSP session could not be established.") );
            goto error;
        }

        p_sys->p_header = block_Alloc( 4096 );
        p_sys->p_header->i_buffer =
            rmff_dump_header( h, (char *)p_sys->p_header->p_buffer, 1024 );
        rmff_free_header( h );
    }
    else
    {
        msg_Warn( p_access, "only real/helix rtsp servers supported for now" );
        goto error;
    }

    free( psz_server );
    return VLC_SUCCESS;

 error:
    free( psz_server );
    Close( p_this );
    return VLC_EGENERIC;
}
예제 #3
0
rtsp_session_t *rtsp_session_start(xine_stream_t *stream, char *mrl) {

  rtsp_session_t *rtsp_session = calloc(1, sizeof(rtsp_session_t));
  xine_t *xine = stream->xine;
  char *server;
  char *mrl_line=strdup(mrl);
  rmff_header_t *h;
  int bandwidth_id;
  uint32_t bandwidth;

  bandwidth_id = xine->config->register_enum(xine->config, "media.network.bandwidth", 10,
			      rtsp_bandwidth_strs,
			      _("network bandwidth"),
			      _("Specify the bandwidth of your internet connection here. "
			        "This will be used when streaming servers offer different versions "
              "with different bandwidth requirements of the same stream."),
			      0, NULL, NULL);
  bandwidth = rtsp_bandwidths[bandwidth_id];

  rtsp_session->recv = xine_buffer_init(BUF_SIZE);

connect:

  /* connect to server */
  rtsp_session->s=rtsp_connect(stream, mrl_line, NULL);
  if (!rtsp_session->s)
  {
    xprintf(stream->xine, XINE_VERBOSITY_LOG,
	    _("rtsp_session: failed to connect to server %s\n"), mrl_line);
    xine_buffer_free(rtsp_session->recv);
    free(rtsp_session);
    return NULL;
  }

  /* looking for server type */
  if (rtsp_search_answers(rtsp_session->s,"Server"))
    server=strdup(rtsp_search_answers(rtsp_session->s,"Server"));
  else {
    if (rtsp_search_answers(rtsp_session->s,"RealChallenge1"))
      server=strdup("Real");
    else
      server=strdup("unknown");
  }

  if (strstr(server,"Real") || strstr(server,"Helix"))
  {
    /* we are talking to a real server ... */

    h=real_setup_and_get_header(rtsp_session->s, bandwidth);
    if (!h) {
      /* got an redirect? */
      if (rtsp_search_answers(rtsp_session->s, "Location"))
      {
        free(mrl_line);
	mrl_line=strdup(rtsp_search_answers(rtsp_session->s, "Location"));
        xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "rtsp_session: redirected to %s\n", mrl_line);
	rtsp_close(rtsp_session->s);
	free(server);
	goto connect; /* *shudder* i made a design mistake somewhere */
      } else
      {
        xprintf(stream->xine, XINE_VERBOSITY_LOG,
		_("rtsp_session: session can not be established.\n"));
        rtsp_close(rtsp_session->s);
        xine_buffer_free(rtsp_session->recv);
        free(rtsp_session);
        return NULL;
      }
    }

	  rtsp_session->header_left =
    rtsp_session->header_len  = rmff_dump_header(h,rtsp_session->header,HEADER_SIZE);
    if (rtsp_session->header_len < 0) {
      xprintf (stream->xine, XINE_VERBOSITY_LOG,
	       _("rtsp_session: rtsp server returned overly-large headers, session can not be established.\n"));
      goto session_abort;
    }

    xine_buffer_copyin(rtsp_session->recv, 0, rtsp_session->header, rtsp_session->header_len);
    rtsp_session->recv_size = rtsp_session->header_len;
    rtsp_session->recv_read = 0;

  } else
  {
    xprintf(stream->xine, XINE_VERBOSITY_LOG,
	    _("rtsp_session: rtsp server type '%s' not supported yet. sorry.\n"), server);
    session_abort:
    rtsp_close(rtsp_session->s);
    free(server);
    xine_buffer_free(rtsp_session->recv);
    free(rtsp_session);
    return NULL;
  }
  free(server);

  return rtsp_session;
}