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