1 /*
2  * Copyright 2008-2014 Arsen Chaloyan
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Id: mrcp_message.c 2136 2014-07-04 06:33:36Z achaloyan@gmail.com $
17  */
18 
19 #include "mrcp_message.h"
20 #include "mrcp_generic_header.h"
21 #include "mrcp_resource.h"
22 #include "apt_text_message.h"
23 #include "apt_log.h"
24 
25 /** Associate MRCP resource with message */
mrcp_message_resource_set_by_id(mrcp_message_t * message,const mrcp_resource_t * resource)26 static apt_bool_t mrcp_message_resource_set_by_id(mrcp_message_t *message, const mrcp_resource_t *resource)
27 {
28 	if(!resource) {
29 		return FALSE;
30 	}
31 	message->resource = resource;
32 	message->channel_id.resource_name = resource->name;
33 	mrcp_message_header_data_alloc(
34 		&message->header,
35 		mrcp_generic_header_vtable_get(message->start_line.version),
36 		resource->get_resource_header_vtable(message->start_line.version),
37 		message->pool);
38 
39 	/* associate method_name and method_id */
40 	if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
41 		const apt_str_t *name = apt_string_table_str_get(
42 			resource->get_method_str_table(message->start_line.version),
43 			resource->method_count,
44 			message->start_line.method_id);
45 		if(!name) {
46 			return FALSE;
47 		}
48 		message->start_line.method_name = *name;
49 	}
50 	else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
51 		const apt_str_t *name = apt_string_table_str_get(
52 			resource->get_event_str_table(message->start_line.version),
53 			resource->event_count,
54 			message->start_line.method_id);
55 		if(!name) {
56 			return FALSE;
57 		}
58 		message->start_line.method_name = *name;
59 	}
60 
61 	return TRUE;
62 }
63 
64 /** Associate MRCP resource specific data by resource name */
mrcp_message_resource_set(mrcp_message_t * message,const mrcp_resource_t * resource)65 MRCP_DECLARE(apt_bool_t) mrcp_message_resource_set(mrcp_message_t *message, const mrcp_resource_t *resource)
66 {
67 	if(!resource) {
68 		return FALSE;
69 	}
70 	message->resource = resource;
71 	mrcp_message_header_data_alloc(
72 		&message->header,
73 		mrcp_generic_header_vtable_get(message->start_line.version),
74 		resource->get_resource_header_vtable(message->start_line.version),
75 		message->pool);
76 
77 	/* associate method_name and method_id */
78 	if(message->start_line.message_type == MRCP_MESSAGE_TYPE_REQUEST) {
79 		message->start_line.method_id = apt_string_table_id_find(
80 			resource->get_method_str_table(message->start_line.version),
81 			resource->method_count,
82 			&message->start_line.method_name);
83 		if(message->start_line.method_id >= resource->method_count) {
84 			return FALSE;
85 		}
86 	}
87 	else if(message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
88 		message->start_line.method_id = apt_string_table_id_find(
89 			resource->get_event_str_table(message->start_line.version),
90 			resource->event_count,
91 			&message->start_line.method_name);
92 		if(message->start_line.method_id >= resource->event_count) {
93 			return FALSE;
94 		}
95 	}
96 
97 	return TRUE;
98 }
99 
100 /** Create an MRCP message */
mrcp_message_create(apr_pool_t * pool)101 MRCP_DECLARE(mrcp_message_t*) mrcp_message_create(apr_pool_t *pool)
102 {
103 	mrcp_message_t *message = apr_palloc(pool,sizeof(mrcp_message_t));
104 	mrcp_start_line_init(&message->start_line);
105 	mrcp_channel_id_init(&message->channel_id);
106 	mrcp_message_header_init(&message->header);
107 	apt_string_reset(&message->body);
108 	message->resource = NULL;
109 	message->pool = pool;
110 	return message;
111 }
112 
113 /** Create an MRCP request message */
mrcp_request_create(const mrcp_resource_t * resource,mrcp_version_e version,mrcp_method_id method_id,apr_pool_t * pool)114 MRCP_DECLARE(mrcp_message_t*) mrcp_request_create(const mrcp_resource_t *resource, mrcp_version_e version, mrcp_method_id method_id, apr_pool_t *pool)
115 {
116 	mrcp_message_t *request_message = mrcp_message_create(pool);
117 	request_message->start_line.message_type = MRCP_MESSAGE_TYPE_REQUEST;
118 	request_message->start_line.version = version;
119 	request_message->start_line.method_id = method_id;
120 	mrcp_message_resource_set_by_id(request_message,resource);
121 	return request_message;
122 }
123 
124 /** Create an MRCP response message */
mrcp_response_create(const mrcp_message_t * request_message,apr_pool_t * pool)125 MRCP_DECLARE(mrcp_message_t*) mrcp_response_create(const mrcp_message_t *request_message, apr_pool_t *pool)
126 {
127 	mrcp_message_t *response_message = mrcp_message_create(pool);
128 	response_message->start_line.message_type = MRCP_MESSAGE_TYPE_RESPONSE;
129 	response_message->start_line.request_state = MRCP_REQUEST_STATE_COMPLETE;
130 	response_message->start_line.status_code = MRCP_STATUS_CODE_SUCCESS;
131 	if(request_message) {
132 		response_message->channel_id = request_message->channel_id;
133 		response_message->start_line.request_id = request_message->start_line.request_id;
134 		response_message->start_line.version = request_message->start_line.version;
135 		response_message->start_line.method_id = request_message->start_line.method_id;
136 		response_message->start_line.method_name = request_message->start_line.method_name;
137 		mrcp_message_resource_set_by_id(response_message,request_message->resource);
138 	}
139 	return response_message;
140 }
141 
142 /** Create an MRCP event message */
mrcp_event_create(const mrcp_message_t * request_message,mrcp_method_id event_id,apr_pool_t * pool)143 MRCP_DECLARE(mrcp_message_t*) mrcp_event_create(const mrcp_message_t *request_message, mrcp_method_id event_id, apr_pool_t *pool)
144 {
145 	mrcp_message_t *event_message = mrcp_message_create(pool);
146 	event_message->start_line.message_type = MRCP_MESSAGE_TYPE_EVENT;
147 	event_message->start_line.method_id = event_id;
148 	if(request_message) {
149 		event_message->channel_id = request_message->channel_id;
150 		event_message->start_line.request_id = request_message->start_line.request_id;
151 		event_message->start_line.version = request_message->start_line.version;
152 		mrcp_message_resource_set_by_id(event_message,request_message->resource);
153 	}
154 	return event_message;
155 }
156 
157 /** Destroy MRCP message */
mrcp_message_destroy(mrcp_message_t * message)158 MRCP_DECLARE(void) mrcp_message_destroy(mrcp_message_t *message)
159 {
160 	apt_string_reset(&message->body);
161 	mrcp_message_header_destroy(&message->header);
162 }
163 
164 /** Validate MRCP message */
mrcp_message_validate(mrcp_message_t * message)165 MRCP_DECLARE(apt_bool_t) mrcp_message_validate(mrcp_message_t *message)
166 {
167 	if(message->body.length) {
168 		/* content length must be specified */
169 		mrcp_generic_header_t *generic_header = mrcp_generic_header_prepare(message);
170 		if(!generic_header) {
171 			return FALSE;
172 		}
173 		if(mrcp_generic_header_property_check(message,GENERIC_HEADER_CONTENT_LENGTH) != TRUE ||
174 		  !generic_header->content_length) {
175 			generic_header->content_length = message->body.length;
176 			mrcp_generic_header_property_add(message,GENERIC_HEADER_CONTENT_LENGTH);
177 		}
178 	}
179 
180 	return TRUE;
181 }
182 
183 /** Add MRCP generic header field by specified property (numeric identifier) */
mrcp_generic_header_property_add(mrcp_message_t * message,apr_size_t id)184 MRCP_DECLARE(apt_bool_t) mrcp_generic_header_property_add(mrcp_message_t *message, apr_size_t id)
185 {
186 	apt_header_field_t *header_field = mrcp_header_field_value_generate(
187 										&message->header.generic_header_accessor,
188 										id,
189 										FALSE,
190 										message->pool);
191 	if(!header_field) {
192 		return FALSE;
193 	}
194 	header_field->id = id;
195 	return apt_header_section_field_add(&message->header.header_section,header_field);
196 }
197 
198 /** Add only the name of MRCP generic header field specified by property (numeric identifier) */
mrcp_generic_header_name_property_add(mrcp_message_t * message,apr_size_t id)199 MRCP_DECLARE(apt_bool_t) mrcp_generic_header_name_property_add(mrcp_message_t *message, apr_size_t id)
200 {
201 	apt_header_field_t *header_field = mrcp_header_field_value_generate(
202 										&message->header.generic_header_accessor,
203 										id,
204 										TRUE,
205 										message->pool);
206 	if(!header_field) {
207 		return FALSE;
208 	}
209 	header_field->id = id;
210 	return apt_header_section_field_add(&message->header.header_section,header_field);
211 }
212 
213 /** Add MRCP resource header field by specified property (numeric identifier) */
mrcp_resource_header_property_add(mrcp_message_t * message,apr_size_t id)214 MRCP_DECLARE(apt_bool_t) mrcp_resource_header_property_add(mrcp_message_t *message, apr_size_t id)
215 {
216 	apt_header_field_t *header_field = mrcp_header_field_value_generate(
217 										&message->header.resource_header_accessor,
218 										id,
219 										FALSE,
220 										message->pool);
221 	if(!header_field) {
222 		return FALSE;
223 	}
224 	header_field->id = id + GENERIC_HEADER_COUNT;
225 	return apt_header_section_field_add(&message->header.header_section,header_field);
226 }
227 
228 /** Add only the name of MRCP resource header field specified by property (numeric identifier) */
mrcp_resource_header_name_property_add(mrcp_message_t * message,apr_size_t id)229 MRCP_DECLARE(apt_bool_t) mrcp_resource_header_name_property_add(mrcp_message_t *message, apr_size_t id)
230 {
231 	apt_header_field_t *header_field = mrcp_header_field_value_generate(
232 										&message->header.resource_header_accessor,
233 										id,
234 										TRUE,
235 										message->pool);
236 	if(!header_field) {
237 		return FALSE;
238 	}
239 	header_field->id = id + GENERIC_HEADER_COUNT;
240 	return apt_header_section_field_add(&message->header.header_section,header_field);
241 }
242 
243 /** Get the next MRCP header field */
mrcp_message_next_header_field_get(const mrcp_message_t * message,apt_header_field_t * header_field)244 MRCP_DECLARE(apt_header_field_t*) mrcp_message_next_header_field_get(const mrcp_message_t *message, apt_header_field_t *header_field)
245 {
246 	const apt_header_section_t *header_section = &message->header.header_section;
247 	if(header_field) {
248 		apt_header_field_t *next = APR_RING_NEXT(header_field,link);
249 		if(next == APR_RING_SENTINEL(&header_section->ring,apt_header_field_t,link)) {
250 			return NULL;
251 		}
252 		return next;
253 	}
254 
255 	if(APR_RING_EMPTY(&header_section->ring,apt_header_field_t,link)) {
256 		return NULL;
257 	}
258 	return APR_RING_FIRST(&header_section->ring);
259 }
260