int send_play_reply(RTSP_buffer * rtsp, char *object, RTSP_session * rtsp_session) { char r[1024]; char temp[30]; RTP_session *p = rtsp_session->rtp_session; TRACE_FUNC(); /* build a reply message */ sprintf(r, "%s %d %s" RTSP_EL "CSeq: %d" RTSP_EL "Server: %s/%s" RTSP_EL, RTSP_VER, 200, get_stat(200), rtsp->rtsp_cseq, PACKAGE, VERSION); add_time_stamp(r, 0); strcat(r, "Session: "); sprintf(temp, "%d", rtsp_session->session_id); strcat(r, temp); strcat(r, RTSP_EL); // strcat(r, "RTP-info: url="); strcat(r, "RTP-info: "); // strcat(r, object); // strcat(r, ";"); do { strcat(r, "url="); // strcat(r, object); // TODO: we MUST be sure to send the correct url sprintf(r + strlen(r), "rtsp://%s/%s/%s!%s", prefs_get_hostname(), p->sd_filename, p->sd_filename, p->current_media->filename); strcat(r, ";"); sprintf(r + strlen(r), "seq=%u;rtptime=%u", p->start_seq, p->start_rtptime); if (p->next != NULL) { strcat(r, ","); } else { // strcat(r, "\r\n\r\n"); strcat(r, RTSP_EL); } p = p->next; } while (p != NULL); // end of message strcat(r, RTSP_EL); bwrite(r, (unsigned short) strlen(r), rtsp); // INFOLOGG("200 - %s ", object); return ERR_NOERROR; }
int RTCP_send_packet(RTP_session *session,rtcp_pkt_type type) { unsigned char *pkt=NULL; RTCP_header hdr; uint32 pkt_size=0,hdr_s=0; hdr.version=2; hdr.padding=0; hdr.pt=type; hdr_s=sizeof(hdr); switch (type) { case SR: { struct timeval ntp_time; RTCP_header_SR hdr_sr; int hdr_sr_s; //printf("SR\n"); hdr_sr_s=sizeof(hdr_sr); pkt_size=hdr_s+hdr_sr_s; hdr.length=htons((pkt_size >> 2) -1); hdr.count=0; hdr_sr.ssrc=htonl(session->ssrc); gettimeofday(&ntp_time, NULL); hdr_sr.ntp_timestampH = htonl((unsigned int)ntp_time.tv_sec); hdr_sr.ntp_timestampL = htonl((unsigned int)ntp_time.tv_usec); hdr_sr.rtp_timestamp = htonl((unsigned int)((double)ntp_time.tv_sec + (double)ntp_time.tv_usec/1000000.) * session->current_media->description.clock_rate + session->start_rtptime); hdr_sr.pkt_count=session->rtcp_stats[i_server].pkt_count; hdr_sr.octet_count=session->rtcp_stats[i_server].octet_count; pkt=(unsigned char*)calloc(1,pkt_size); if (pkt==NULL) { return ERR_ALLOC; } memcpy(pkt,&hdr,hdr_s); memcpy(pkt+hdr_s,&hdr_sr,hdr_sr_s); //fprintf(stderr,"pkt_size=%d,hdr_s=%d,hdr_sr_s=%d\n",pkt_size,hdr_s,hdr_sr_s); break; } case RR: { RTCP_header_RR hdr_rr; int hdr_rr_s; //printf("RR\n"); hdr_rr_s=sizeof(hdr_rr); pkt_size=hdr_s+hdr_rr_s; hdr.length=htons((pkt_size >> 2) -1); hdr.count=0; hdr_rr.ssrc=htonl(session->ssrc); pkt=(unsigned char*)calloc(1,pkt_size); if (pkt==NULL) { return ERR_ALLOC; } memcpy(pkt,&hdr,hdr_s); memcpy(pkt+hdr_s,&hdr_rr,hdr_rr_s); break; } case SDES: { RTCP_header_SDES hdr_sdes; char *name; int hdr_sdes_s,name_s; //printf("SDES\n"); name=prefs_get_hostname(); name_s=strlen(name); hdr_sdes_s=sizeof(hdr_sdes); pkt_size=(((hdr_s+hdr_sdes_s+name_s)%4)?1:0)+(hdr_s+hdr_sdes_s+name_s); hdr.length=htons((pkt_size >> 2) -1); pkt=(unsigned char*)calloc(1,pkt_size); if (pkt==NULL) { return ERR_ALLOC; } hdr.count=1; hdr_sdes.ssrc=htonl(session->ssrc); hdr_sdes.attr_name=htonl(1); // 1=CNAME hdr_sdes.len=htonl(name_s); memcpy(pkt,&hdr,hdr_s); memcpy(pkt+hdr_s,&hdr_sdes,hdr_sdes_s); memcpy(pkt+hdr_s+hdr_sdes_s,name,name_s); //fprintf(stderr,"pkt_size=%d,hdr_s=%d,hdr_sdes_s=%d,name_s=%d\n",pkt_size,hdr_s,hdr_sdes_s,name_s); break; } case BYE: { RTCP_header_BYE hdr_bye; int hdr_bye_s; char *reason="The medium is over."; //printf("BYE\n"); hdr_bye_s=sizeof(hdr_bye); pkt_size=hdr_s+hdr_bye_s; hdr.length=htons((pkt_size >> 2) -1); hdr.count=1; hdr_bye.ssrc=htonl(session->ssrc); hdr_bye.length=htonl(strlen(reason)); hdr_bye.ssrc=htonl(session->ssrc); pkt=(unsigned char*)calloc(1,pkt_size); if (pkt==NULL) { return ERR_ALLOC; } memcpy(pkt,&hdr,hdr_s); memcpy(pkt+hdr_s,&hdr_bye,hdr_bye_s); break; } default: { //printf("DEFAULT\n"); return ERR_NOERROR; } } if (session->rtcp_outsize+pkt_size<=sizeof(session->rtcp_outbuffer)) { memcpy(session->rtcp_outbuffer+session->rtcp_outsize,pkt,pkt_size); session->rtcp_outsize+=pkt_size; } else { fnc_log(FNC_LOG_VERBOSE,"Output RTCP packet lost\n"); } free(pkt); return ERR_NOERROR; }
int RTSP_teardown(RTSP_buffer * rtsp) { long int session_id; char *p; RTSP_session *s; RTP_session *rtp_curr, *rtp_prev = NULL, *rtp_temp; int valid_url; char object[255], server[255], trash[255], *filename; unsigned short port; char url[255]; unsigned int cseq; // CSeq if ((p = strstr(rtsp->in_buffer, HDR_CSEQ)) == NULL) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_PARSE; } else { if (sscanf(p, "%254s %d", trash, &(rtsp->rtsp_cseq)) != 2) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_PARSE; } } cseq = rtsp->rtsp_cseq; /* Extract the URL */ if (!sscanf(rtsp->in_buffer, " %*s %254s ", url)) { send_reply(400, 0, rtsp); /* bad request */ return ERR_PARSE; } /* Validate the URL */ switch (parse_url(url, server, sizeof(server), &port, object, sizeof(object))) { case 1: // bad request send_reply(400, 0, rtsp); return ERR_PARSE; break; case -1: // internal server error send_reply(500, 0, rtsp); return ERR_PARSE; break; default: break; } if (strcmp(server, prefs_get_hostname()) != 0) { /* Currently this feature is disabled. */ /* wrong server name */ // send_reply(404, 0 , rtsp); /* Not Found */ // return ERR_PARSE; } if (strstr(object, "../")) { /* disallow relative paths outside of current directory. */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_PARSE; } if (strstr(object, "./")) { /* Disallow ./ */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_PARSE; } p = strrchr(object, '.'); valid_url = 0; if (p == NULL) { send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_PARSE; } else { valid_url = is_supported_url(p); } if (!valid_url) { send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_PARSE; } // Session if ((p = strstr(rtsp->in_buffer, HDR_SESSION)) != NULL) { if (sscanf(p, "%254s %ld", trash, &session_id) != 2) { send_reply(454, 0, rtsp); /* Session Not Found */ return ERR_PARSE; // return ERR_NOERROR; } } else { session_id = -1; } s = rtsp->session_list; if (s == NULL) { send_reply(415, 0, rtsp); // Internal server error return ERR_GENERIC; } if (s->session_id != session_id) { send_reply(454, 0, rtsp); /* Session Not Found */ return ERR_PARSE; } fnc_log(FNC_LOG_INFO,"TEARDOWN %s RTSP/1.0 ",url); send_teardown_reply(rtsp, session_id, cseq); // See User-Agent if ((p=strstr(rtsp->in_buffer, HDR_USER_AGENT))!=NULL) { char cut[strlen(p)]; strcpy(cut,p); p=strstr(cut, "\n"); cut[strlen(cut)-strlen(p)-1]='\0'; fnc_log(FNC_LOG_CLIENT,"%s\n",cut); } else fnc_log(FNC_LOG_CLIENT,"- \n"); if (strchr(object, '!')) /*Compatibility with RealOne and RealPlayer */ filename = strchr(object, '!') + 1; else filename = object; // Release all URI RTP session rtp_curr = s->rtp_session; while (rtp_curr != NULL) { if (strcmp(rtp_curr->current_media->filename, filename) == 0 || strcmp(rtp_curr->current_media->aggregate, filename) == 0) { rtp_temp = rtp_curr; if (rtp_prev != NULL) rtp_prev->next = rtp_curr->next; else s->rtp_session = rtp_curr->next; rtp_curr = rtp_curr->next; // Release the scheduler entry schedule_remove(rtp_temp->sched_id); // Close connections } else { rtp_prev = rtp_curr; rtp_curr = rtp_curr->next; } } if (s->rtp_session == NULL) { // Close connection //close(s->fd); // Release the RTSP session free(rtsp->session_list); rtsp->session_list = NULL; } return ERR_NOERROR; }
int RTSP_setup(RTSP_buffer * rtsp, RTSP_session ** new_session) { char address[16]; char object[255], server[255]; char url[255]; unsigned short port; RTSP_session *rtsp_s; RTP_session *rtp_s, *rtp_s_prec; int SessionID = 0; // port_pair cli_ports; // port_pair ser_ports; struct timeval now_tmp; char *p/* = NULL*/; unsigned int start_seq, start_rtptime; char transport_str[255]; media_entry *list, *matching_me, req; struct sockaddr_storage rtsp_peer; socklen_t namelen = sizeof(rtsp_peer); unsigned long ssrc; SD_descr *matching_descr; unsigned char is_multicast_dad = 1; //unicast and the first multicast RTP_transport transport; char *saved_ptr, *transport_tkn; int max_interlvd; // init memset(&req, 0, sizeof(req)); memset(&transport, 0, sizeof(transport)); // Parse the input message /* Get the URL */ if (!sscanf(rtsp->in_buffer, " %*s %254s ", url)) { send_reply(400, 0, rtsp); /* bad request */ return ERR_NOERROR; } /* Validate the URL */ switch (parse_url(url, server, sizeof(server), &port, object, sizeof(object))) { //object is requested file's name case 1: // bad request send_reply(400, 0, rtsp); return ERR_NOERROR; case -1: // interanl server error send_reply(500, 0, rtsp); return ERR_NOERROR; break; default: break; } if (strcmp(server, prefs_get_hostname()) != 0) { /* Currently this feature is disabled. */ /* wrong server name */ // send_reply(404, 0 , rtsp); /* Not Found */ // return ERR_NOERROR; } if (strstr(object, "../")) { /* disallow relative paths outside of current directory. */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_NOERROR; } if (strstr(object, "./")) { /* Disallow the ./ */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_NOERROR; } if (!(p = strrchr(object, '.'))) { // if filename is without extension send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_NOERROR; } else if (!is_supported_url(p)) { //if filename's extension is not valid send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_NOERROR; } if ( !(p = strchr(object, '!')) ) { //if '!' is not present then a file has not been specified send_reply(500, 0, rtsp); /* Internal server error */ return ERR_NOERROR; } else { // SETUP name.sd!stream strcpy(req.filename, p + 1); req.flags |= ME_FILENAME; *p = '\0'; } // ------------ START PATCH { char temp[255]; char *pd=NULL; strcpy(temp, object); #if 0 printf("%s\n", object); // BEGIN // if ( (p = strstr(temp, "/")) ) { if ( (p = strchr(temp, '/')) ) { strcpy(object, p + 1); // CRITIC. } printf("%s\n", temp); #endif // pd = strstr(p, ".sd"); // this part is usefull in order to pd = strstr(temp, ".sd"); if ( (p = strstr(pd + 1, ".sd")) ) { // have compatibility with RealOne strcpy(object, pd + 4); // CRITIC. } //Note: It's a critic part // END } // ------------ END PATCH if (enum_media(object, &matching_descr) != ERR_NOERROR) { send_reply(500, 0, rtsp); /* Internal server error */ return ERR_NOERROR; } list=matching_descr->me_list; if (get_media_entry(&req, list, &matching_me) == ERR_NOT_FOUND) { send_reply(404, 0, rtsp); /* Not found */ return ERR_NOERROR; } // Get the CSeq if ((p = strstr(rtsp->in_buffer, HDR_CSEQ)) == NULL) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } else { if (sscanf(p, "%*s %d", &(rtsp->rtsp_cseq)) != 1) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } } /*if ((p = strstr(rtsp->in_buffer, "ssrc")) != NULL) { p = strchr(p, '='); sscanf(p + 1, "%lu", &ssrc); } else {*/ ssrc = random32(0); //} // Start parsing the Transport header if ((p = strstr(rtsp->in_buffer, HDR_TRANSPORT)) == NULL) { send_reply(406, "Require: Transport settings" /* of rtp/udp;port=nnnn. "*/, rtsp); /* Not Acceptable */ return ERR_NOERROR; } if (sscanf(p, "%*10s%255s", transport_str) != 1) { fnc_log(FNC_LOG_ERR,"SETUP request malformed: Transport string is empty\n"); send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } printf("transport: %s\n", transport_str); // XXX tmp. // tokenize the coma seaparated list of transport settings: if ( !(transport_tkn=strtok_r(transport_str, ",", &saved_ptr)) ) { fnc_log(FNC_LOG_ERR,"Malformed Transport string from client\n"); send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } if (getpeername(rtsp->fd, (struct sockaddr *)&rtsp_peer, &namelen) != 0) { send_reply(415, 0, rtsp); // Internal server error return ERR_GENERIC; } transport.type = RTP_no_transport; do { // search a good transport string if ( (p = strstr(transport_tkn, RTSP_RTP_AVP)) ) { // Transport: RTP/AVP p += strlen(RTSP_RTP_AVP); if ( !*p || (*p == ';') || (*p == ' ')) { #if 0 // if ((p = strstr(rtsp->in_buffer, "client_port")) == NULL && strstr(rtsp->in_buffer, "multicast") == NULL) { if ((p = strstr(transport_tkn, "client_port")) == NULL && strstr(transport_tkn, "multicast") == NULL) { send_reply(406, "Require: Transport settings of rtp/udp;port=nnnn. ", rtsp); /* Not Acceptable */ return ERR_NOERROR; } #endif // #if 0 if (strstr(transport_tkn, "unicast")) { if( (p = strstr(transport_tkn, "client_port")) ) { p = strstr(p, "="); sscanf(p + 1, "%d", &(transport.u.udp.cli_ports.RTP)); p = strstr(p, "-"); sscanf(p + 1, "%d", &(transport.u.udp.cli_ports.RTCP)); } if (RTP_get_port_pair(&transport.u.udp.ser_ports) != ERR_NOERROR) { send_reply(500, 0, rtsp); /* Internal server error */ return ERR_GENERIC; } // strcpy(address, get_address()); //UDP connection for outgoing RTP packets udp_connect(transport.u.udp.cli_ports.RTP, &transport.u.udp.rtp_peer, (*((struct sockaddr_in *) (&rtsp_peer))).sin_addr.s_addr,&transport.rtp_fd); //UDP connection for outgoing RTCP packets udp_connect(transport.u.udp.cli_ports.RTCP, &transport.u.udp.rtcp_out_peer,(*((struct sockaddr_in *) (&rtsp_peer))).sin_addr.s_addr, &transport.rtcp_fd_out); udp_open(transport.u.udp.ser_ports.RTCP, &transport.u.udp.rtcp_in_peer, &transport.rtcp_fd_in); //bind transport.u.udp.is_multicast = 0; } else if ( matching_descr->flags & SD_FL_MULTICAST ) { /*multicast*/ // TODO: make the difference between only multicast allowed or unicast fallback allowed. transport.u.udp.cli_ports.RTP = transport.u.udp.ser_ports.RTP =matching_me->rtp_multicast_port; transport.u.udp.cli_ports.RTCP = transport.u.udp.ser_ports.RTCP =matching_me->rtp_multicast_port+1; is_multicast_dad = 0; if (!(matching_descr->flags & SD_FL_MULTICAST_PORT) ) { struct in_addr inp; unsigned char ttl=DEFAULT_TTL; struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(matching_descr->multicast); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(transport.rtp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); setsockopt(transport.rtp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); is_multicast_dad = 1; strcpy(address, matching_descr->multicast); //RTP outgoing packets inet_aton(address, &inp); udp_connect(transport.u.udp.ser_ports.RTP, &transport.u.udp.rtp_peer, inp.s_addr, &transport.rtp_fd); //RTCP outgoing packets inet_aton(address, &inp); udp_connect(transport.u.udp.ser_ports.RTCP, &transport.u.udp.rtcp_out_peer, inp.s_addr, &transport.rtcp_fd_out); //udp_open(transport.u.udp.ser_ports.RTCP, &(sp2->rtcp_in_peer), &(sp2->rtcp_fd_in)); //bind if(matching_me->next==NULL) matching_descr->flags |= SD_FL_MULTICAST_PORT; matching_me->rtp_multicast_port = transport.u.udp.ser_ports.RTP; transport.u.udp.is_multicast = 1; fnc_log(FNC_LOG_DEBUG,"\nSet up socket for multicast ok\n"); } } else continue; transport.type = RTP_rtp_avp; break; // found a valid transport } else if (!strncmp(p, "/TCP", 4)) { // Transport: RTP/AVP/TCP;interleaved=x-y // XXX still not finished if( (p = strstr(transport_tkn, "interleaved")) ) { p = strstr(p, "="); sscanf(p + 1, "%d", &(transport.u.tcp.interleaved.RTP)); if ( (p = strstr(p, "-")) ) sscanf(p + 1, "%d", &(transport.u.tcp.interleaved.RTCP)); else transport.u.tcp.interleaved.RTCP = transport.u.tcp.interleaved.RTP + 1; } else { // search for max used interleved channel. max_interlvd = -1; for (rtp_s = (rtsp->session_list)?rtsp->session_list->rtp_session:NULL; rtp_s; rtp_s = rtp_s->next) max_interlvd = max(max_interlvd, (rtp_s->transport.type == RTP_rtp_avp_tcp)?rtp_s->transport.u.tcp.interleaved.RTCP:-1); transport.u.tcp.interleaved.RTP = max_interlvd + 1; transport.u.tcp.interleaved.RTCP = max_interlvd + 2; } transport.rtp_fd = rtsp->fd; // dup(rtsp->fd); transport.rtcp_fd_out = rtsp->fd; // dup(rtsp->fd); transport.rtcp_fd_in = -1; transport.type = RTP_rtp_avp_tcp; break; // found a valid transport } } } while ((transport_tkn=strtok_r(NULL, ",", &saved_ptr))); printf("rtp transport: %d\n", transport.type); if (transport.type == RTP_no_transport) { // fnc_log(FNC_LOG_ERR,"Unsupported Transport\n"); send_reply(461, "Unsupported Transport", rtsp); /* Bad Request */ return ERR_NOERROR; } // If there's a Session header we have an aggregate control if ((p = strstr(rtsp->in_buffer, HDR_SESSION)) != NULL) { if (sscanf(p, "%*s %d", &SessionID) != 1) { send_reply(454, 0, rtsp); /* Session Not Found */ return ERR_NOERROR; } } else { // Generate a random Session number gettimeofday(&now_tmp, 0); srand((now_tmp.tv_sec * 1000) + (now_tmp.tv_usec / 1000)); #ifdef WIN32 SessionID = rand(); #else SessionID = 1 + (int) (10.0 * rand() / (100000 + 1.0)); #endif if (SessionID == 0) { SessionID++; } } // Add an RTSP session if necessary if ( !rtsp->session_list ) { rtsp->session_list = (RTSP_session *) calloc(1, sizeof(RTSP_session)); } rtsp_s = rtsp->session_list; // Setup the RTP session if (rtsp->session_list->rtp_session == NULL) { rtsp->session_list->rtp_session = (RTP_session *) calloc(1, sizeof(RTP_session)); rtp_s = rtsp->session_list->rtp_session; } else { for (rtp_s = rtsp_s->rtp_session; rtp_s != NULL; rtp_s = rtp_s->next) { rtp_s_prec = rtp_s; } rtp_s_prec->next = (RTP_session *) calloc(1, sizeof(RTP_session)); rtp_s = rtp_s_prec->next; } #ifdef WIN32 start_seq = rand(); start_rtptime = rand(); #else // start_seq = 1 + (int) (10.0 * rand() / (100000 + 1.0)); // start_rtptime = 1 + (int) (10.0 * rand() / (100000 + 1.0)); #if 0 start_seq = 1 + (unsigned int) ((float)(0xFFFF) * ((float)rand() / (float)RAND_MAX)); start_rtptime = 1 + (unsigned int) ((float)(0xFFFFFFFF) * ((float)rand() / (float)RAND_MAX)); #else start_seq = 1 + (unsigned int) (rand()%(0xFFFF)); start_rtptime = 1 + (unsigned int) (rand()%(0xFFFFFFFF)); #endif #endif if (start_seq == 0) { start_seq++; } if (start_rtptime == 0) { start_rtptime++; } rtp_s->pause = 1; strcpy(rtp_s->sd_filename, object); /*xxx*/ rtp_s->current_media = (media_entry *) calloc(1, sizeof(media_entry)); // if(!(matching_descr->flags & SD_FL_MULTICAST_PORT)){ if( is_multicast_dad ) { if ( mediacpy(&rtp_s->current_media, &matching_me) ) { send_reply(500, 0, rtsp); /* Internal server error */ return ERR_GENERIC; } } gettimeofday(&now_tmp, 0); srand((now_tmp.tv_sec * 1000) + (now_tmp.tv_usec / 1000)); rtp_s->start_rtptime = start_rtptime; rtp_s->start_seq = start_seq; memcpy(&rtp_s->transport, &transport, sizeof(transport)); rtp_s->is_multicast_dad = is_multicast_dad; /*xxx*/ rtp_s->sd_descr=matching_descr; rtp_s->sched_id = schedule_add(rtp_s); rtp_s->ssrc = ssrc; // Setup the RTSP session rtsp_s->session_id = SessionID; *new_session = rtsp_s; fnc_log(FNC_LOG_INFO,"SETUP %s RTSP/1.0 ",url); send_setup_reply(rtsp, rtsp_s, matching_descr, rtp_s); // See User-Agent if ((p=strstr(rtsp->in_buffer, HDR_USER_AGENT))!=NULL) { char cut[strlen(p)]; strcpy(cut,p); p=strstr(cut, "\n"); cut[strlen(cut)-strlen(p)-1]='\0'; fnc_log(FNC_LOG_CLIENT,"%s\n",cut); } else fnc_log(FNC_LOG_CLIENT,"- \n"); return ERR_NOERROR; }
/* **************************************************************** * DESCRIBE METHOD HANDLING **************************************************************** */ int RTSP_describe(RTSP_buffer * rtsp) { int valid_url, res; char object[255], server[255], trash[255]; char *p; unsigned short port; char url[255]; media_entry media, req; description_format descr_format = df_SDP_format; // shawill put to some default char descr[MAX_DESCR_LENGTH]; /* Extract la URL */ if (!sscanf(rtsp->in_buffer, " %*s %254s ", url)) { send_reply(400, 0, rtsp); /* bad request */ return ERR_NOERROR; } /* Validate the URL */ switch (parse_url(url, server, sizeof(server), &port, object, sizeof(object))) { case 1: // bad request send_reply(400, 0, rtsp); return ERR_NOERROR; break; case -1: // internal server error send_reply(500, 0, rtsp); return ERR_NOERROR; break; default: break; } if (strcmp(server, prefs_get_hostname()) != 0) { /* Currently this feature is disabled. */ /* wrong server name */ // send_reply(404, 0 , rtsp); /* Not Found */ // return ERR_NOERROR; } if (strstr(object, "../")) { /* disallow relative paths outside of current directory. */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_NOERROR; } if (strstr(object, "./")) { /* Disallow ./ */ send_reply(403, 0, rtsp); /* Forbidden */ return ERR_NOERROR; } p = strrchr(object, '.'); valid_url = 0; if (p == NULL) { send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_NOERROR; } else { valid_url = is_supported_url(p); } if (!valid_url) { send_reply(415, 0, rtsp); /* Unsupported media type */ return ERR_NOERROR; } // Disallow Header REQUIRE if (strstr(rtsp->in_buffer, HDR_REQUIRE)) { send_reply(551, 0, rtsp); /* Option not supported */ return ERR_NOERROR; } /* Get the description format. SDP is recomended */ if (strstr(rtsp->in_buffer, HDR_ACCEPT) != NULL) { if (strstr(rtsp->in_buffer, "application/sdp") != NULL) { descr_format = df_SDP_format; } else { // Add here new description formats send_reply(551, 0, rtsp); /* Option not supported */ return ERR_NOERROR; } } // Get the CSeq if ((p = strstr(rtsp->in_buffer, HDR_CSEQ)) == NULL) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } else { if (sscanf(p, "%254s %d", trash, &(rtsp->rtsp_cseq)) != 2) { send_reply(400, 0, rtsp); /* Bad Request */ return ERR_NOERROR; } } memset(&media, 0, sizeof(media)); memset(&req, 0, sizeof(req)); req.flags = ME_DESCR_FORMAT; req.descr_format = descr_format; res = get_media_descr(object, &req, &media, descr); if (res == ERR_NOT_FOUND) { send_reply(404, 0, rtsp); // Not found return ERR_NOERROR; } if (res == ERR_PARSE || res == ERR_GENERIC || res == ERR_ALLOC) { send_reply(500, 0, rtsp); // Internal server error return ERR_NOERROR; } if(max_connection()==ERR_GENERIC){ /*redirect*/ return send_redirect_3xx(rtsp, object); } fnc_log(FNC_LOG_INFO,"DESCRIBE %s RTSP/1.0 ",url); send_describe_reply(rtsp, object, descr_format, descr); // See User-Agent if ((p=strstr(rtsp->in_buffer, HDR_USER_AGENT))!=NULL) { char cut[strlen(p)]; strcpy(cut,p); p=strstr(cut, "\n"); cut[strlen(cut)-strlen(p)-1]='\0'; fnc_log(FNC_LOG_CLIENT,"%s\n",cut); } else fnc_log(FNC_LOG_CLIENT,"- \n"); return ERR_NOERROR; }