示例#1
0
GF_EXPORT
GF_Err gf_rtsp_get_command(GF_RTSPSession *sess, GF_RTSPCommand *com)
{
	GF_Err e;
	u32 BodyStart, size;
	if (!sess || !com) return GF_BAD_PARAM;

	//reset the command
	gf_rtsp_command_reset(com);
	//if no connection, we have sent a "Connection: Close"
	if (!sess->connection) return GF_IP_CONNECTION_CLOSED;

	//lock
	gf_mx_p(sess->mx);

	//fill TCP buffer
	e = gf_rtsp_fill_buffer(sess);
	if (e) goto exit;
	//this is upcoming, interleaved data
	if (strncmp(sess->TCPBuffer+sess->CurrentPos, "RTSP", 4)) {
		e = GF_IP_NETWORK_EMPTY;
		goto exit;
	}
	e = gf_rtsp_read_reply(sess);
	if (e) goto exit;

	gf_rtsp_get_body_info(sess, &BodyStart, &size);
	e = RTSP_ParseCommandHeader(sess, com, BodyStart);
	//before returning an error we MUST reset the TCP buffer

	//copy the body if any
	if (!e && com->Content_Length) {
		com->body = (char *) gf_malloc(sizeof(char) * (com->Content_Length));
		memcpy(com->body, sess->TCPBuffer+sess->CurrentPos + BodyStart, com->Content_Length);
	}	
	//reset TCP buffer
	sess->CurrentPos += BodyStart + com->Content_Length;

	if (!com->CSeq) com->StatusCode = NC_RTSP_Bad_Request;

	if (e || (com->StatusCode != NC_RTSP_OK)) goto exit;

	//NB: there is no "session state" in our lib when acting at the server side, as it depends
	//on the server implementation. We cannot block responses / announcement to be sent
	//dynamically, nor reset the session ourselves as we don't know the details of the session
	//(eg TEARDOWN may keep resources up or not, ...)

	//we also have the same pb for CSeq, as nothing forbids a server to buffer commands (and it 
	//happens during aggregation of PLAY/PAUSE with overlapping ranges)

	//however store the last CSeq in case for client checking
	if (!sess->CSeq) {
		sess->CSeq = com->CSeq;
	}
	//check we're in the right range
	else {
		if (sess->CSeq >= com->CSeq) 
			com->StatusCode = NC_RTSP_Header_Field_Not_Valid;
		else
			sess->CSeq = com->CSeq;
	}

	//
	//if a connection closed is signal, check this is the good session
	// and reset it (the client is no longer connected)
	if (sess->last_session_id && com->Session && !strcmp(com->Session, sess->last_session_id) 
		&& com->Connection && !stricmp(com->Connection, "Close")) {

		gf_rtsp_session_reset(sess, 0);
		//destroy the socket
		if (sess->connection) gf_sk_del(sess->connection);
		sess->connection = NULL;
		
		//destroy the http tunnel if any
		if (sess->HasTunnel && sess->http) {
			gf_sk_del(sess->http);
			sess->http = NULL;
		}
	}	

exit:
	gf_mx_v(sess->mx);
	return e;
}
示例#2
0
M4Err RTSP_GetRequest(RTSPSession *sess, RTSPCommand *com)
{
	M4Err e;
	u32 BodyStart, size;
	if (!sess || !com) return M4BadParam;

	//reset the command
	RTSP_ResetCommand(com);
	//if no connection, we have sent a "Connection: Close"
	if (!sess->connection) return M4ConnectionClosed;

	//lock
	MX_P(sess->mx);

	//fill TCP buffer
	e = RTSP_FillTCPBuffer(sess);
	if (e) goto exit;
	//this is upcoming, interleaved data
	if (strncmp(sess->TCPBuffer+sess->CurrentPos, "RTSP", 4)) {
		e = M4NetworkEmpty;
		goto exit;
	}
	e = RTSP_ReadReply(sess);
	if (e) goto exit;

	RTSP_GetBodyInfo(sess, &BodyStart, &size);
	e = RTSP_ParseCommandHeader(sess, com, BodyStart);
	//before returning an error we MUST reset the TCP buffer

	//copy the body if any
	if (!e && com->Content_Length) {
		com->body = malloc(sizeof(char) * (com->Content_Length));
		memcpy(com->body, sess->TCPBuffer+sess->CurrentPos + BodyStart, com->Content_Length);
	}	
	//reset TCP buffer
	sess->CurrentPos += BodyStart + com->Content_Length;

	if (!com->CSeq) com->StatusCode = NC_RTSP_Bad_Request;

	if (e || (com->StatusCode != NC_RTSP_OK)) goto exit;

	//NB: there is no "session state" in our lib when acting at the server side, as it depends
	//on the server implementation. We cannot block responses / announcement to be sent
	//dynamically, nor reset the session ourselves as we don't know the details of the session
	//(eg TEARDOWN may keep resources up or not, ...)

	//we also have the same pb for CSeq, as nothing forbids a server to buffer commands (and it 
	//happens during aggregation of PLAY/PAUSE with overlapping ranges)

	//however store the last CSeq in case for client checking
	if (!sess->CSeq) {
		sess->CSeq = com->CSeq;
	}
	//check we're in the right range
	else {
		if (sess->CSeq >= com->CSeq) 
			com->StatusCode = NC_RTSP_Header_Field_Not_Valid;
		else
			sess->CSeq = com->CSeq;
	}

	//
	//if a connection closed is signal, check this is the good session
	// and reset it (the client is no longer connected)
	if (sess->SessionID && com->Session && !strcmp(com->Session, sess->SessionID) 
		&& com->Connection && !stricmp(com->Connection, "Close")) {

		RTSP_ResetSession(sess, 0);
		//destroy the socket
		if (sess->connection) SK_Delete(sess->connection);
		sess->connection = NULL;
		
		//destroy the http tunnel if any
		if (sess->HasTunnel && sess->http) {
			SK_Delete(sess->http);
			sess->http = NULL;
		}
	}	

exit:
	MX_V(sess->mx);
	return e;
}