695 lines
18 KiB
C
695 lines
18 KiB
C
/*
|
|
* Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "lwip\sockets.h"
|
|
#include "lwip\netif.h"
|
|
#include "lwip\dns.h"
|
|
|
|
#include "lwip\api.h"
|
|
|
|
#include "lwip\tcp.h"
|
|
|
|
#include <event.h>
|
|
#include <log.h>
|
|
#include <frame.h>
|
|
#include <stream.h>
|
|
#include <pmsg.h>
|
|
#include <rtp.h>
|
|
//#include "common.h"
|
|
#include "osal/string.h"
|
|
|
|
|
|
|
|
void write_access_log( char *path, struct sockaddr *addr, int code, char *req,
|
|
int length, char *referer, char *user_agent );
|
|
|
|
struct rtsp_session {
|
|
struct rtsp_session *next;
|
|
struct rtsp_session *prev;
|
|
char id[32];
|
|
struct session *sess;
|
|
};
|
|
|
|
struct rtsp_location {
|
|
struct loc_node node;
|
|
char realm[128];
|
|
char username[128];
|
|
char password[128];
|
|
open_func open;
|
|
void *private;
|
|
};
|
|
|
|
struct rtsp_conn {
|
|
struct {
|
|
struct rtp_endpoint *ep;
|
|
int rtcp;
|
|
} ichan[MAX_INTERLEAVE_CHANNELS];
|
|
};
|
|
|
|
static struct rtsp_location *rtsp_loc_list = NULL;
|
|
static struct rtsp_session *sess_list = NULL;
|
|
static char *get_local_path( char *path )
|
|
{
|
|
char *c;
|
|
static char *root = "/";
|
|
|
|
if( os_strncasecmp( path, "rtsp://", 7 ) ) return NULL;
|
|
for( c = path + 7; *c != '/'; ++c ) if( *c == 0 ) return root;
|
|
return c;
|
|
}
|
|
|
|
static struct loc_node *node_find_location( struct loc_node *list,
|
|
char *path, int len )
|
|
{
|
|
struct loc_node *loc;
|
|
|
|
for( loc = list; loc; loc = loc->next )
|
|
{
|
|
//_os_printf("%s path:%s\tloc:%s\tlen:%d\tres:%d\t%X\t%d\n",__FUNCTION__,path,loc->path,len,loc->path[len],'/',strncmp( path, loc->path, strlen( loc->path ) ));
|
|
//if( (! strncmp( path, loc->path, strlen( loc->path ) )) && ( loc->path[len] == '/' || loc->path[len] == 0 ) )
|
|
if( ! strncmp( path, loc->path, strlen( loc->path ) ))
|
|
{
|
|
return loc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct rtsp_location *find_rtsp_location( char *uri, char *base, int *track )
|
|
{
|
|
char *path, *c, *end;
|
|
int len;
|
|
|
|
if( ! ( path = get_local_path( uri ) ) ) return NULL;
|
|
len = strlen( path );
|
|
|
|
if( track )
|
|
{
|
|
*track = -1;
|
|
if( ( c = strrchr( path, '/' ) ) &&
|
|
! strncmp( c, "/track", 6 ) )
|
|
{
|
|
*track = strtol( c + 6, &end, 10 );
|
|
if( ! *end ) len -= strlen( c );
|
|
}
|
|
}
|
|
|
|
if( len > 1 && path[len - 1] == '/' ) --len;
|
|
|
|
if( base )
|
|
{
|
|
strncpy( base, path, len );
|
|
base[len] = 0;
|
|
}
|
|
|
|
return (struct rtsp_location *)node_find_location(
|
|
(struct loc_node *)rtsp_loc_list, path, len );
|
|
}
|
|
|
|
static void init_location( struct loc_node *node, const char *path,
|
|
struct loc_node **list )
|
|
{
|
|
node->next = *list;
|
|
node->prev = NULL;
|
|
if( node->next ) node->next->prev = node;
|
|
*list = node;
|
|
strcpy( node->path, path );
|
|
}
|
|
|
|
void new_rtsp_location( const char *path, char *realm, char *username, char *password,
|
|
open_func open, void *private )
|
|
{
|
|
struct rtsp_location *loc;
|
|
|
|
loc = (struct rtsp_location *)malloc( sizeof( struct rtsp_location ) );
|
|
init_location( (struct loc_node *)loc, path,
|
|
(struct loc_node **)&rtsp_loc_list );
|
|
if( realm ) strcpy( loc->realm, realm );
|
|
else loc->realm[0] = 0;
|
|
if( username ) strcpy( loc->username, username );
|
|
else loc->username[0] = 0;
|
|
if( password ) strcpy( loc->password, password );
|
|
else loc->password[0] = 0;
|
|
loc->open = open;
|
|
loc->private = private;
|
|
}
|
|
|
|
static void rtsp_session_close( struct session *sess )
|
|
{
|
|
struct rtsp_session *rs = (struct rtsp_session *)sess->control_private;
|
|
|
|
spook_log( SL_DEBUG, "freeing session %s", rs->id );
|
|
if( rs->next ) rs->next->prev = rs->prev;
|
|
if( rs->prev ) rs->prev->next = rs->next;
|
|
else sess_list = rs->next;
|
|
free( rs );
|
|
}
|
|
|
|
static struct rtsp_session *new_rtsp_session( struct session *sess )
|
|
{
|
|
struct rtsp_session *rs;
|
|
|
|
rs = (struct rtsp_session *)malloc( sizeof( struct rtsp_session ) );
|
|
rs->next = sess_list;
|
|
rs->prev = NULL;
|
|
if( rs->next ) rs->next->prev = rs;
|
|
sess_list = rs;
|
|
random_id( (unsigned char *)rs->id, 30 );
|
|
rs->sess = sess;
|
|
sess->control_private = rs;
|
|
sess->control_close = rtsp_session_close;
|
|
return rs;
|
|
}
|
|
|
|
static struct rtsp_session *get_session( char *id )
|
|
{
|
|
struct rtsp_session *rs;
|
|
|
|
if( ! id ) return NULL;
|
|
for( rs = sess_list; rs; rs = rs->next )
|
|
if( ! strcmp( rs->id, id ) ) break;
|
|
return rs;
|
|
}
|
|
|
|
void rtsp_conn_disconnect( struct conn *c )
|
|
{
|
|
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
|
|
int i;
|
|
|
|
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; ++i )
|
|
if( rc->ichan[i].ep && ! rc->ichan[i].rtcp )
|
|
rc->ichan[i].ep->session->closed(
|
|
rc->ichan[i].ep->session,
|
|
rc->ichan[i].ep );
|
|
free( rc );
|
|
}
|
|
|
|
void interleave_disconnect( struct conn *c, int chan )
|
|
{
|
|
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
|
|
|
|
rc->ichan[chan].ep = NULL;
|
|
}
|
|
|
|
int interleave_recv( struct conn *c, int chan, unsigned char *d, int len )
|
|
{
|
|
struct rtsp_conn *rc = (struct rtsp_conn *)c->proto_state;
|
|
|
|
if( chan >= MAX_INTERLEAVE_CHANNELS || ! rc->ichan[chan].ep ) return -1;
|
|
if( rc->ichan[chan].rtcp )
|
|
interleave_recv_rtcp( rc->ichan[chan].ep, d, len );
|
|
return 0;
|
|
}
|
|
|
|
int interleave_send( struct conn *c, int chan, struct iovec *v, int count )
|
|
{
|
|
unsigned char head[4];
|
|
int len = 0, i;
|
|
|
|
for( i = 0; i < count; ++i ) len += v[i].iov_len;
|
|
if( avail_send_buf( c ) < len + 4 ) return 1;
|
|
head[0] = '$';
|
|
head[1] = chan;
|
|
PUT_16( head + 2, len );
|
|
send_data( c, head, 4 );
|
|
for( i = 0; i < count; ++i )
|
|
send_data( c, v[i].iov_base, v[i].iov_len );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void log_request( struct req *req, int code, int length )
|
|
{
|
|
char *ref, *ua;
|
|
|
|
ref = get_header( req->req, "referer" );
|
|
ua = get_header( req->req, "user-agent" );
|
|
write_access_log( NULL, (struct sockaddr *)&req->conn->client_addr,
|
|
code, (char *)req->conn->req_buf, length,
|
|
ref ? ref : "-", ua ? ua : "-" );
|
|
}
|
|
|
|
static int rtsp_create_reply( struct req *req, int code, char *reason )
|
|
{
|
|
if( ! ( req->resp = new_pmsg( 512 ) ) ) return -1;
|
|
req->resp->type = PMSG_RESP;
|
|
req->resp->proto_id = add_pmsg_string( req->resp, "RTSP/1.0" );
|
|
req->resp->sl.stat.code = code;
|
|
req->resp->sl.stat.reason = add_pmsg_string( req->resp, reason );
|
|
copy_headers( req->resp, req->req, "CSeq" );
|
|
return 0;
|
|
}
|
|
|
|
static void rtsp_send_error( struct req *req, int code, char *reason )
|
|
{
|
|
log_request( req, code, 0 );
|
|
rtsp_create_reply( req, code, reason );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
}
|
|
/*
|
|
static int rtsp_verify_auth( struct req *req, char *realm,
|
|
char *username, char *password )
|
|
{
|
|
int ret = check_digest_response( req->req, realm, username, password );
|
|
|
|
if( ret > 0 ) return 0;
|
|
|
|
log_request( req, 401, 0 );
|
|
rtsp_create_reply( req, 401, "Unauthorized" );
|
|
add_digest_challenge( req->resp, realm, ret == 0 ? 1 : 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
return -1;
|
|
}
|
|
*/
|
|
static int handle_OPTIONS( struct req *req )
|
|
{
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
add_header( req->resp, "Public",
|
|
"DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE" );
|
|
log_request( req, 200, 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
return 0;
|
|
}
|
|
|
|
static int handle_DESCRIBE( struct req *req )
|
|
{
|
|
char sdp[512+128], path[64], hdr[128];
|
|
int sdp_len;
|
|
struct rtsp_location *loc;
|
|
struct session *sess;
|
|
|
|
spook_log( SL_DEBUG, "describing streams under '%s'", req->req->sl.req.uri );
|
|
//_os_printf("%s:%d url:%s\n",__FUNCTION__,__LINE__,req->req->sl.req.uri);
|
|
|
|
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
|
|
path, NULL ) ) ||
|
|
! ( sess = loc->open( path, loc->private ) ) )
|
|
{
|
|
_os_printf("no found uri:%s\tloc:%X\n",req->req->sl.req.uri,(int)loc);
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
if( loc->realm[0] && rtsp_verify_auth( req, loc->realm,
|
|
loc->username, loc->password ) < 0 )
|
|
return 0;*/
|
|
|
|
sdp_len = sizeof( sdp ) - 2;
|
|
if( sess->get_sdp( sess, sdp, &sdp_len, path ) > 0 )
|
|
{
|
|
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
sprintf( hdr, "%s/", req->req->sl.req.uri );
|
|
//add_header( req->resp, "Content-Base", hdr );
|
|
add_header( req->resp, "Content-Type", "application/sdp" );
|
|
add_header( req->resp, "Cache-Control", "no-cache" );
|
|
add_header( req->resp, "Server", "Hisilicon RTSP Streaming Media Server/1.0.0" );
|
|
|
|
log_request( req, 200, sdp_len );
|
|
|
|
|
|
if( tcp_send_pmsg( req->conn, req->resp, sdp_len ) >= 0 )
|
|
send_data( req->conn, (unsigned char *)sdp, sdp_len );
|
|
} else
|
|
{
|
|
_os_printf("sdp:%x %x\n",(int)sess->get_sdp,(int)sess->get_sdp( sess, sdp, &sdp_len, path));
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
}
|
|
|
|
sess->select_close(sess, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rtsp_udp_setup( struct session *s, int track,
|
|
struct req *req, char *t )
|
|
{
|
|
char *p, *end, trans[128];
|
|
int cport, server_port;
|
|
|
|
if( ! ( p = strstr( t, "client_port" ) ) || *(p + 11) != '=' )
|
|
return -1;
|
|
cport = strtol( p + 12, &end, 10 );
|
|
if( end == p + 12 ) return -1;
|
|
spook_log( SL_DEBUG, "client requested UDP port %d", cport );
|
|
|
|
if( connect_udp_endpoint( s->ep[track], req->conn->client_addr.sin_addr,
|
|
cport, &server_port ) < 0 )
|
|
return -1;
|
|
|
|
spook_log( SL_VERBOSE, "our port is %d, client port is %d",
|
|
server_port, cport );
|
|
|
|
sprintf( trans, "RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d",
|
|
cport, cport + 1, server_port, server_port + 1 );
|
|
add_header( req->resp, "Transport", trans );
|
|
return 0;
|
|
}
|
|
|
|
static int rtsp_interleave_setup( struct session *s, int track,
|
|
struct req *req, char *t )
|
|
{
|
|
struct rtsp_conn *rc = (struct rtsp_conn *)req->conn->proto_state;
|
|
char *p, *end, trans[128];
|
|
int rtp_chan = -1, rtcp_chan = -1, i;
|
|
|
|
if( ( p = strstr( t, "interleaved" ) ) )
|
|
{
|
|
if( *(p + 11) != '=' ) return -1;
|
|
rtp_chan = strtol( p + 12, &end, 10 );
|
|
rtcp_chan = rtp_chan + 1; // XXX make better parser
|
|
if( end == p + 12 ) return -1;
|
|
if( rtp_chan < 0 || rtcp_chan < 0 ||
|
|
rtp_chan >= MAX_INTERLEAVE_CHANNELS ||
|
|
rtcp_chan >= MAX_INTERLEAVE_CHANNELS )
|
|
return -1;
|
|
spook_log( SL_VERBOSE, "requested interleave channels %d-%d",
|
|
rtp_chan, rtcp_chan );
|
|
if( rc && ( rc->ichan[rtp_chan].ep ||
|
|
rc->ichan[rtcp_chan].ep ) )
|
|
return -1;
|
|
} else
|
|
{
|
|
spook_log( SL_VERBOSE, "requested any interleave channel" );
|
|
if( rc )
|
|
{
|
|
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; i += 2 )
|
|
if( ! rc->ichan[i].ep && ! rc->ichan[i + 1].ep )
|
|
break;
|
|
if( i >= MAX_INTERLEAVE_CHANNELS ) return -1;
|
|
rtp_chan = i;
|
|
rtcp_chan = i + 1;
|
|
} else
|
|
{
|
|
rtp_chan = 0;
|
|
rtcp_chan = 1;
|
|
}
|
|
}
|
|
|
|
if( ! rc )
|
|
{
|
|
rc = (struct rtsp_conn *)malloc( sizeof( struct rtsp_conn ) );
|
|
if( ! rc )
|
|
{
|
|
spook_log( SL_ERR,
|
|
"out of memory on malloc rtsp_conn" );
|
|
return -1;
|
|
}
|
|
for( i = 0; i < MAX_INTERLEAVE_CHANNELS; ++i )
|
|
rc->ichan[i].ep = NULL;
|
|
req->conn->proto_state = rc;
|
|
}
|
|
|
|
rc->ichan[rtp_chan].ep = s->ep[track];
|
|
rc->ichan[rtp_chan].rtcp = 0;
|
|
rc->ichan[rtcp_chan].ep = s->ep[track];
|
|
rc->ichan[rtcp_chan].rtcp = 1;
|
|
|
|
connect_interleaved_endpoint( s->ep[track], req->conn,
|
|
rtp_chan, rtcp_chan );
|
|
|
|
sprintf( trans, "RTP/AVP/TCP;unicast;interleaved=%d-%d",
|
|
rtp_chan, rtcp_chan );
|
|
add_header( req->resp, "Transport", trans );
|
|
return 0;
|
|
}
|
|
|
|
static int handle_SETUP( struct req *req )
|
|
{
|
|
char *t, *sh, path[256];
|
|
int track, ret;
|
|
struct session *s;
|
|
struct rtsp_session *rs = NULL;
|
|
struct rtsp_location *loc;
|
|
|
|
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
|
|
path, &track ) ) ||
|
|
track < 0 || track >= MAX_TRACKS )
|
|
{
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
return 0;
|
|
}
|
|
/*
|
|
if( loc->realm[0] && rtsp_verify_auth( req, loc->realm,
|
|
loc->username, loc->password ) < 0 )
|
|
return 0;*/
|
|
|
|
if( ! ( t = get_header( req->req, "Transport" ) ) )
|
|
{
|
|
_os_printf("%s %d\r\n",__func__,__LINE__);
|
|
// XXX better error reply
|
|
rtsp_send_error( req, 461, "Unspecified Transport" );
|
|
return 0;
|
|
}
|
|
|
|
if( ! ( sh = get_header( req->req, "Session" ) ) )
|
|
{
|
|
/*callback: live_open */
|
|
if( ! ( s = loc->open( path, loc->private ) ) )
|
|
{
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
return 0;
|
|
}
|
|
sprintf( s->addr, "IP4 %s",
|
|
inet_ntoa( req->conn->client_addr.sin_addr ) );
|
|
} else if( ! ( rs = get_session( sh ) ) )
|
|
{
|
|
rtsp_send_error( req, 454, "Session Not Found" );
|
|
return 0;
|
|
} else s = rs->sess;
|
|
|
|
if( s->ep[track] )
|
|
{
|
|
_os_printf("%s %d\r\n",__func__,__LINE__);
|
|
// XXX better error reply
|
|
rtsp_send_error( req, 461, "Unsupported Transport" );
|
|
return 0;
|
|
}
|
|
|
|
/* callback: live_setup */
|
|
if( s->setup( s, track ) < 0 )
|
|
{
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
if( ! rs ) s->select_close(s, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
spook_log( SL_DEBUG, "setting up RTP (%s)", t );
|
|
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
|
|
if( ! strncasecmp( t, "RTP/AVP/TCP", 11 ) )
|
|
{
|
|
// ret = -1;
|
|
ret = rtsp_interleave_setup( s, track, req, t );
|
|
}
|
|
else if( ( ! strncasecmp( t, "RTP/AVP", 7 ) && t[7] != '/' ) ||
|
|
! strncasecmp( t, "RTP/AVP/UDP", 11 ) )
|
|
ret = rtsp_udp_setup( s, track, req, t );
|
|
else ret = -1;
|
|
|
|
if( ret < 0 )
|
|
{
|
|
free_pmsg( req->resp );
|
|
_os_printf("%s %d\r\n",__func__,__LINE__);
|
|
rtsp_send_error( req, 461, "Unsupported Transport" );
|
|
s->select_close(s, s->ep[track]);
|
|
} else
|
|
{
|
|
if( ! rs ) rs = new_rtsp_session( s );
|
|
add_header( req->resp, "Session", rs->id );
|
|
log_request( req, 200, 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
|
|
/* add by jornny */
|
|
rs->sess->conn = req->conn;
|
|
req->conn->sess = s;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_PLAY( struct req *req )
|
|
{
|
|
struct rtsp_session *rs;
|
|
double start;
|
|
int have_start = 0, i, p, ret;
|
|
char *range, hdr[512];
|
|
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
|
|
{
|
|
rtsp_send_error( req, 454, "Session Not Found" );
|
|
return 0;
|
|
}
|
|
|
|
range = get_header( req->req, "Range" );
|
|
if( range && sscanf( range, "npt=%lf-", &start ) == 1 )
|
|
{
|
|
have_start = 1;
|
|
spook_log( SL_VERBOSE,
|
|
"starting streaming for session %s at position %.4f",
|
|
rs->id, start );
|
|
} else spook_log( SL_VERBOSE,
|
|
"starting streaming for session %s", rs->id );
|
|
|
|
/* callback:live_play( struct session *s, double *start ) */
|
|
rs->sess->play( rs->sess, have_start ? &start : NULL );
|
|
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
add_header( req->resp, "Session", rs->id );
|
|
if( have_start && start >= 0 )
|
|
{
|
|
spook_log( SL_DEBUG, "backend seeked to %.4f", start );
|
|
sprintf( hdr, "npt=%.4f-", start );
|
|
add_header( req->resp, "Range", hdr );
|
|
p = 0;
|
|
for( i = 0; i < MAX_TRACKS; ++i )
|
|
{
|
|
if( ! rs->sess->ep[i] ) continue;
|
|
ret = snprintf( hdr + p, sizeof( hdr ) - p,
|
|
"url=%s/track%d;seq=%d;rtptime=%u,",
|
|
req->req->sl.req.uri, i,
|
|
rs->sess->ep[i]->seqnum,
|
|
rs->sess->ep[i]->last_timestamp );
|
|
if( ret >= sizeof( hdr ) - p )
|
|
{
|
|
p = -1;
|
|
break;
|
|
}
|
|
p += ret;
|
|
}
|
|
if( p > 0 )
|
|
{
|
|
hdr[p - 1] = 0; /* Kill last comma */
|
|
add_header( req->resp, "RTP-Info", hdr );
|
|
}
|
|
}
|
|
log_request( req, 200, 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
#ifdef FLY_CONTROL_RECEIVE
|
|
#endif
|
|
/* to test audio adc when transporting picture */
|
|
// extern void auadc_init(void);
|
|
// auadc_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_PAUSE( struct req *req )
|
|
{
|
|
struct rtsp_session *rs;
|
|
|
|
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
|
|
{
|
|
rtsp_send_error( req, 454, "Session Not Found" );
|
|
return 0;
|
|
}
|
|
|
|
if( ! rs->sess->pause )
|
|
{
|
|
rtsp_send_error( req, 501, "Not Implemented" );
|
|
return 0;
|
|
}
|
|
|
|
spook_log( SL_VERBOSE, "pausing session %s", rs->id );
|
|
|
|
rs->sess->pause( rs->sess );
|
|
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
add_header( req->resp, "Session", rs->id );
|
|
log_request( req, 200, 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
return 0;
|
|
}
|
|
|
|
static int handle_TEARDOWN( struct req *req )
|
|
{
|
|
struct rtsp_location *loc;
|
|
struct rtsp_session *rs;
|
|
int track;
|
|
_os_printf("handle_teardown\r\n");
|
|
if( ! ( loc = find_rtsp_location( req->req->sl.req.uri,
|
|
NULL, &track ) ) ||
|
|
track >= MAX_TRACKS )
|
|
{
|
|
rtsp_send_error( req, 404, "Not Found" );
|
|
return 0;
|
|
}
|
|
|
|
if( ! ( rs = get_session( get_header( req->req, "Session" ) ) ) )
|
|
{
|
|
rtsp_send_error( req, 454, "Session Not Found" );
|
|
return 0;
|
|
}
|
|
spook_log( SL_VERBOSE, "tearing down %s in session %s",
|
|
req->req->sl.req.uri, rs->id );
|
|
|
|
rtsp_create_reply( req, 200, "OK" );
|
|
add_header( req->resp, "Session", rs->id );
|
|
|
|
/* This might destroy the session, so do it after creating the reply
|
|
* callback function: live_teardown */
|
|
rs->sess->closed( rs->sess, track < 0 ? NULL : rs->sess->ep[track] );
|
|
|
|
/* add by jornny */
|
|
//req->conn->sess = NULL;
|
|
|
|
log_request( req, 200, 0 );
|
|
tcp_send_pmsg( req->conn, req->resp, -1 );
|
|
return 0;
|
|
}
|
|
|
|
static int handle_unknown( struct req *req )
|
|
{
|
|
rtsp_send_error( req, 501, "Not Implemented" );
|
|
return 0;
|
|
}
|
|
|
|
uint8 spook_handle_open = 1;
|
|
|
|
int rtsp_handle_msg( struct req *req )
|
|
{
|
|
int ret;
|
|
_os_printf("===========%s=============\r\n",req->req->sl.req.method);
|
|
|
|
if(spook_handle_open == 0){
|
|
ret = handle_unknown( req );
|
|
return ret;
|
|
}
|
|
|
|
if( ! os_strcasecmp( req->req->sl.req.method, "OPTIONS" ) )
|
|
ret = handle_OPTIONS( req );
|
|
else if( ! os_strcasecmp( req->req->sl.req.method, "DESCRIBE" ) )
|
|
ret = handle_DESCRIBE( req );
|
|
else if( ! os_strcasecmp( req->req->sl.req.method, "SETUP" ) )
|
|
ret = handle_SETUP( req );
|
|
else if( ! os_strcasecmp( req->req->sl.req.method, "PLAY" ) )
|
|
ret = handle_PLAY( req );
|
|
else if( ! os_strcasecmp( req->req->sl.req.method, "PAUSE" ) )
|
|
ret = handle_PAUSE( req );
|
|
else if( ! os_strcasecmp( req->req->sl.req.method, "TEARDOWN" ) )
|
|
ret = handle_TEARDOWN( req );
|
|
else ret = handle_unknown( req );
|
|
return ret;
|
|
}
|
|
|