📄 rtsp.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 <sys/types.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <event.h>#include <log.h>#include <frame.h>#include <stream.h>#include <pmsg.h>#include <rtp.h>#include <conf_parse.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( 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 ) if( ! strncmp( path, loc->path, strlen( loc->path ) ) && ( loc->path[len] == '/' || loc->path[len] == 0 ) ) 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, 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( 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( 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->teardown( 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, 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[8192], path[256], hdr[512]; int sdp_len; struct rtsp_location *loc; struct session *sess; spook_log( SL_DEBUG, "describing streams under '%s'", req->req->sl.req.uri ); if( ! ( loc = find_rtsp_location( req->req->sl.req.uri, path, NULL ) ) || ! ( sess = loc->open( path, loc->private ) ) ) { 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, req->req->sl.req.uri ) > 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" ); log_request( req, 200, sdp_len ); if( tcp_send_pmsg( req->conn, req->resp, sdp_len ) >= 0 ) send_data( req->conn, sdp, sdp_len ); } else rtsp_send_error( req, 404, "Not Found" ); sess->teardown( sess, NULL ); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -