apps/streamer/rtsp.c

Go to the documentation of this file.
00001 /*
00002  * (C)2004 Alexander Melichenko <alexlp@freemail.ru>
00003  *
00004  * This file consist a portion of code from Spook Live Video Streamer
00005  * The Spook webpage at <http://www.litech.org/spook/> where updated releases
00006  * and documentation may be found.
00007  *
00008  * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
00009  *
00010  *  This program is free software: you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation, either version 3 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00022  */
00023 
00024 #include <sys/types.h>
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <fcntl.h>
00030 #include <errno.h>
00031 #include <sys/time.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 
00036 #include "event.h"
00037 #include "str.h"
00038 #include "rtp.h"
00039 #include "rtsp.h"
00040 
00041 #undef  DEBUG
00042 
00043 struct param *_param;
00044 
00045 struct session {
00046         struct session *next;
00047         struct session *prev;
00048         char id[32];
00049 };
00050 
00051 /*
00052  * Connection states:
00053  *   CONN_STATE_START: just accepted the connection, protocol is yet unknown
00054  *   CONN_STATE_RTSP: might get an RTSP request or an interleaved RTP packet
00055  *   CONN_STATE_RTSP_REQ: definitely getting an RTSP request
00056  *   CONN_STATE_INTERLEAVED: definitely getting an interleaved RTP packet
00057  *   CONN_STATE_HTTP: definitely getting an HTTP request
00058  */
00059 
00060 #define CONN_STATE_START        0
00061 #define CONN_STATE_RTSP         1
00062 #define CONN_STATE_RTSP_REQ     2
00063 #define CONN_STATE_INTERLEAVED  3
00064 #define CONN_STATE_HTTP         10
00065 
00066 struct conn {
00067         struct conn *next;
00068         struct conn *prev;
00069         int fd;
00070         struct sockaddr_in client_addr;
00071         struct event *read_event;
00072         struct event *write_event;
00073         int state;
00074         char req_buf[4096];
00075         int req_len;
00076         struct { char *name; char *value; } req_hdr[16];
00077         unsigned char send_buf[65536];
00078         int send_buf_r;
00079         int send_buf_w;
00080         int drop_after;
00081         int close_flag;
00082         struct session *attached_session;
00083 };
00084 
00085 struct listener {
00086         int fd;
00087 };
00088 
00089 struct conn *conn_list = NULL;
00090 struct session *sess_list = NULL;
00091 
00092 static void do_read( struct event *e, void *d );
00093 
00094 static void del_session( struct session *sess )
00095 {
00096         if( sess->next ) sess->next->prev = sess->prev;
00097         if( sess->prev ) sess->prev->next = sess->next;
00098         else sess_list = sess->next;
00099         free( sess );
00100 }
00101 
00102 static struct session *new_session( void )
00103 {
00104         struct session *sess;
00105         int len;
00106 
00107         sess = (struct session *)malloc( sizeof( struct session ) );
00108         sess->next = sess_list;
00109         sess->prev = NULL;
00110         if( sess->next ) sess->next->prev = sess;
00111         sess_list = sess;
00112 
00113         for( len = 0; len < 15; ++len )
00114                 sprintf( sess->id + len * 2, "%02X",
00115                                 (unsigned int)( random() & 0xff ) );
00116         sess->id[30] = 0;
00117         return sess;
00118 }
00119 
00120 static struct session *get_session( char *id )
00121 {
00122         struct session *s;
00123 
00124         for( s = sess_list; s; s = s->next )
00125                 if( ! strcmp( s->id, id ) ) break;
00126         return s;
00127 }
00128 
00129 static void close_session( struct session *s )
00130 {
00131         del_session( s );
00132 }
00133 
00134 static void drop_conn(struct conn *c) {
00135         if(c->attached_session)
00136                 close_session(c->attached_session);
00137         remove_event(c->read_event);
00138         remove_event(c->write_event);
00139         if(c->fd >= 0)
00140                 close(c->fd);
00141         c->fd = -1;
00142         if(c->next)
00143                 c->next->prev = c->prev;
00144         if(c->prev)
00145                 c->prev->next = c->next;
00146         else
00147                 conn_list = c->next;
00148         free(c);
00149 }
00150 
00151 static void conn_write( struct event *e, void *d )
00152 {
00153         struct conn *c = (struct conn *)d;
00154         int ret, len;
00155 
00156         while( c->send_buf_r != c->send_buf_w )
00157         {
00158                 if( c->send_buf_w < c->send_buf_r )
00159                         len = sizeof( c->send_buf ) - c->send_buf_r;
00160                 else
00161                         len = c->send_buf_w - c->send_buf_r;
00162                 ret = write( c->fd, c->send_buf + c->send_buf_r, len );
00163                 if( ret <= 0 )
00164                 {
00165                         if( ret < 0 && errno == EAGAIN ) return;
00166                         drop_conn( c );
00167                         return;
00168                 }
00169                 c->send_buf_r += ret;
00170                 if( c->send_buf_r == sizeof( c->send_buf ) )
00171                         c->send_buf_r = 0;
00172         }
00173         if( c->drop_after ) drop_conn( c );
00174         else set_event_enabled( c->write_event, 0 );
00175 }
00176 
00177 static inline int avail_send_buf( struct conn *c )
00178 {
00179         if( c->send_buf_r > c->send_buf_w )
00180                 return c->send_buf_r - c->send_buf_w - 1;
00181         else return sizeof( c->send_buf ) - c->send_buf_w + c->send_buf_r - 1;
00182 }
00183 
00184 static int send_data( struct conn *c, unsigned char *d, int len )
00185 {
00186         if( avail_send_buf( c ) < len ) return 1;
00187 
00188         while( --len >= 0 )
00189         {
00190                 c->send_buf[c->send_buf_w++] = *(d++);
00191                 if( c->send_buf_w == sizeof( c->send_buf ) )
00192                         c->send_buf_w = 0;
00193         }
00194 
00195         set_event_enabled( c->write_event, 1 );
00196 
00197         return 0;
00198 }
00199 
00200 
00201 static char *get_header( struct conn *c, char *name )
00202 {
00203         int i;
00204         static char *empty = "";
00205 
00206         for( i = 0; c->req_hdr[i].name; ++i )
00207                 if( ! strcasecmp( c->req_hdr[i].name, name ) )
00208                         return c->req_hdr[i].value;
00209         return empty;
00210 }
00211 
00212 static int handle_OPTIONS( struct conn *c )
00213 {
00214         unsigned char rep[8192];
00215 
00216         send_data( c, rep, sprintf( rep, "RTSP/1.0 200 OK\r\nCSeq: %s\r\nPublic: DESCRIBE, SETUP, TEARDOWN, PLAY\r\n\r\n", get_header( c, "CSeq" ) ) );
00217         return 0;
00218 }
00219 
00220 static int handle_DESCRIBE( struct conn *c )
00221 {
00222         char rep[8192], sdp[8192];
00223         int rep_len;
00224         
00225         if((_param->rtsp_use_cmd_addr && !ismulticast(_param) && str_count) ||
00226              (!_param->rtsp_use_cmd_addr && str_count)){
00227             c->close_flag = 1; 
00228             send_data( c, rep, sprintf( rep, "RTSP/1.0 455 Server is busy\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00229             return 0;
00230         }
00231 
00232         write_sdp(_param, 0, sdp);
00233         rep_len = sprintf( rep,
00234             "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
00235             "Content-Type: application/sdp\r\nContent-Length: %d\r\n\r\n", 
00236                     get_header( c, "CSeq" ), strlen(sdp));
00237 #ifdef DEBUG
00238         fprintf(stderr, "DESCRIBE reply:\n%s", rep);
00239         fprintf(stderr,  "%s", sdp);
00240 #endif
00241         send_data( c, rep, rep_len );
00242         send_data( c, sdp, strlen(sdp) );
00243         return 0;
00244 }
00245 
00246 static int rtsp_udp_setup( struct conn *c, char *t )
00247 {
00248         char *p, *end;
00249         int cport;
00250         struct session *s;
00251         unsigned char rep[8192];
00252         char mode_u[] = "unicast", mode_m[] = "multicast", *mode;
00253         
00254         memset(rep, 0, 8192);
00255 
00256         if( ! ( p = strstr( t, "client_port" ) ) || *(p + 11) != '=' )
00257                 return -1;
00258         cport = strtol( p + 12, &end, 10 );
00259         if( end == p + 12 ) return -1;
00260 
00261 fprintf(stderr, "t == |%s|\r\n", t);
00262 
00263 #ifdef DEBUG
00264         fprintf(stderr, "client port is %d\n", cport);
00265 #endif
00266         s = new_session();
00267 
00268         if((mode = strstr( t, "multicast" ))){
00269             mode = mode_m;
00270         } else {
00271             mode = mode_u;
00272         }
00273         
00274         if(!_param->rtsp_use_cmd_port){
00275             if(str_count<1){
00276                 _param->dport  = cport;
00277             }
00278         }
00279         
00280         if(!_param->rtsp_use_cmd_addr){
00281             if(str_count<1){
00282                 _param->dst = strdup(inet_ntoa(c->client_addr.sin_addr));
00283             }
00284         }
00285 
00286         if(!str_count++) str_setup = 1;
00287         usleep(10);
00288 
00289         c->attached_session = s;
00290         sprintf( rep,   "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
00291                         "Session: %s\r\nTransport: RTP/AVP;"
00292                         "%s;destination=%s;port=%d\r\n\r\n", 
00293                             get_header( c, "CSeq" ), s->id, mode, _param->dst,  cport);
00294 #ifdef DEBUG    
00295         fprintf(stderr, "SETUP reply:\n%s", rep);
00296 #endif
00297         send_data( c, rep, strlen(rep) );
00298         
00299         return 0;
00300 }
00301 
00302 static int handle_SETUP( struct conn *c )
00303 {
00304         char *t;
00305         unsigned char rep[8192];
00306 
00307         memset(rep, 0, 8192);
00308 
00309         t = get_header( c, "Transport" );
00310 
00311         if( ( ! strncasecmp( t, "RTP/AVP", 7 ) && t[7] != '/' ) ||
00312                         ! strncasecmp( t, "RTP/AVP/UDP", 11 ) )
00313         {
00314                 if( rtsp_udp_setup( c, t ) == 0 ) return 0;
00315         }
00316 
00317         send_data( c, rep, sprintf( rep, "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00318 
00319         return 0;
00320 }
00321 
00322 static int handle_PLAY( struct conn *c )
00323 {
00324         struct session *s;
00325         unsigned char rep[8192];
00326 
00327         memset(rep, 0, 8192);
00328 
00329         if( ! ( s = get_session( get_header( c, "Session" ) ) ) )
00330         {
00331                 send_data( c, rep, sprintf( rep, "RTSP/1.0 454 Session Not Found\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00332                 return 0;
00333         }
00334         
00335         
00336         sprintf( rep,   "RTSP/1.0 200 OK\r\nCSeq: %s\r\nSession: %s"
00337                         "\r\n\r\n", 
00338                             get_header( c, "CSeq" ), s->id );
00339 #ifdef DEBUG
00340         fprintf(stderr,  "PLAY reply:\n%s", rep);
00341 #endif
00342         send_data( c, rep, strlen(rep) );
00343         str_play = 1;
00344 
00345         return 0;
00346 }
00347 
00348 static int handle_PAUSE( struct conn *c )
00349 {
00350         struct session *s;
00351         unsigned char rep[8192];
00352 
00353         memset(rep, 0, 8192);
00354 
00355         if( ! ( s = get_session( get_header( c, "Session" ) ) ) )
00356         {
00357                 send_data( c, rep, sprintf( rep, "RTSP/1.0 454 Session Not Found\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00358                 return 0;
00359         }
00360         
00361         
00362         sprintf( rep,   "RTSP/1.0 200 OK\r\nCSeq: %s\r\nSession: %s"
00363                         "\r\n\r\n", 
00364                             get_header( c, "CSeq" ), s->id );
00365 #ifdef DEBUG
00366         fprintf(stderr,  "PAUSE reply:\n%s", rep);
00367 #endif
00368         send_data( c, rep, strlen(rep) );
00369         if(str_count<2){
00370             if(!_param->rtsp_qt_compat){
00371                 str_play = 0;
00372             }
00373         }
00374 
00375         return 0;
00376 }
00377 
00378 
00379 static int handle_TEARDOWN( struct conn *c )
00380 {
00381         struct session *s;
00382         unsigned char rep[8192];
00383 
00384         if( ! ( s = get_session( get_header( c, "Session" ) ) ) )
00385         {
00386                 send_data( c, rep, sprintf( rep, "RTSP/1.0 454 Session Not Found\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00387                 return 0;
00388         }
00389         send_data( c, rep, sprintf( rep, "RTSP/1.0 200 OK\r\nCSeq: %s\r\nSession: %s\r\n\r\n", get_header( c, "CSeq" ), s->id ) );
00390         if( c->attached_session == s ) c->attached_session = NULL;
00391         close_session( s );
00392 
00393         if(--str_count<=0){
00394             str_count = 0;
00395             if(!_param->rtsp_qt_compat){
00396                 str_teardown = 1;
00397             }
00398         }
00399         c->close_flag = 1;
00400         return 0;
00401 }
00402 
00403 static int handle_unknown( struct conn *c )
00404 {
00405         unsigned char rep[8192];
00406 
00407         send_data( c, rep, sprintf( rep, "RTSP/1.0 501 Not Implemented\r\nCSeq: %s\r\n\r\n", get_header( c, "CSeq" ) ) );
00408         return 0;
00409 }
00410 
00411 static int handle_request( struct conn *c )
00412 {
00413         char *t;
00414         int i = 0;
00415 
00416         if( c->req_buf[0] == 0 ) return -1;
00417 
00418 #ifdef DEBUG
00419         fprintf(stderr, "Request:\n%s\n", c->req_buf);
00420 #endif
00421 
00422         /* Terminate the first line of the request */
00423         for( t = c->req_buf; *t != '\r' && *t != '\n'; ++t )
00424                 if( *t == 0 ) return -1;
00425         *(t++) = 0;
00426         if( *t == '\n' ) *(t++) = 0;
00427         /* Find the name and content of each header line */
00428         for( i = 0; i < 15; ++i )
00429         {
00430                 /* We should be sitting on the header name */
00431                 c->req_hdr[i].name = t;
00432                 /* Terminate where the colon is */
00433                 for( ; *t != ':'; ++t )
00434                         if( *t == 0 || *t == '\r' || *t == '\n' ) return -1;
00435                 *(t++) = 0;
00436                 /* Skip any spaces after the colon */
00437                 for( ; *t == ' '; ++t )
00438                         if( *t == 0 ) return -1;
00439                 /* Should be the start of the header content */
00440                 c->req_hdr[i].value = t;
00441                 for( ; *t != '\r' && *t != '\n'; ++t )
00442                         if( *t == 0 ) return -1;
00443                 /* Terminate the content string */
00444                 *(t++) = 0;
00445                 if( *t == '\n' ) *(t++) = 0;
00446                 /* Are we at the end of the header? */
00447                 if( *t == 0 || *t == '\r' || *t == '\n' ) break;
00448         }
00449         if( i == 15 ) return -1; /* Too many headers */
00450         c->req_hdr[i + 1].name = NULL;
00451 
00452 #if 0
00453         for( i = 0; i < 16 && c->req_hdr[i].name; ++i )
00454         {
00455                 printf( "Header name = %s\n", c->req_hdr[i].name );
00456                 printf( "Header value = %s\n", c->req_hdr[i].value );
00457         }
00458 #endif
00459 
00460         if( ! strncasecmp( c->req_buf, "OPTIONS ", 8 ) )
00461                 return handle_OPTIONS( c );
00462         else if( ! strncasecmp( c->req_buf, "DESCRIBE ", 9 ) )
00463                 return handle_DESCRIBE( c );
00464         else if( ! strncasecmp( c->req_buf, "SETUP ", 6 ) )
00465                 return handle_SETUP( c );
00466         else if( ! strncasecmp( c->req_buf, "PLAY ", 5 ) )
00467                 return handle_PLAY( c );
00468         else if( ! strncasecmp( c->req_buf, "PAUSE ", 6 ) )
00469                 return handle_PAUSE( c );
00470         else if( ! strncasecmp( c->req_buf, "TEARDOWN ", 9 ) )
00471                 return handle_TEARDOWN( c );
00472         else return handle_unknown( c );
00473 }
00474 
00475 static int parse_client_data( struct conn *c )
00476 {
00477         char *t;
00478 
00479         switch( c->state )
00480         {
00481         case CONN_STATE_START:
00482                 if( strchr( c->req_buf, '\n' ) )
00483                 {
00484                     c->state = CONN_STATE_RTSP;
00485                     return 1;
00486                 }
00487                 break;
00488         case CONN_STATE_RTSP:
00489                 if( c->req_len < 4 ) return 0;
00490                 c->state = CONN_STATE_RTSP_REQ;
00491                 return 1;
00492         case CONN_STATE_RTSP_REQ:
00493                 if( ! ( t = strstr( c->req_buf, "\r\n\r\n" ) ) ) return 0;
00494                 t[2] = 0;
00495                 if( handle_request( c ) < 0 ) return -1;
00496                 /* should really just delete the request from the
00497                  * buffer, not the entire buffer */
00498                 c->req_len = 0;
00499                 if( c->state == CONN_STATE_RTSP_REQ )
00500                         c->state = CONN_STATE_RTSP;
00501                 break;
00502         }
00503         return 0;
00504 }
00505 
00506 static void do_read( struct event *e, void *d )
00507 {
00508         struct conn *c = (struct conn *)d;
00509         int ret;
00510 
00511         for(;;)
00512         {
00513                 ret = read( c->fd,
00514                                 c->req_buf + c->req_len,
00515                                 sizeof( c->req_buf ) - c->req_len - 1 );
00516                 if( ret <= 0 )
00517                 {
00518                         if( ret < 0 )
00519                         {
00520                                 if( errno == EAGAIN ) return;
00521                                 fprintf( stderr, "read error%s: %s\n",
00522                                         "",
00523                                         strerror( errno ) );
00524                         } else{
00525 #ifdef DEBUG
00526                             fprintf( stderr, "connection closed\n" );
00527 #endif
00528                         }
00529 
00530                         if(!c->close_flag){
00531                             str_count--;
00532                         }
00533                         if(str_count<=0){
00534                             str_count = 0;
00535                             if(!_param->rtsp_qt_compat){
00536                                 str_teardown = 1;
00537                             }
00538                         }
00539                         drop_conn( c );
00540                         return;
00541                 }
00542 
00543                 c->req_len += ret;
00544 
00545                 if( c->req_len == sizeof( c->req_buf ) - 1 )
00546                 {
00547                         fprintf( stderr, "malformed request from client\n" );
00548                         drop_conn( c );
00549                         return;
00550                 }
00551 
00552                 c->req_buf[c->req_len] = 0;
00553                 while( ( ret = parse_client_data( c ) ) > 0 );
00554                 if( ret < 0 ) return;
00555         }
00556 }
00557 
00558 static void do_accept(struct event *e, void *d) {
00559         struct listener *listener = (struct listener *)d;
00560         int fd;
00561         socklen_t addrlen;
00562         struct sockaddr_in addr;
00563         struct conn *c;
00564 
00565         addrlen = sizeof(addr);
00566         if((fd = accept( listener->fd, (struct sockaddr *)&addr, &addrlen)) < 0) {
00567                 perror("accept");
00568                 exit(1);
00569         }
00570 
00571 #ifdef DEBUG    
00572         fprintf(stderr, "accepted connection\n");
00573 #endif
00574 
00575         fcntl(fd, F_SETFL, O_NONBLOCK);
00576 
00577         c = (struct conn *)malloc(sizeof(struct conn));
00578         c->next = conn_list;
00579         if(c->next)
00580                 c->next->prev = c;
00581         c->prev = NULL;
00582         c->fd = fd;
00583         c->client_addr = addr;
00584         c->state = CONN_STATE_START;
00585         c->req_len = 0;
00586         c->read_event = add_fd_event(fd, 0, 0, do_read, c);
00587         c->write_event = add_fd_event(fd, 1, 0, conn_write, c);
00588         set_event_enabled(c->write_event, 0);
00589         c->send_buf_r = c->send_buf_w = 0;
00590         c->drop_after = 0;
00591         c->attached_session = NULL;
00592         conn_list = c;
00593         c->close_flag = 0;
00594 }
00595 
00596 
00597 
00598 int rtsp_listen(struct param *p) {
00599         int port;
00600         struct sockaddr_in addr;
00601         struct listener *listener;
00602         int opt, fd;
00603         
00604         _param = p;
00605         port = p->rtsp_port;
00606 
00607         addr.sin_family = AF_INET;
00608         addr.sin_addr.s_addr = 0;
00609         addr.sin_port = htons(port);
00610 
00611         if((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
00612                 perror("socket");
00613                 return -1;
00614         }
00615         opt = 1;
00616         if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
00617                 perror("setsockopt");
00618         if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00619                 perror("bind");
00620                 close(fd);
00621                 return -1;
00622         }
00623         if(listen(fd, 5) < 0) {
00624                 perror("listen");
00625                 close(fd);
00626                 return -1;
00627         }
00628 
00629         listener = (struct listener *)malloc(sizeof(struct listener));
00630         listener->fd = fd;
00631 
00632         add_fd_event(fd, 0, 0, do_accept, listener);
00633 #ifdef DEBUG
00634         fprintf(stderr, "listening on port %d\n", port);
00635 #endif
00636         return 0;
00637 }
00638 

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1