/*! \brief License permissions checking function. * * The function will check the license given as first paramenter is compatible * with the permissions accepted by user in <tt>Permission Mask</tt> given as * second parameter. Exiting, the function will return in <tt>mask</tt> * parameter the mask of permissions that conflict with license. * * \param license cc_license struct of license. * * \param mask pointer to permission mask used as input paramter for * accepted permissions by user and as return value for conflicting * permissions. */ int cc_perm_chk(cc_license * license, cc_perm_mask * mask) { cc_perm_mask parsedmsk; return 0; //TODO: Disabled license check, should be made in a better way if (!license) { nms_printf(NMSML_DBG1, "no CC license defined\n"); return 0; } // uriLicense parse if (!license->uriLicense) return nms_printf(NMSML_ERR, "no uriLicense present: could not parse license uri\n"); if ((cc_parse_urilicense(license->uriLicense, &parsedmsk))) return nms_printf(NMSML_ERR, "cannot parse uriLicense (cc_prms_mask)\n"); *((CC_BITMASK_T *) mask) = ~(*((CC_BITMASK_T *) mask)) & *((CC_BITMASK_T *) & parsedmsk); if (*((CC_BITMASK_T *) mask)) return 1; return 0; }
int set_rtsp_sessions(rtsp_thread * rtsp_th, int content_length, char *content_base, char *body) { sdp_attr *sdp_a; char *tkn; switch (rtsp_th->descr_fmt) { case DESCRIPTION_SDP_FORMAT: if (! (rtsp_th->rtsp_queue = rtsp_sess_create(rtsp_th->urlname, content_base))) return 1; if (! (rtsp_th->rtsp_queue->body = (char *) malloc(content_length + 1))) return nms_printf(NMSML_FATAL, "Cannot allocate memory.\n"); memcpy(rtsp_th->rtsp_queue->body, body, content_length); rtsp_th->rtsp_queue->body[content_length] = '\0'; rtsp_th->type = M_ON_DEMAND; if (! (rtsp_th->rtsp_queue->info = sdp_session_setup(rtsp_th->rtsp_queue->body, content_length))) return nms_printf(NMSML_ERR, "SDP parse error\n"); // we look for particular attributes of session for (sdp_a = rtsp_th->rtsp_queue->info->attr_list; sdp_a; sdp_a = sdp_a->next) { if (!strncasecmp(sdp_a->name, "control", 7)) { tkn = sdp_a->value; // 7 == strlen("control") while ((*tkn == ' ') || (*tkn == ':')) // skip spaces and colon tkn++; rtsp_th->rtsp_queue->pathname = tkn; rtsp_th->type = CONTAINER; } } // media setup if (set_rtsp_media(rtsp_th)) return 1; break; case DESCRIPTION_MH_FORMAT: /* not yet implemented */ // break; default: nms_printf(NMSML_ERR, "Unknown decription format.\n"); return 1; break; } return 0; }
/*! \brief Parses Licenes URI and fills cc_perms data structure. * * To know what are the conditions of the license we parse the uri and look for * short names. * * \param uri license uri to parse. * \param conds cc_perms structure to be filled. */ int cc_parse_urilicense(char *uri, cc_perm_mask * mask) { char *tkn, *permstr, *step; unsigned int i; memset(mask, 0, sizeof(*mask)); // look if there is an "http:// prefix" if (strncasecmp(uri, "http://", 7)) tkn = uri; else tkn = uri + 7; if (strncasecmp(tkn, BASE_URI_LICENSE, strlen(BASE_URI_LICENSE))) // TODO: must continue or give an error, or ask what to to? return nms_printf(NMSML_ERR, "the base URI of license is not \"%s\", so it can't be considered valid\n"); tkn = tkn + strlen(BASE_URI_LICENSE); while (*tkn == '/') tkn++; if (!(permstr = strdup(tkn))) return nms_printf(NMSML_FATAL, "memory error in cc_parse_urilicense\n"); if ((tkn = strchr(permstr, '/'))) *tkn = '\0'; // Check for special licenses :TODO // for (i=0; i<sizeof(cc_spec_licenses)/sizeof(*cc_spec_licenses); i++) { for (i = 0; cc_spec_licenses[i].int_code; i++) { if (!strcasecmp(permstr, cc_spec_licenses[i].urlstr)) { mask->spec_license = cc_spec_licenses[i].int_code; break; } } if (!mask->spec_license) // Search for CC atributes for (tkn = strtok_r(permstr, "-", &step); tkn; tkn = strtok_r(NULL, "-", &step)) { // while(tkn) { if (!strcasecmp(tkn, cc_by.urltkn)) mask->by = 1; else if (!strcasecmp(tkn, cc_nc.urltkn)) mask->nc = 1; else if (!strcasecmp(tkn, cc_nd.urltkn)) mask->nd = 1; else if (!strcasecmp(tkn, cc_sa.urltkn)) mask->sa = 1; } free(permstr); return 0; }
int check_response(rtsp_thread * rtsp_th) { int wait_res = rtsp_th->wait_for.res; int wait_cseq = rtsp_th->wait_for.cseq; char *wait_s_id = rtsp_th->wait_for.session_id; char Session_ID[RTSP_SESSION_ID_LEN]; char *str_pos, *content; int CSeq; int opcode = 0; if ((content = strchr(rtsp_th->in_buffer.data, '\n')) == NULL) { nms_printf(NMSML_ERR, "ERROR: CANNOT find end of line in server response.\n"); return -1; } if ((str_pos = strcasestr(content, "CSeq")) == NULL) { nms_printf(NMSML_ERR, "ERROR: CANNOT find CSeq number in server response.\n"); return -1; } str_pos += 5; while ((*(str_pos) == ' ') || (*(str_pos) == ':')) str_pos++; sscanf(str_pos, "%d", &CSeq); switch (wait_res) { case RTSP_GET_RESPONSE: if (CSeq == 1) opcode = RTSP_GET_RESPONSE; break; case RTSP_SETUP_RESPONSE: if (CSeq == wait_cseq) opcode = RTSP_SETUP_RESPONSE; break; default: if ((str_pos = strcasestr(content, "Session")) != NULL) { str_pos += 7; if (get_session_str(Session_ID, str_pos)) { nms_printf(NMSML_ERR, "ERROR: CANNOT get SessionID\n"); break; } if (strcmp(Session_ID, wait_s_id)) { nms_printf(NMSML_ERR, "Unexpected SessionID\n"); break; } } if (CSeq == wait_cseq) opcode = wait_res; break; } nms_printf(NMSML_DBG2, "Opcode Set to %d\n", opcode); return opcode; }
// private functions static int mpa_sync(uint8_t ** data, size_t * data_len /*, mpa_frm *mpa */ ) { #if 0 // ID3 tag check not useful int ret; if (!mpa->probed) { /*look if ID3 tag is present */ if (!memcmp(*data, "ID3", 3)) { // ID3 tag present id3v2_hdr id3hdr; // fnc_log(FNC_LOG_DEBUG, "ID3v2 tag present in %s\n", i_stream->name); memcpy(&id3hdr, *data, 4); // if ( (ret = istream_read(ID3v2_HDRLEN - 4, &id3hdr.rev, i_stream)) != ID3v2_HDRLEN - 4 ) if ((ret = mpa_read(ID3v2_HDRLEN - 4, &id3hdr.rev, in)) != ID3v2_HDRLEN - 4) return (ret < 0) ? ERR_PARSE : ERR_EOF; // if ( (ret=mpa_read_id3v2(&id3hdr, i_stream, mpa)) ) if ((ret = mpa_read_id3v2(&id3hdr, in, mpa))) return ret; // if ( (ret=istream_read(4, *data, i_stream)) != 4 ) if ((ret = mpa_read(4, *data, in)) != 4) return (ret < 0) ? ERR_PARSE : ERR_EOF; } } #endif for (; !MPA_IS_SYNC(*data) && (*data_len >= 4); (*data)++, (*data_len)--) nms_printf(NMSML_DBG3, "[MPA] sync: %X%X%X%X\n", data[0], data[1], data[2], data[3]); return (*data_len >= 4) ? 0 /*sync found */ : 1 /*sync not found */ ; }
rtsp_session *rtsp_sess_create(char *urlname, char *content_base) { rtsp_session *rtsp_s; if ((rtsp_s = (rtsp_session *) malloc(sizeof(rtsp_session))) == NULL) { nms_printf(NMSML_FATAL, "rtsp_sess_create: Cannot allocate memory.\n"); return NULL; } if (content_base == NULL) { rtsp_s->content_base = NULL; rtsp_s->pathname = urlname; } else { /* shawill: using strdup insted if ((rtsp_s->pathname=rtsp_s->content_base=(char *)malloc(strlen(content_base)+1))==NULL) { nms_printf(NMSML_FATAL, "Cannot allocate memory!\n"); return NULL; } strcpy(rtsp_s->content_base,content_base); */ if (! (rtsp_s->pathname = rtsp_s->content_base = strdup(content_base))) return NULL; rtsp_s->pathname += strlen(content_base); } rtsp_s->Session_ID[0] = '\0'; rtsp_s->CSeq = 1; rtsp_s->media_queue = NULL; rtsp_s->next = NULL; rtsp_s->info = NULL; return rtsp_s; }
static int single_parse(rtp_vorbis * vorb, rtp_pkt * pkt, rtp_frame * fr, rtp_buff * config, rtp_ssrc * ssrc) { uint8_t * this_pkt = RTP_PKT_DATA(pkt) + vorb->offset; unsigned len = nms_consume_BE2(&this_pkt); if (vorb->id != RTP_XIPH_ID(pkt) && //not the current id // !cfg_cache_find(vorb,RTP_XIPH_ID(pkt)) || //XXX (RTP_XIPH_T(pkt) != 1) //not a config packet ) { nms_printf(NMSML_ERR, "Id %0x unknown, expected %0x\n", (unsigned)RTP_XIPH_ID(pkt), (unsigned)vorb->id); return RTP_PARSE_ERROR; } fr->data = vorb->buf = realloc(vorb->buf, len); fr->len = vorb->len = len; memcpy(fr->data, this_pkt, fr->len); vorb->pkts--; if (vorb->pkts == 0) { rtp_rm_pkt(ssrc); } if (RTP_XIPH_T(pkt) == 1) return -1; //cfg_fixup(vorb, fr, config, RTP_XIPH_ID(pkt)); else { config->data = vorb->conf[0].conf; config->len = vorb->conf[0].len; } return 0; }
/** * Sends the Bye packet. Actually it does nothing * @param rtp_sess The session for which to send the bye packet * @return 0 */ int rtcp_send_bye(rtp_session * rtp_sess) { // TODO: really send bye packet nms_printf(NMSML_DBG1, "SRRC %d: sending RTCP Bye. Warning! Not yet implemented!", rtp_sess->local_ssrc); return 0; }
/** * Creates a copy of an nms_sockaddr structure */ int nms_sockaddr_dup(nms_sockaddr * dst, nms_sockaddr * src) { if (!(dst->addr = malloc(src->addr_len))) return -nms_printf(NMSML_FATAL, "Cannot allocate memory\n"); memcpy(dst->addr, src->addr, src->addr_len); dst->addr_len = src->addr_len; return 0; }
/** * BYE packet handler, when rtcp layer gets a bye packet * it signals it to the rtp layer reporting the end * of stream. * @param ssrc The SSRC for which the packet was received * @param pkt The packet itself * @return 0 */ int rtcp_parse_bye(rtp_ssrc * ssrc, rtcp_pkt * pkt) { rtsp_thread * rtsp_t; int i; for (i = 0; i < pkt->common.count; i++) nms_printf(NMSML_DBG3, "Received BYE from SSRC: %u\n", pkt->r.bye.src[i]); rtsp_t = ssrc->rtp_sess->owner; rtsp_t->rtp_th->run = 0; return 0; }
static int mpa_uninit_parser(rtp_ssrc * stm_src, unsigned pt) { rtp_mpa *mpa_priv = stm_src->privs[pt]; if (mpa_priv) { nms_printf(NMSML_DBG2, "[rtp_mpa] freeing private resources...\n"); free(mpa_priv->data); free(mpa_priv); } return 0; }
rtsp_session *rtsp_sess_dup(rtsp_session * curr_rtsp_s) { rtsp_session *new_rtsp_s; if ((new_rtsp_s = (rtsp_session *) malloc(sizeof(rtsp_session))) == NULL) { nms_printf(NMSML_FATAL, "Cannot allocate memory.\n"); return NULL; } memcpy(new_rtsp_s, curr_rtsp_s, sizeof(rtsp_session)); new_rtsp_s->Session_ID[0] = '\0'; new_rtsp_s->next = NULL; return new_rtsp_s; }
// debug function to diplay MPA header information static void mpa_info(mpa_frm * mpa) { switch (mpa->id) { case MPA_MPEG_1: nms_printf(NMSML_DBG3, "[MPA] MPEG1\n"); break; case MPA_MPEG_2: nms_printf(NMSML_DBG3, "[MPA] MPEG2\n"); break; case MPA_MPEG_2_5: nms_printf(NMSML_DBG3, "[MPA] MPEG2.5\n"); break; default: nms_printf(NMSML_DBG3, "[MPA] MPEG reserved (bad)\n"); return; break; } switch (mpa->layer) { case MPA_LAYER_I: nms_printf(NMSML_DBG3, "[MPA] Layer I\n"); break; case MPA_LAYER_II: nms_printf(NMSML_DBG3, "[MPA] Layer II\n"); break; case MPA_LAYER_III: nms_printf(NMSML_DBG3, "[MPA] Layer III\n"); break; default: nms_printf(NMSML_DBG3, "[MPA] Layer reserved (bad)\n"); return; break; } nms_printf(NMSML_DBG3, "[MPA] bitrate: %d; sample rate: %3.0f; pkt_len: %d\n", mpa->bit_rate, mpa->sample_rate, mpa->frm_len); }
int issdplicense(char *sdp_a) { unsigned int i; // shawill: sizeof(nms_cc_licenses)/sizeof(*nms_cc_licenses) == number of couples name-description present for (i = 0; i < sizeof(nms_cc_licenses) / sizeof(*nms_cc_licenses); i++) { if (!strncasecmp (sdp_a, nms_cc_licenses[i][CC_ATTR_NAME], strlen(nms_cc_licenses[i][CC_ATTR_NAME]))) { nms_printf(NMSML_DBG1, "found valid cc field in SDP description (%s - %s)\n", nms_cc_licenses[i][CC_ATTR_NAME], nms_cc_licenses[i][CC_ATTR_DESCR]); return 1; } } return 0; }
int remove_pkt(rtsp_thread * rtsp_th) { char *buff = NULL; size_t new_size = rtsp_th->in_buffer.size - rtsp_th->in_buffer.first_pkt_size; if (new_size) { if ((buff = malloc(new_size)) == NULL) return nms_printf(NMSML_FATAL, "remove_pkt: Cannot allocate memory!" " (%d bytes)\n", new_size); memcpy(buff, rtsp_th->in_buffer.data + rtsp_th->in_buffer.first_pkt_size, rtsp_th->in_buffer.size - rtsp_th->in_buffer.first_pkt_size); } else buff = NULL; free(rtsp_th->in_buffer.data); rtsp_th->in_buffer.data = buff; rtsp_th->in_buffer.size -= rtsp_th->in_buffer.first_pkt_size; rtsp_th->in_buffer.first_pkt_size = 0; return 0; }
int set_rtsp_media(rtsp_thread * rtsp_th) { rtsp_session *curr_rtsp_s = rtsp_th->rtsp_queue; rtsp_medium *curr_rtsp_m = NULL; sdp_medium_info *sdp_m, *sdp_m_prev; sdp_attr *sdp_attr; char *tkn, *ch; uint8_t pt; int error=0; switch (rtsp_th->descr_fmt) { case DESCRIPTION_SDP_FORMAT: //erasing unknown media sdp_m = curr_rtsp_s->info->media_info_queue; sdp_m_prev = NULL; while (sdp_m) { error = 0; for (sdp_attr = sdp_m->attr_list; sdp_attr; sdp_attr = sdp_attr->next) { if (!strncasecmp(sdp_attr->name, "rtpmap", 6)) { tkn = sdp_attr->value; while ((*tkn == ' ') || (*tkn == ':')) tkn++; strtoul(tkn, &tkn, 10); while (*tkn == ' ') tkn++; if (!(ch = strchr(tkn, '/'))) { nms_printf(NMSML_WARN, "Invalid field rtpmap.\n"); error++; } *ch = '\0'; if (rtp_parser_check(tkn)) { nms_printf(NMSML_WARN, "Ignoring unsupported media" "type: %s.\n", tkn); error++; } *ch = '/'; } } if (error) { if (!sdp_m_prev) { curr_rtsp_s->info->media_info_queue = sdp_m->next; sdp_medium_destroy(sdp_m); sdp_m = curr_rtsp_s->info->media_info_queue; } else { sdp_m_prev->next = sdp_m->next; sdp_medium_destroy(sdp_m); sdp_m = sdp_m_prev->next; } } else { sdp_m_prev = sdp_m; sdp_m = sdp_m->next; } } if (!curr_rtsp_s->info->media_info_queue) { nms_printf(NMSML_ERR, "No known medium found.\n"); return 1; } for (sdp_m = curr_rtsp_s->info->media_info_queue; sdp_m; sdp_m = sdp_m->next) { if (curr_rtsp_m == NULL) { /* first medium */ if ((curr_rtsp_s->media_queue = curr_rtsp_m = rtsp_med_create(rtsp_th)) == NULL) return 1; } else if (rtsp_th->type == CONTAINER) { /* media in the same session */ if ((curr_rtsp_m->next = rtsp_med_create(rtsp_th)) == NULL) return 1; curr_rtsp_m->rtp_sess->next = curr_rtsp_m->next->rtp_sess; curr_rtsp_m = curr_rtsp_m->next; } else if (rtsp_th->type == M_ON_DEMAND) { /* one medium for each session */ if ((curr_rtsp_s->next = rtsp_sess_dup(curr_rtsp_s)) == NULL) return 1; curr_rtsp_s = curr_rtsp_s->next; if ((curr_rtsp_s->media_queue = rtsp_med_create(rtsp_th)) == NULL) return 1; curr_rtsp_m->rtp_sess->next = curr_rtsp_s->media_queue->rtp_sess; curr_rtsp_m = curr_rtsp_s->media_queue; } curr_rtsp_m->medium_info = sdp_m; // setup rtp format list for current media for (tkn = sdp_m->fmts; *tkn && !(!(pt = strtoul(tkn, &ch, 10)) && ch == tkn); tkn = ch) { switch (sdp_m->media_type) { case 'A': if (rtp_announce_pt(curr_rtsp_m->rtp_sess, pt, AU)) return 1; break; case 'V': if (rtp_announce_pt(curr_rtsp_m->rtp_sess, pt, VI)) return 1; break; default: // not recognized if (rtp_announce_pt(curr_rtsp_m->rtp_sess, pt, NA)) return 1; break; } } for (sdp_attr = sdp_m->attr_list; sdp_attr; sdp_attr = sdp_attr->next) { if (!strncasecmp(sdp_attr->name, "control", 7)) { tkn = sdp_attr->value; while ((*tkn == ' ') || (*tkn == ':')) tkn++; curr_rtsp_m->filename = tkn; } else if (!strncasecmp(sdp_attr->name, "rtpmap", 6)) { /* We assume the string in the format: * rtpmap:PaloadType EncodingName/ClockRate[/Channels] */ tkn = sdp_attr->value; // skip spaces and colon (we should not do this!) while ((*tkn == ' ') || (*tkn == ':')) tkn++; if (((pt = strtoul(tkn, &tkn, 10)) >= 96) && (pt <= 127)) { while (*tkn == ' ') tkn++; if (!(ch = strchr(tkn, '/'))) { nms_printf(NMSML_WARN, "Invalid field rtpmap.\n"); break; } *ch = '\0'; if (rtp_dynpt_reg (curr_rtsp_m->rtp_sess, pt, tkn)) return 1; switch (sdp_m->media_type) { case 'A': sscanf(ch + 1, "%u/%c", &curr_rtsp_m->rtp_sess->ptdefs[pt]->rate, &RTP_AUDIO(curr_rtsp_m->rtp_sess->ptdefs[pt])-> channels); break; case 'V': sscanf(ch + 1, "%u", &curr_rtsp_m->rtp_sess->ptdefs[pt]->rate); break; default: // not recognized break; } *ch = '/'; tkn = ++ch; } else { // shawill: should be an error or a warning? nms_printf(NMSML_WARN, "Warning: rtpmap attribute is trying to set a" "non-dynamic payload type: not permitted\n"); } } else if (!strncasecmp(sdp_attr->name, "fmtp", 4)) { /* We assume the string in the format: * fmtp:PaloadType <format specific parameters> */ tkn = sdp_attr->value; // 4 == strlen("fmtp") // skip spaces and colon (we should not do this!) while ((*tkn == ' ') || (*tkn == ':')) tkn++; if ((pt = strtoul(tkn, &tkn, 10)) <= 127) { while (*tkn == ' ') tkn++; rtp_pt_attr_add(curr_rtsp_m->rtp_sess->ptdefs, pt, tkn); } else { // shawill: should be an error or a warning? nms_printf(NMSML_WARN, "Warning: fmtp attribute is trying to set an" "out of bounds payload type: not permitted\n"); } /* dirty keyword from old fenice used for dinamic * payload change - TO BE REMOVED */ } else if (!strncasecmp(sdp_attr->name, "med", 3)) { sdp_medium_info m_info; /* We assume the string in the format: * med:sdp-like m= field */ tkn = sdp_attr->value; // 3 == strlen("med") // skip spaces and colon (we should not do this!) while ((*tkn == ' ') || (*tkn == ':')) tkn++; if (sdp_parse_m_descr(&m_info, tkn)) { nms_printf(NMSML_ERR, "malformed a=med: from fenice\n"); return 1; } // check if everything is correct if (!(pt = strtoul(m_info.fmts, &ch, 10)) && ch == m_info.fmts) { nms_printf(NMSML_ERR, "Could not determine pt value in a=med: string" " from fenice\n"); return 1; } switch (sdp_m->media_type) { case 'A': if (strncasecmp (tkn, "audio ", 6)) { nms_printf(NMSML_ERR, "a=med; attribute defined a different media" " type than the original\n"); return 1; } if (rtp_announce_pt (curr_rtsp_m->rtp_sess, pt, AU)) return 1; break; case 'V': if (strncasecmp (tkn, "video ", 6)) { nms_printf(NMSML_ERR, "a=med; attribute defined a different media" " type than the original\n"); return 1; } if (rtp_announce_pt (curr_rtsp_m->rtp_sess, pt, VI)) return 1; break; default: // not recognized if (rtp_announce_pt (curr_rtsp_m->rtp_sess, pt, NA)) return 1; break; } } } } break; case DESCRIPTION_MH_FORMAT: /* not yet implemented */ // break; default: nms_printf(NMSML_ERR, "Unknown decription format.\n"); return 1; break; } return 0; }
int sdp_parse_m_descr(sdp_medium_info * m_info, char *m_descr) { char *tkn, *endtkn; if (!(tkn = strchr(m_descr, ' '))) return nms_printf(NMSML_ERR, "SDP Media description string not valid: (m=%s)\n", m_descr); *tkn = '\0'; // parse media type if (!strcmp(m_descr, "video")) m_info->media_type = 'V'; else if (!strcmp(m_descr, "audio")) m_info->media_type = 'A'; else if (!strcmp(m_descr, "application")) m_info->media_type = 'P'; else if (!strcmp(m_descr, "data")) m_info->media_type = 'D'; else if (!strcmp(m_descr, "control")) m_info->media_type = 'C'; *tkn = ' '; // parse port and number of ports m_info->port = strtol(tkn, &endtkn, 10); if (tkn == endtkn) return nms_printf(NMSML_ERR, "SDP Media description string not valid: (m=%s)\n" "Could not find port field\n", m_descr); tkn = endtkn; // + 1; if (*endtkn == '/') { m_info->n_ports = strtol(tkn + 1, &endtkn, 10); tkn = endtkn; // + 1; } else m_info->n_ports = 1; for (; *tkn == ' '; tkn++); // skip spaces if (!(*tkn)) return nms_printf(NMSML_ERR, "SDP Media description string not valid: (m=%s)\n" "Could not find transport field\n", m_descr); // parse transport protocol if (!(endtkn = strchr(tkn, ' '))) return nms_printf(NMSML_ERR, "SDP Media description string not valid: (m=%s)\n" "Description terminates whithout <fmt list>\n", m_descr); *endtkn = '\0'; strncpy(m_info->transport, tkn, 7); m_info->transport[7] = '\0'; *endtkn = ' '; tkn = endtkn + 1; // fmt list: here we expect to store payload types for (; *tkn == ' '; tkn++); // skip spaces m_info->fmts = tkn; return 0; }
int rtsp_recv(rtsp_thread * rtsp_th) { int n = -1, m = 0; char buffer[RTSP_BUFFERSIZE]; #ifdef ENABLE_SCTP nms_rtsp_interleaved *p; struct sctp_sndrcvinfo sinfo; #endif memset(buffer, '\0', RTSP_BUFFERSIZE); switch(rtsp_th->transport.sock.socktype) { case TCP: n = nmst_read(&rtsp_th->transport, buffer, RTSP_BUFFERSIZE, NULL); break; #ifdef ENABLE_SCTP case SCTP: memset(&sinfo, 0, sizeof(sinfo)); n = nmst_read(&rtsp_th->transport, buffer, RTSP_BUFFERSIZE, &sinfo); m = sinfo.sinfo_stream; break; #endif default: break; } if (n == 0) { return 0; } if (n < 0) { nms_printf(NMSML_ERR, "Could not read from RTSP socket\n"); return n; } if (rtsp_th->transport.sock.socktype == TCP || (rtsp_th->transport.sock.socktype == SCTP && m==0)) { if ((rtsp_th->in_buffer.size) == 0) { if ((rtsp_th->in_buffer.data = (char *) calloc(1, n + 1)) == NULL) return nms_printf(NMSML_FATAL, "Cannot alloc memory space for received RTSP data\n"); memcpy(rtsp_th->in_buffer.data, buffer, n); } else { if ((rtsp_th->in_buffer.data = (char *) realloc(rtsp_th->in_buffer.data, n + rtsp_th->in_buffer.size + 1)) == NULL) return nms_printf(NMSML_FATAL, "Cannot alloc memory space for received RTSP data\n"); memcpy(rtsp_th->in_buffer.data + rtsp_th->in_buffer.size, buffer, n); } rtsp_th->in_buffer.size += n; rtsp_th->in_buffer.data[rtsp_th->in_buffer.size] = '\0'; } else /* if (rtsp_th->transport.sock.socktype == SCTP && m!=0) */ { #ifdef ENABLE_SCTP for (p = rtsp_th->interleaved; p && !((p->proto.sctp.rtp_st == m) || (p->proto.sctp.rtcp_st == m)); p = p->next); if (p) { if (p->proto.sctp.rtp_st == m) { nms_printf(NMSML_DBG2, "Interleaved RTP data (%u bytes: channel %d -> sd %d)\n", n, m, p->rtp_fd); send(p->rtp_fd, buffer, n, MSG_EOR); } else { nms_printf(NMSML_DBG2, "Interleaved RTCP data (%u bytes: channel %d -> sd %d)\n", n, m, p->rtcp_fd); send(p->rtcp_fd, buffer, n, MSG_EOR); } } #endif } return n; }
/** * @brief scan status code of an RTSP reply * * @param status_line the status line in the reply * @return reply status code or -1 on error */ int check_status(char *status_line, rtsp_thread * rtsp_th) { char ver[32]; unsigned short res_state; char *reason_phrase; char *location = NULL; // string tokenizers char *tkn, *prev_tkn, *step = NULL; if (sscanf(status_line, "%31s %hu ", ver, &res_state) < 2) { nms_printf(NMSML_ERR, "invalid Status-Line in DESCRIBE Response\n"); return -1; } reason_phrase = strchr(strchr(status_line, ' ') + 1, ' ') + 1; rtsp_th->response_id = res_state; if (RTSP_IS_SUCCESS(res_state)) return res_state; else if (RTSP_IS_REDIRECT(res_state)) { nms_printf(NMSML_NORM, "WARNING: Redirection. reply was: %hu %s\n", res_state, reason_phrase); switch (res_state) { case RTSP_FOUND: if ((prev_tkn = strtok_r(rtsp_th->in_buffer.data + strlen(status_line) + 1, "\n", &step)) == NULL) { nms_printf(NMSML_ERR, "Could not find \"Location\" so..." " Where I'll redirect you?\n"); return -1; } while (((tkn = strtok_r(NULL, "\n", &step)) != NULL) && ((tkn - prev_tkn) > 1)) { if (((tkn - prev_tkn) == 2) && (*prev_tkn == '\r')) break; if (!strncasecmp(prev_tkn, "Location", 8)) { prev_tkn += 8; while ((*(prev_tkn) == ' ') || (*(prev_tkn) == ':')) prev_tkn++; location = strdup(prev_tkn); // sscanf(prev_tkn,"%d",&location); } prev_tkn = tkn; } if (location) { nms_printf(NMSML_NORM, "Redirecting to %s\n", location); rtsp_open((rtsp_ctrl*)rtsp_th, location); } else return -nms_printf(NMSML_ERR, "No location string\n"); } } else if (RTSP_IS_CLIENT_ERROR(res_state)) nms_printf(NMSML_ERR, "Client error. Reply was: %hu %s\n", res_state, reason_phrase); else if (RTSP_IS_SERVER_ERROR(res_state)) nms_printf(NMSML_ERR, "Server error. Reply was: %hu %s\n", res_state, reason_phrase); return -1; }
static int mpa_parse(rtp_ssrc * stm_src, rtp_frame * fr, rtp_buff * config) { rtp_mpa *mpa_priv; rtp_pkt *pkt; size_t pkt_len; // size of RTP packet, rtp header included. mpa_frm mpa; uint8_t *mpa_data; if (!fr) return RTP_IN_PRM_ERR; mpa_priv = stm_src->privs[fr->pt]; // XXX should we check if payload/mime-type are compatible with parser? if (!(pkt = rtp_get_pkt(stm_src, &pkt_len))) return RTP_BUFF_EMPTY; // discard pkt if it's fragmented and the first fragment was lost while (RTP_MPA_PKT(pkt)->frag_offset) { rtp_rm_pkt(stm_src); if (!(pkt = rtp_get_pkt(stm_src, &pkt_len))) return RTP_BUFF_EMPTY; else if (RTP_PKT_PT(pkt) != fr->pt) return RTP_PARSE_ERROR; } mpa_data = RTP_MPA_PKT(pkt)->data; nms_printf(NMSML_DBG3, "--- fr->len: %d-%d\n", pkt_len, RTP_PAYLOAD_SIZE(pkt, pkt_len)); pkt_len = RTP_MPA_DATA_LEN(pkt, pkt_len); // now pkt_len is only the payload len (excluded mpa subheader) nms_printf(NMSML_DBG3, "--- fr->len: %d\n", pkt_len); if (mpa_sync(&mpa_data, &pkt_len)) return RTP_PARSE_ERROR; if (mpa_decode_header(mpa_data, &mpa)) return RTP_PARSE_ERROR; /* XXX if the frame is not fragmented we could use directly the data contained in bufferpool * instead of memcpy the frame in a newly allocated space */ // init private struct if this is the first time we're called if (!mpa_priv) { nms_printf(NMSML_DBG3, "[rtp_mpa] allocating new private struct..."); if (! (stm_src->privs[fr->pt] = mpa_priv = malloc(sizeof(rtp_mpa)))) return RTP_ERRALLOC; mpa_priv->data_size = max(DEFAULT_MPA_DATA_FRAME, mpa.frm_len); if (!(mpa_priv->data = malloc(mpa_priv->data_size))) return RTP_ERRALLOC; nms_printf(NMSML_DBG3, "done\n"); } else if ((RTP_MPA_FRAG_OFFSET(pkt) + pkt_len) > mpa_priv->data_size) { nms_printf(NMSML_DBG3, "[rtp_mpa] reallocating data..."); mpa_priv->data_size += max(DEFAULT_MPA_DATA_FRAME, pkt_len); if (!(mpa_priv->data = realloc(mpa_priv->data, mpa_priv->data_size))) return RTP_ERRALLOC; nms_printf(NMSML_DBG3, "done\n"); } fr->data = mpa_priv->data; for (fr->len = 0; pkt && (fr->len < mpa.frm_len) && (fr->timestamp == RTP_PKT_TS(pkt)); fr->len += pkt_len, rtp_rm_pkt(stm_src), (pkt = rtp_get_pkt(stm_src, &pkt_len)), pkt_len = RTP_MPA_DATA_LEN(pkt, pkt_len)) { // pkt consistency checks if (RTP_MPA_FRAG_OFFSET(pkt) + pkt_len <= mpa_priv->data_size) { nms_printf(NMSML_DBG3, "copying %d byte of data to offset: %d\n", pkt_len, RTP_MPA_FRAG_OFFSET(pkt)); memcpy(fr->data + RTP_MPA_FRAG_OFFSET(pkt), mpa_data, pkt_len); } } nms_printf(NMSML_DBG3, "fr->len: %d\n", fr->len); return RTP_FILL_OK; }