int RTSP_setup(RTSP_buffer * pRtsp) { char s8TranStr[128], *s8Str; char *pStr; RTP_transport Transport; int s32SessionID=0; RTP_session *rtp_s, *rtp_s_prec; RTSP_session *rtsp_s; if ((s8Str = strstr(pRtsp->in_buffer, HDR_TRANSPORT)) == NULL) { fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__); send_reply(406, 0, pRtsp); // Not Acceptable printf("not acceptable"); return ERR_NOERROR; } //检查传输层子串是否正确 if (sscanf(s8Str, "%*10s %255s", s8TranStr) != 1) { fprintf(stderr,"SETUP request malformed: Transport string is empty\n"); send_reply(400, 0, pRtsp); // Bad Request printf("check transport 400 bad request"); return ERR_NOERROR; } fprintf(stderr,"*** transport: %s ***\n", s8TranStr); //如果需要增加一个会话 if ( !pRtsp->session_list ) { pRtsp->session_list = (RTSP_session *) calloc(1, sizeof(RTSP_session)); } rtsp_s = pRtsp->session_list; //建立一个新会话,插入到链表中 if (pRtsp->session_list->rtp_session == NULL) { pRtsp->session_list->rtp_session = (RTP_session *) calloc(1, sizeof(RTP_session)); rtp_s = pRtsp->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; } /* printf("\tFile Name %s\n", Object); if((rtp_s->file_id = open(Object, O_RDONLY)) < 0) { printf("Open File error %s, %d\n", __FILE__, __LINE__); } */ //起始状态为暂停 rtp_s->pause = 1; rtp_s->hndRtp = NULL; Transport.type = RTP_no_transport; if((pStr = strstr(s8TranStr, RTSP_RTP_AVP))) { //Transport: RTP/AVP pStr += strlen(RTSP_RTP_AVP); if ( !*pStr || (*pStr == ';') || (*pStr == ' ')) { //单播 if (strstr(s8TranStr, "unicast")) { //如果指定了客户端端口号,填充对应的两个端口号 if( (pStr = strstr(s8TranStr, "client_port")) ) { pStr = strstr(s8TranStr, "="); sscanf(pStr + 1, "%d", &(Transport.u.udp.cli_ports.RTP)); pStr = strstr(s8TranStr, "-"); sscanf(pStr + 1, "%d", &(Transport.u.udp.cli_ports.RTCP)); } //服务器端口 if (RTP_get_port_pair(&Transport.u.udp.ser_ports) != ERR_NOERROR) { fprintf(stderr, "Error %s,%d\n", __FILE__, __LINE__); send_reply(500, 0, pRtsp);/* Internal server error */ return ERR_GENERIC; } //建立RTP套接字 rtp_s->hndRtp = (struct _tagStRtpHandle*)RtpCreate((unsigned int)(((struct sockaddr_in *)(&pRtsp->stClientAddr))->sin_addr.s_addr), Transport.u.udp.cli_ports.RTP, _h264nalu); printf("<><><><>Creat RTP<><><><>\n"); Transport.u.udp.is_multicast = 0; } else { printf("multicast not codeing\n"); //multicast 多播处理.... } Transport.type = RTP_rtp_avp; } else if (!strncmp(s8TranStr, "/TCP", 4)) { if( (pStr = strstr(s8TranStr, "interleaved")) ) { pStr = strstr(s8TranStr, "="); sscanf(pStr + 1, "%d", &(Transport.u.tcp.interleaved.RTP)); if ((pStr = strstr(pStr, "-"))) sscanf(pStr + 1, "%d", &(Transport.u.tcp.interleaved.RTCP)); else Transport.u.tcp.interleaved.RTCP = Transport.u.tcp.interleaved.RTP + 1; } else { } Transport.rtp_fd = pRtsp->fd; // Transport.rtcp_fd_out = pRtsp->fd; // Transport.rtcp_fd_in = -1; Transport.type = RTP_rtp_avp_tcp; } } printf("pstr=%s\n",pStr); if (Transport.type == RTP_no_transport) { fprintf(stderr,"AAAAAAAAAAA Unsupported Transport,%s,%d\n", __FILE__, __LINE__); send_reply(461, 0, pRtsp);// Bad Request return ERR_NOERROR; } memcpy(&rtp_s->transport, &Transport, sizeof(Transport)); //如果有会话头,就有了一个控制集合 if ((pStr = strstr(pRtsp->in_buffer, HDR_SESSION)) != NULL) { if (sscanf(pStr, "%*s %d", &s32SessionID) != 1) { fprintf(stderr, "Error %s,%i\n", __FILE__, __LINE__); send_reply(454, 0, pRtsp); // Session Not Found return ERR_NOERROR; } } else { //产生一个非0的随机的会话序号 struct timeval stNowTmp; gettimeofday(&stNowTmp, 0); srand((stNowTmp.tv_sec * 1000) + (stNowTmp.tv_usec / 1000)); s32SessionID = 1 + (int) (10.0 * rand() / (100000 + 1.0)); if (s32SessionID == 0) { s32SessionID++; } } pRtsp->session_list->session_id = s32SessionID; pRtsp->session_list->rtp_session->sched_id = schedule_add(rtp_s); send_setup_reply(pRtsp, rtsp_s, rtp_s); 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; }