/** Parse header section */ APT_DECLARE(apt_bool_t) apt_header_section_parse(apt_header_section_t *header, apt_text_stream_t *stream, apr_pool_t *pool) { apt_header_field_t *header_field; apt_bool_t result = FALSE; do { header_field = apt_header_field_parse(stream,pool); if(header_field) { if(apt_string_is_empty(&header_field->name) == FALSE) { /* normal header */ apt_header_section_field_add(header,header_field); } else { /* empty header => exit */ result = TRUE; break; } } else { /* malformed header => skip to the next one */ } } while(apt_text_is_eos(stream) == FALSE); return result; }
/** Parse RTSP header */ RTSP_DECLARE(apt_bool_t) rtsp_header_parse(rtsp_header_t *header, apt_text_stream_t *text_stream, apr_pool_t *pool) { apt_pair_t pair; apt_bool_t result = FALSE; do { if(apt_text_header_read(text_stream,&pair) == TRUE) { if(pair.name.length) { /* parse header_field (name/value) */ rtsp_header_field_id id = apt_string_table_id_find(rtsp_header_string_table,RTSP_HEADER_FIELD_COUNT,&pair.name); if(id < RTSP_HEADER_FIELD_COUNT) { if(rtsp_header_field_parse(header,id,&pair.value,pool) == TRUE) { rtsp_header_property_add(&header->property_set,id); } } } else { /* empty header -> exit */ result = TRUE; break; } } } while(apt_text_is_eos(text_stream) == FALSE); return result; }
/** Parse MRCP message-header */ MRCP_DECLARE(apt_bool_t) mrcp_message_header_parse(mrcp_message_header_t *message_header, apt_text_stream_t *text_stream, apr_pool_t *pool) { apt_pair_t pair; apt_bool_t result = FALSE; mrcp_header_allocate(&message_header->generic_header_accessor,pool); mrcp_header_allocate(&message_header->resource_header_accessor,pool); do { if(apt_text_header_read(text_stream,&pair) == TRUE) { if(pair.name.length) { /* normal header */ if(mrcp_header_parse(&message_header->resource_header_accessor,&pair,pool) != TRUE) { if(mrcp_header_parse(&message_header->generic_header_accessor,&pair,pool) != TRUE) { /* unknown MRCP header */ } } } else { /* empty header -> exit */ result = TRUE; break; } } else { /* malformed header, skip to the next one */ } } while(apt_text_is_eos(text_stream) == FALSE); return result; }
/* Receive MRCP message through TCP/MRCPv2 connection */ static apt_bool_t mrcp_client_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) { mrcp_connection_agent_t *agent = obj; mrcp_connection_t *connection = descriptor->client_data; apr_status_t status; apr_size_t offset; apr_size_t length; apt_text_stream_t *stream; mrcp_message_t *message; apt_message_status_e msg_status; if(!connection || !connection->sock) { return FALSE; } stream = &connection->rx_stream; /* calculate offset remaining from the previous receive / if any */ offset = stream->pos - stream->text.buf; /* calculate available length */ length = connection->rx_buffer_size - offset; status = apr_socket_recv(connection->sock,stream->pos,&length); if(status == APR_EOF || length == 0) { apt_pollset_t *pollset = apt_poller_task_pollset_get(agent->task); apt_log(APT_LOG_MARK,APT_PRIO_INFO,"TCP/MRCPv2 Peer Disconnected %s",connection->id); if(pollset) { apt_pollset_remove(pollset,&connection->sock_pfd); } apr_socket_close(connection->sock); connection->sock = NULL; mrcp_client_agent_disconnect_raise(agent,connection); return TRUE; } /* calculate actual length of the stream */ stream->text.length = offset + length; stream->pos[length] = '\0'; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Receive MRCPv2 Stream %s [%"APR_SIZE_T_FMT" bytes]\n%.*s", connection->id, length, connection->verbose == TRUE ? length : 0, stream->pos); /* reset pos */ apt_text_stream_reset(stream); do { msg_status = mrcp_parser_run(connection->parser,stream,&message); if(mrcp_client_message_handler(connection,message,msg_status) == FALSE) { return FALSE; } } while(apt_text_is_eos(stream) == FALSE); /* scroll remaining stream */ apt_text_stream_scroll(stream); return TRUE; }
static apt_message_status_e apt_message_generator_break(apt_message_generator_t *generator, apt_text_stream_t *stream) { /* failed to generate message */ if(apt_text_is_eos(stream) == TRUE) { /* end of stream reached */ return APT_MESSAGE_STATUS_INCOMPLETE; } /* error case */ return APT_MESSAGE_STATUS_INVALID; }
static apt_bool_t test_file_process(apt_test_suite_t *suite, const char *file_path) { apr_file_t *file; char buffer[500]; apt_text_stream_t stream; rtsp_parser_t *parser; rtsp_generator_t *generator; apr_size_t length; apr_size_t offset; rtsp_message_t *message; apt_message_status_e msg_status; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Open File [%s]",file_path); if(apr_file_open(&file,file_path,APR_FOPEN_READ | APR_FOPEN_BINARY,APR_OS_DEFAULT,suite->pool) != APR_SUCCESS) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Open File"); return FALSE; } parser = rtsp_parser_create(suite->pool); generator = rtsp_generator_create(suite->pool); apt_text_stream_init(&stream,buffer,sizeof(buffer)-1); do { /* calculate offset remaining from the previous receive / if any */ offset = stream.pos - stream.text.buf; /* calculate available length */ length = sizeof(buffer) - 1 - offset; if(apr_file_read(file,stream.pos,&length) != APR_SUCCESS) { break; } /* calculate actual length of the stream */ stream.text.length = offset + length; stream.pos[length] = '\0'; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parse RTSP Stream [%"APR_SIZE_T_FMT" bytes]\n%s",length,stream.pos); /* reset pos */ apt_text_stream_reset(&stream); do { msg_status = rtsp_parser_run(parser,&stream,&message); rtsp_message_handler(generator,message,msg_status); } while(apt_text_is_eos(&stream) == FALSE); /* scroll remaining stream */ apt_text_stream_scroll(&stream); } while(apr_file_eof(file) != APR_EOF); apr_file_close(file); return TRUE; }
/* Receive RTSP message through RTSP connection */ static apt_bool_t rtsp_server_poller_signal_process(void *obj, const apr_pollfd_t *descriptor) { rtsp_server_t *server = obj; rtsp_server_connection_t *rtsp_connection = descriptor->client_data; apr_status_t status; apr_size_t offset; apr_size_t length; apt_text_stream_t *stream; rtsp_message_t *message; apt_message_status_e msg_status; if(descriptor->desc.s == server->listen_sock) { apt_log(RTSP_LOG_MARK,APT_PRIO_DEBUG,"Accept Connection"); return rtsp_server_connection_accept(server); } if(!rtsp_connection || !rtsp_connection->sock) { return FALSE; } stream = &rtsp_connection->rx_stream; /* calculate offset remaining from the previous receive / if any */ offset = stream->pos - stream->text.buf; /* calculate available length */ length = sizeof(rtsp_connection->rx_buffer) - 1 - offset; status = apr_socket_recv(rtsp_connection->sock,stream->pos,&length); if(status == APR_EOF || length == 0) { apt_log(RTSP_LOG_MARK,APT_PRIO_INFO,"RTSP Peer Disconnected %s",rtsp_connection->id); return rtsp_server_connection_close(server,rtsp_connection); } /* calculate actual length of the stream */ stream->text.length = offset + length; stream->pos[length] = '\0'; apt_log(RTSP_LOG_MARK,APT_PRIO_INFO,"Receive RTSP Data %s [%"APR_SIZE_T_FMT" bytes]\n%s", rtsp_connection->id, length, stream->pos); /* reset pos */ apt_text_stream_reset(stream); do { msg_status = rtsp_parser_run(rtsp_connection->parser,stream,&message); rtsp_server_message_handler(rtsp_connection,message,msg_status); } while(apt_text_is_eos(stream) == FALSE); /* scroll remaining stream */ apt_text_stream_scroll(stream); return TRUE; }
static mrcp_stream_result_e mrcp_generator_break(mrcp_generator_t *generator, apt_text_stream_t *stream) { /* failed to generate either start-line or header */ if(apt_text_is_eos(stream) == TRUE) { /* end of stream reached, rewind/restore stream */ stream->pos = generator->pos; generator->result = MRCP_STREAM_MESSAGE_TRUNCATED; } else { /* error case */ generator->result = MRCP_STREAM_MESSAGE_INVALID; } return generator->result; }
static mrcp_stream_result_e mrcp_parser_break(mrcp_parser_t *parser, apt_text_stream_t *stream) { /* failed to parse either start-line or header */ if(apt_text_is_eos(stream) == TRUE) { /* end of stream reached, rewind/restore stream */ stream->pos = parser->pos; parser->result = MRCP_STREAM_MESSAGE_TRUNCATED; parser->message = NULL; } else { /* error case */ parser->result = MRCP_STREAM_MESSAGE_INVALID; } return parser->result; }
/** Walk through MRCP stream and invoke message handler for each parsed message */ MRCP_DECLARE(apt_bool_t) mrcp_stream_walk(mrcp_parser_t *parser, apt_text_stream_t *stream, mrcp_message_handler_f handler, void *obj) { mrcp_stream_result_e result; if(parser->skip_lf == TRUE) { /* skip <LF> occurred as a result of message segmentation between <CR> and <LF> */ apt_text_char_skip(stream,APT_TOKEN_LF); parser->skip_lf = FALSE; } do { result = mrcp_parser_run(parser,stream); if(result == MRCP_STREAM_MESSAGE_COMPLETE) { /* message is completely parsed */ apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Parsed MRCP Message [%lu]", stream->pos - stream->text.buf); /* invoke message handler */ handler(obj,parser->message,result); } else if(result == MRCP_STREAM_MESSAGE_TRUNCATED) { /* message is partially parsed, to be continued */ apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Truncated MRCP Message [%lu]", stream->pos - stream->text.buf); /* prepare stream for further processing */ if(apt_text_stream_scroll(stream) == TRUE) { apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Scroll MRCP Stream", stream->text.buf); } return TRUE; } else if(result == MRCP_STREAM_MESSAGE_INVALID){ /* error case */ apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse MRCP Message"); /* invoke message handler */ handler(obj,parser->message,result); /* reset stream pos */ stream->pos = stream->text.buf; return FALSE; } } while(apt_text_is_eos(stream) == FALSE); /* reset stream pos */ stream->pos = stream->text.buf; return TRUE; }
/** Parse MRCP channel-identifier */ MRCP_DECLARE(apt_bool_t) mrcp_channel_id_parse(mrcp_channel_id *channel_id, apt_text_stream_t *text_stream, apr_pool_t *pool) { apt_bool_t match = FALSE; apt_pair_t pair; do { if(apt_text_header_read(text_stream,&pair) == TRUE) { if(pair.name.length) { if(pair.value.length && strncasecmp(pair.name.buf,MRCP_CHANNEL_ID,MRCP_CHANNEL_ID_LENGTH) == 0) { match = TRUE; apt_id_resource_parse(&pair.value,'@',&channel_id->session_id,&channel_id->resource_name,pool); break; } /* skip this header, expecting channel identifier first */ } else { /* empty header */ break; } } } while(apt_text_is_eos(text_stream) == FALSE); return match; }
/** Parse message by raising corresponding event handlers */ APT_DECLARE(apt_message_status_e) apt_message_parser_run(apt_message_parser_t *parser, apt_text_stream_t *stream, void **message) { const char *pos; apt_message_status_e status = APT_MESSAGE_STATUS_INCOMPLETE; if(parser->skip_lf == TRUE) { /* skip <LF> occurred as a result of message segmentation between <CR> and <LF> */ apt_text_char_skip(stream,APT_TOKEN_LF); parser->skip_lf = FALSE; } if(message) { *message = NULL; } do { pos = stream->pos; if(parser->stage == APT_MESSAGE_STAGE_START_LINE) { if(parser->vtable->on_start(parser,&parser->context,stream,parser->pool) == FALSE) { if(apt_text_is_eos(stream) == FALSE) { status = APT_MESSAGE_STATUS_INVALID; } break; } apt_crlf_segmentation_test(parser,stream); parser->stage = APT_MESSAGE_STAGE_HEADER; } if(parser->stage == APT_MESSAGE_STAGE_HEADER) { /* read header section */ apt_bool_t res = apt_header_section_parse(parser->context.header,stream,parser->pool); if(parser->verbose == TRUE) { apr_size_t length = stream->pos - pos; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Parsed Message Header [%"APR_SIZE_T_FMT" bytes]\n%.*s", length, length, pos); } apt_crlf_segmentation_test(parser,stream); if(res == FALSE) { break; } if(parser->vtable->on_header_complete) { if(parser->vtable->on_header_complete(parser,&parser->context) == FALSE) { status = APT_MESSAGE_STATUS_INVALID; break; } } if(parser->context.body && parser->context.body->length) { apt_str_t *body = parser->context.body; parser->content_length = body->length; body->buf = apr_palloc(parser->pool,parser->content_length+1); body->buf[parser->content_length] = '\0'; body->length = 0; parser->stage = APT_MESSAGE_STAGE_BODY; } else { status = APT_MESSAGE_STATUS_COMPLETE; if(message) { *message = parser->context.message; } parser->stage = APT_MESSAGE_STAGE_START_LINE; break; } } if(parser->stage == APT_MESSAGE_STAGE_BODY) { if(apt_message_body_read(parser,stream) == FALSE) { break; } if(parser->vtable->on_body_complete) { parser->vtable->on_body_complete(parser,&parser->context); } status = APT_MESSAGE_STATUS_COMPLETE; if(message) { *message = parser->context.message; } parser->stage = APT_MESSAGE_STAGE_START_LINE; break; } } while(apt_text_is_eos(stream) == FALSE); return status; }
/** Get the next content part */ APT_DECLARE(apt_bool_t) apt_multipart_content_get(apt_multipart_content_t *multipart_content, apt_content_part_t *content_part, apt_bool_t *is_final) { apt_str_t boundary; apt_header_field_t *header_field; apt_text_stream_t *stream = &multipart_content->stream; if(!content_part || !is_final) { return FALSE; } *is_final = FALSE; apt_content_part_reset(content_part); /* skip preamble */ apt_text_skip_to_char(stream,'-'); if(apt_text_is_eos(stream) == TRUE) { return FALSE; } /* skip initial hyphens */ apt_text_chars_skip(stream,'-'); if(apt_text_is_eos(stream) == TRUE) { return FALSE; } /* read line and the boundary */ if(apt_text_line_read(stream,&boundary) == FALSE) { return FALSE; } /* remove optional trailing spaces */ while(boundary.length && boundary.buf[boundary.length-1] == APT_TOKEN_SP) boundary.length--; /* check whether this is the final boundary */ if(boundary.length >= 2) { if(boundary.buf[boundary.length-1] == '-' && boundary.buf[boundary.length-2] == '-') { /* final boundary */ boundary.length -= 2; *is_final = TRUE; } } /* compare boundaries */ if(apt_string_is_empty(&multipart_content->boundary) == TRUE) { /* no boundary was specified from user space, learn boundary from the content */ multipart_content->boundary = boundary; } else { if(apt_string_compare(&multipart_content->boundary,&boundary) == FALSE) { /* invalid boundary */ return FALSE; } } if(*is_final == TRUE) { /* final boundary => return TRUE, content remains empty */ return TRUE; } /* read header fields */ if(apt_header_section_parse(&content_part->header,stream,multipart_content->pool) == FALSE) { return FALSE; } for(header_field = APR_RING_FIRST(&content_part->header.ring); header_field != APR_RING_SENTINEL(&content_part->header.ring, apt_header_field_t, link); header_field = APR_RING_NEXT(header_field, link)) { if(strncmp(header_field->name.buf,CONTENT_LENGTH_HEADER,header_field->name.length) == 0) { content_part->length = &header_field->value; } else if(strncmp(header_field->name.buf,CONTENT_TYPE_HEADER,header_field->name.length) == 0) { content_part->type = &header_field->value; } else if(strncmp(header_field->name.buf,CONTENT_ID_HEADER,header_field->name.length) == 0) { content_part->id = &header_field->value; } } if(content_part->length && apt_string_is_empty(content_part->length) == FALSE) { apr_size_t length = atoi(content_part->length->buf); if(length + stream->pos > stream->end) { return FALSE; } /* read content */ apt_string_assign_n(&content_part->body,stream->pos,length,multipart_content->pool); stream->pos += length; } return TRUE; }
/** Get the next content part */ APT_DECLARE(apt_bool_t) apt_multipart_content_get(apt_multipart_content_t *multipart_content, apt_str_t *content_type, apt_str_t *content) { apt_str_t boundary; apt_pair_t header; apt_bool_t is_final = FALSE; apt_text_stream_t *stream = &multipart_content->stream; if(!content || !content_type) { return FALSE; } apt_string_reset(content); /* skip preamble */ apt_text_skip_to_char(stream,'-'); if(apt_text_is_eos(stream) == TRUE) { return FALSE; } /* skip initial hyphens */ apt_text_chars_skip(stream,'-'); if(apt_text_is_eos(stream) == TRUE) { return FALSE; } /* read line and the boundary */ if(apt_text_line_read(stream,&boundary) == FALSE) { return FALSE; } /* remove optional trailing spaces */ while(boundary.length && boundary.buf[boundary.length-1] == APT_TOKEN_SP) boundary.length--; /* check whether this is the final boundary */ if(boundary.length >= 2) { if(boundary.buf[boundary.length-1] == '-' && boundary.buf[boundary.length-2] == '-') { /* final boundary */ boundary.length -= 2; is_final = TRUE; } } /* compare boundaries */ if(apt_string_is_empty(&multipart_content->boundary) == TRUE) { /* no boundary was specified from user space, learn boundary from the content */ multipart_content->boundary = boundary; } else { if(apt_string_compare(&multipart_content->boundary,&boundary) == FALSE) { /* invalid boundary */ return FALSE; } } if(is_final == TRUE) { /* final boundary => return TRUE, content remains empty */ return TRUE; } /* read header fields */ do { if(apt_text_header_read(stream,&header) == TRUE) { if(header.name.length) { if(apt_string_compare(&multipart_content->content_type_header,&header.name) == TRUE) { apt_string_copy(content_type,&header.value,multipart_content->pool); } else if(apt_string_compare(&multipart_content->content_length_header,&header.name) == TRUE) { if(header.value.buf) { content->length = atol(header.value.buf); if(content->length) { content->buf = apr_palloc(multipart_content->pool,content->length+1); content->buf[content->length] = '\0'; } } } } else { /* empty header => exit */ break; } } } while(apt_text_is_eos(stream) == FALSE); if(!content->length || content->length + stream->pos > stream->end) { return FALSE; } /* read content */ memcpy(content->buf,stream->pos,content->length); stream->pos += content->length; return TRUE; }