summaryrefslogtreecommitdiff
path: root/toxav/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/msi.c')
-rw-r--r--toxav/msi.c1077
1 files changed, 451 insertions, 626 deletions
diff --git a/toxav/msi.c b/toxav/msi.c
index dca5fe1e..5140a10a 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -1,4 +1,4 @@
1/** toxmsi.c 1/** msi.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 * 4 *
@@ -34,19 +34,7 @@
34#include <stdlib.h> 34#include <stdlib.h>
35#include <stdbool.h> 35#include <stdbool.h>
36 36
37#define same(x, y) strcmp((const char*) x, (const char*) y) == 0 37#define MSI_MAXMSG_SIZE 256
38
39#define MSI_MAXMSG_SIZE 1024
40
41#define TYPE_REQUEST 1
42#define TYPE_RESPONSE 2
43
44unsigned char *VERSION_STRING = (unsigned char *)"0.3.1";
45#define VERSION_STRLEN 5
46
47#define CT_AUDIO_HEADER_VALUE "AUDIO"
48#define CT_VIDEO_HEADER_VALUE "VIDEO"
49
50 38
51/* Define default timeout for a request. 39/* Define default timeout for a request.
52 * There is no behavior specified by the msi on what will 40 * There is no behavior specified by the msi on what will
@@ -57,31 +45,55 @@ unsigned char *VERSION_STRING = (unsigned char *)"0.3.1";
57/** 45/**
58 * Protocol: 46 * Protocol:
59 * 47 *
60 * | desc. ( 1 byte ) | length ( 2 bytes ) | value ( length bytes ) | 48 * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|
61 *
62 * ie.
63 *
64 * | 0x1 | 0x0 0x7 | "version"
65 *
66 * Means: it's field value with length of 7 bytes and value of "version"
67 * It's similar to amp protocol
68 */ 49 */
69 50
70 51
71#define GENERIC_HEADER(header) \ 52typedef enum {
53 IDRequest = 1,
54 IDResponse,
55 IDReason,
56 IDCallType,
57 IDCallId,
58
59} MSIHeaderID;
60
61typedef enum {
62 TypeRequest,
63 TypeResponse,
64
65} MSIMessageType;
66
67typedef enum {
68 invite,
69 start,
70 cancel,
71 reject,
72 end,
73
74} MSIRequest;
75
76typedef enum {
77 ringing,
78 starting,
79 ending,
80 error
81
82} MSIResponse;
83
84
85#define GENERIC_HEADER(header, val_type) \
72typedef struct _MSIHeader##header { \ 86typedef struct _MSIHeader##header { \
73uint8_t* header_value; \ 87val_type value; \
74uint16_t size; \ 88_Bool exists; \
75} MSIHeader##header; 89} MSIHeader##header;
76 90
77 91
78GENERIC_HEADER ( Version ) 92GENERIC_HEADER ( Request, MSIRequest )
79GENERIC_HEADER ( Request ) 93GENERIC_HEADER ( Response, MSIResponse )
80GENERIC_HEADER ( Response ) 94GENERIC_HEADER ( CallType, MSICallType )
81GENERIC_HEADER ( CallType ) 95GENERIC_HEADER ( CallId, MSICallIDType )
82GENERIC_HEADER ( CallId ) 96GENERIC_HEADER ( Reason, MSIReasonStrType )
83GENERIC_HEADER ( Info )
84GENERIC_HEADER ( Reason )
85 97
86 98
87/** 99/**
@@ -91,111 +103,25 @@ GENERIC_HEADER ( Reason )
91 */ 103 */
92typedef struct _MSIMessage { 104typedef struct _MSIMessage {
93 105
94 MSIHeaderVersion version;
95 MSIHeaderRequest request; 106 MSIHeaderRequest request;
96 MSIHeaderResponse response; 107 MSIHeaderResponse response;
97 MSIHeaderCallType calltype; 108 MSIHeaderCallType calltype;
98 MSIHeaderInfo info;
99 MSIHeaderReason reason; 109 MSIHeaderReason reason;
100 MSIHeaderCallId callid; 110 MSIHeaderCallId callid;
101 111
102 struct _MSIMessage *next;
103
104 int friend_id; 112 int friend_id;
105 113
106} MSIMessage; 114} MSIMessage;
107 115
108 116
109static struct _Callbacks { 117inline__ void invoke_callback(MSISession* session, int32_t call_index, MSICallbackID id)
110 MSICallback function;
111 void *data;
112} callbacks[11] = {{0}};
113
114inline__ void invoke_callback(int32_t call_index, MSICallbackID id)
115{ 118{
116 if ( callbacks[id].function ) { 119 if ( session->callbacks[id].function ) {
117 LOGGER_DEBUG("Invoking callback function: %d", id); 120 LOGGER_DEBUG("Invoking callback function: %d", id);
118 callbacks[id].function ( call_index, callbacks[id].data ); 121 session->callbacks[id].function ( session->agent_handler, call_index, session->callbacks[id].data );
119 } 122 }
120} 123}
121 124
122/*static MSICallback callbacks[10] = {0};*/
123
124
125/* define strings for the identifiers */
126#define VERSION_FIELD "Version"
127#define REQUEST_FIELD "Request"
128#define RESPONSE_FIELD "Response"
129#define INFO_FIELD "INFO"
130#define REASON_FIELD "Reason"
131#define CALLTYPE_FIELD "Call-type"
132#define CALLID_FIELD "Call-id"
133
134/* protocol descriptors */
135#define end_byte 0x0
136#define field_byte 0x1
137#define value_byte 0x2
138
139
140typedef enum {
141 invite,
142 start,
143 cancel,
144 reject,
145 end,
146
147} MSIRequest;
148
149
150/**
151 * @brief Get string value for request.
152 *
153 * @param request The request.
154 * @return const uint8_t* The string
155 */
156static inline__ const uint8_t *stringify_request ( MSIRequest request )
157{
158 static const uint8_t *strings[] = {
159 ( uint8_t *) "INVITE",
160 ( uint8_t *) "START",
161 ( uint8_t *) "CANCEL",
162 ( uint8_t *) "REJECT",
163 ( uint8_t *) "END"
164 };
165
166 return strings[request];
167}
168
169
170typedef enum {
171 ringing,
172 starting,
173 ending,
174 error
175
176} MSIResponse;
177
178
179/**
180 * @brief Get string value for response.
181 *
182 * @param response The response.
183 * @return const uint8_t* The string
184 */
185static inline__ const uint8_t *stringify_response ( MSIResponse response )
186{
187 static const uint8_t *strings[] = {
188 ( uint8_t *) "ringing",
189 ( uint8_t *) "starting",
190 ( uint8_t *) "ending",
191 ( uint8_t *) "error"
192 };
193
194 return strings[response];
195}
196
197
198
199/** 125/**
200 * @brief Parse raw 'data' received from socket into MSIMessage struct. 126 * @brief Parse raw 'data' received from socket into MSIMessage struct.
201 * Every message has to have end value of 'end_byte' or _undefined_ behavior 127 * Every message has to have end value of 'end_byte' or _undefined_ behavior
@@ -209,124 +135,69 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
209 */ 135 */
210static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 136static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
211{ 137{
212 138
213#define ON_HEADER(iterator, size_con, header, descriptor, type_size_const) \ 139#define FAIL_CONSTRAINT(constraint, wanted) if ((constraint -= wanted) < 1) { LOGGER_ERROR("Read over length!"); return -1; }
214( memcmp(iterator, descriptor, type_size_const) == 0){ /* Okay */ \ 140#define FAIL_SIZE(byte, valid) if ( byte != valid ) { LOGGER_ERROR("Invalid data size!"); return -1; }
215iterator += type_size_const; /* Set iterator at begining of value part */ \ 141#define FAIL_LIMITS(byte, low, high) if ( byte < low || byte > high ) { LOGGER_ERROR("Invalid data!"); return -1; }
216if ( *iterator != value_byte || size_con <= type_size_const) { return -1; } size_con -= type_size_const; \ 142
217iterator ++; if(size_con <= 3) {return -1;} size_con -= 3; \
218uint16_t _value_size; memcpy(&_value_size, iterator, sizeof(_value_size)); _value_size = ntohs(_value_size);\
219if(size_con < _value_size) { return -1; } size_con -= _value_size; \
220if ( !(header.header_value = calloc(sizeof(uint8_t), _value_size)) ) \
221LOGGER_ERROR("Allocation failed! Program might misbehave!"); \
222header.size = _value_size; \
223memcpy(header.header_value, iterator + 2, _value_size);\
224iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ }
225
226 if ( msg == NULL ) { 143 if ( msg == NULL ) {
227 LOGGER_ERROR("Could not parse message: no storage!"); 144 LOGGER_ERROR("Could not parse message: no storage!");
228 return -1; 145 return -1;
229 } 146 }
230 147
231 if ( data[length - 1] ) /* End byte must have value 0 */ 148 if ( data[length - 1] ) { /* End byte must have value 0 */
149 LOGGER_ERROR("Invalid end byte");
232 return -1; 150 return -1;
233 151 }
234 const uint8_t *_it = data; 152
235 uint16_t size_max = length; 153 const uint8_t *it = data;
236 154 int size_constraint = length;
237 while ( *_it ) {/* until end_byte is hit */ 155
238 156 while ( *it ) {/* until end byte is hit */
239 uint16_t itedlen = (_it - data) + 2; 157 switch (*it) {
240 158 case IDRequest:
241 if ( *_it == field_byte && itedlen < length ) { 159 FAIL_CONSTRAINT(size_constraint, 3);
242 160 FAIL_SIZE(it[1], 1);
243 uint16_t _size; 161 FAIL_LIMITS(it[2], invite, end);
244 memcpy(&_size, _it + 1, sizeof(_size)); 162 msg->request.value = it[2]; it += 3;
245 _size = ntohs(_size); 163 msg->request.exists = 1;
246 164 break;
247 if ( itedlen + _size > length ) return -1; 165 case IDResponse:
248 166 FAIL_CONSTRAINT(size_constraint, 3);
249 _it += 3; /* place it at the field value beginning */ 167 FAIL_SIZE(it[1], 1);
250 size_max -= 3; 168 FAIL_LIMITS(it[2], ringing, error);
251 169 msg->response.value = it[2]; it += 3;
252 switch ( _size ) { /* Compare the size of the hardcoded values ( very convenient ) */ 170 msg->response.exists = 1;
253 171 break;
254 case 4: { /* INFO header */ 172 case IDCallType:
255 if ON_HEADER ( _it, size_max, msg->info, INFO_FIELD, 4 ) 173 FAIL_CONSTRAINT(size_constraint, 3);
256 } 174 FAIL_SIZE(it[1], 1);
257 break; 175 FAIL_LIMITS(it[2], type_audio, type_video);
258 176 msg->calltype.value = it[2]; it += 3;
259 case 6: { /* Reason header */ 177 msg->calltype.exists = 1;
260 if ON_HEADER ( _it, size_max, msg->reason, REASON_FIELD, 6 ) 178 break;
261 } 179 case IDCallId:
262 break; 180 FAIL_CONSTRAINT(size_constraint, sizeof(MSICallIDType) + 2);
263 181 FAIL_SIZE(it[1], sizeof(MSICallIDType));
264 case 7: { /* Version, Request, Call-id headers */ 182 memcpy(msg->callid.value, it + 2, sizeof(MSICallIDType)); it += sizeof(MSICallIDType) + 2;
265 if ON_HEADER ( _it, size_max, msg->version, VERSION_FIELD, 7 ) 183 msg->callid.exists = 1;
266 else if ON_HEADER ( _it, size_max, msg->request, REQUEST_FIELD, 7 ) 184 break;
267 else if ON_HEADER ( _it, size_max, msg->callid, CALLID_FIELD, 7 ) 185 case IDReason:
268 } 186 FAIL_CONSTRAINT(size_constraint, sizeof(MSIReasonStrType) + 2);
269 break; 187 FAIL_SIZE(it[1], sizeof(MSIReasonStrType));
270 188 memcpy(msg->reason.value, it + 2, sizeof(MSIReasonStrType)); it += sizeof(MSIReasonStrType) + 2;
271 case 8: { /* Response header */ 189 msg->reason.exists = 1;
272 if ON_HEADER ( _it, size_max, msg->response, RESPONSE_FIELD, 8 ) 190 break;
273 } 191 default:
274 break; 192 LOGGER_ERROR("Invalid id byte");
275
276 case 9: { /* Call-type header */
277 if ON_HEADER ( _it, size_max, msg->calltype, CALLTYPE_FIELD, 9 )
278 }
279 break;
280
281 default:
282 LOGGER_ERROR("Unkown field value");
283 return -1;
284 }
285 } else {
286 LOGGER_ERROR("Invalid field byte or field size too large");
287 return -1; 193 return -1;
194 break;
288 } 195 }
289
290 /* If it's anything else return failure as the message is invalid */
291
292 } 196 }
293 197
294 return 0; 198 return 0;
295} 199}
296 200
297
298#define ALLOCATE_HEADER( var, mheader_value, t_size) \
299if (!(var.header_value = calloc(sizeof *mheader_value, t_size))) \
300{ LOGGER_WARNING("Header allocation failed! Program might misbehave!"); } \
301else { memcpy(var.header_value, mheader_value, t_size); \
302var.size = t_size; }
303
304
305/**
306 * @brief Speaks for it self.
307 *
308 * @param msg The message.
309 * @return void
310 */
311static void free_message ( MSIMessage *msg )
312{
313 if ( msg == NULL ) {
314 LOGGER_WARNING("Tried to free empty message");
315 return;
316 }
317
318 free ( msg->calltype.header_value );
319 free ( msg->request.header_value );
320 free ( msg->response.header_value );
321 free ( msg->version.header_value );
322 free ( msg->info.header_value );
323 free ( msg->reason.header_value );
324 free ( msg->callid.header_value );
325
326 free ( msg );
327}
328
329
330/** 201/**
331 * @brief Create the message. 202 * @brief Create the message.
332 * 203 *
@@ -335,29 +206,25 @@ static void free_message ( MSIMessage *msg )
335 * @return MSIMessage* Created message. 206 * @return MSIMessage* Created message.
336 * @retval NULL Error occurred. 207 * @retval NULL Error occurred.
337 */ 208 */
338static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 209MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
339{ 210{
340 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 211 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
341 212
342 if ( _retu == NULL ) { 213 if ( retu == NULL ) {
343 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 214 LOGGER_WARNING("Allocation failed! Program might misbehave!");
344 return NULL; 215 return NULL;
345 } 216 }
346 217
347 if ( type == TYPE_REQUEST ) { 218 if ( type == TypeRequest ) {
348 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 219 retu->request.exists = 1;
349 220 retu->request.value = type_value;
350 } else if ( type == TYPE_RESPONSE ) {
351 ALLOCATE_HEADER ( _retu->response, type_id, strlen ( (const char *)type_id ) )
352 221
353 } else { 222 } else {
354 free_message ( _retu ); 223 retu->response.exists = 1;
355 return NULL; 224 retu->response.value = type_value;
356 } 225 }
357 226
358 ALLOCATE_HEADER ( _retu->version, VERSION_STRING, strlen ( (const char *)VERSION_STRING ) ) 227 return retu;
359
360 return _retu;
361} 228}
362 229
363 230
@@ -368,36 +235,27 @@ static MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
368 * @return MSIMessage* Parsed message. 235 * @return MSIMessage* Parsed message.
369 * @retval NULL Error occurred. 236 * @retval NULL Error occurred.
370 */ 237 */
371static MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 238MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
372{ 239{
373 if ( data == NULL ) { 240 if ( data == NULL ) {
374 LOGGER_WARNING("Tried to parse empty message!"); 241 LOGGER_WARNING("Tried to parse empty message!");
375 return NULL; 242 return NULL;
376 } 243 }
377 244
378 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 245 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
379 246
380 if ( _retu == NULL ) { 247 if ( retu == NULL ) {
381 LOGGER_WARNING("Allocation failed! Program might misbehave!"); 248 LOGGER_WARNING("Allocation failed! Program might misbehave!");
382 return NULL; 249 return NULL;
383 } 250 }
384 251
385 memset ( _retu, 0, sizeof ( MSIMessage ) ); 252 if ( parse_raw_data ( retu, data, length ) == -1 ) {
386 253
387 if ( parse_raw_data ( _retu, data, length ) == -1 ) { 254 free ( retu );
388
389 free_message ( _retu );
390 return NULL;
391 }
392
393 if ( !_retu->version.header_value || VERSION_STRLEN != _retu->version.size ||
394 memcmp ( _retu->version.header_value, VERSION_STRING, VERSION_STRLEN ) != 0 ) {
395
396 free_message ( _retu );
397 return NULL; 255 return NULL;
398 } 256 }
399 257
400 return _retu; 258 return retu;
401} 259}
402 260
403 261
@@ -411,130 +269,101 @@ static MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
411 * @param length Pointer to container length. 269 * @param length Pointer to container length.
412 * @return uint8_t* Iterated container. 270 * @return uint8_t* Iterated container.
413 */ 271 */
414static uint8_t *append_header_to_string ( 272uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8_t value_len, uint16_t *length )
415 uint8_t *dest,
416 const uint8_t *header_field,
417 const uint8_t *header_value,
418 uint16_t value_len,
419 uint16_t *length )
420{ 273{
421 if ( dest == NULL ) { 274 if ( dest == NULL ) {
422 LOGGER_ERROR("No destination space!"); 275 LOGGER_ERROR("No destination space!");
423 return NULL; 276 return NULL;
424 } 277 }
425 278
426 if (header_value == NULL) { 279 if (value == NULL || value_len == 0) {
427 LOGGER_ERROR("Empty header value"); 280 LOGGER_ERROR("Empty header value");
428 return NULL; 281 return NULL;
429 } 282 }
430 283
431 if ( header_field == NULL ) { 284 *dest = id; dest ++;
432 LOGGER_ERROR("Empty header field"); 285 *dest = value_len; dest ++;
433 return NULL; 286
434 } 287 memcpy(dest, value, value_len);
435 288
436 289 *length += (2 + value_len);
437 const uint8_t *_hvit = header_value; 290
438 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ 291 return dest + value_len; /* Set to next position ready to be written */
439
440 *dest = field_byte; /* Set the first byte */
441
442 uint8_t *_getback_byte = dest + 1; /* remember the byte we were on */
443 dest += 3; /* swith to 4th byte where field value starts */
444
445 /* Now set the field value and calculate it's length */
446 uint16_t _i = 0;
447
448 for ( ; header_field[_i]; ++_i ) {
449 *dest = header_field[_i];
450 ++dest;
451 };
452
453 _total += _i;
454
455 /* Now set the length of the field byte */
456 uint16_t _convert;
457
458
459 _convert = htons(_i);
460
461 memcpy(_getback_byte, &_convert, sizeof(_convert));
462
463 /* for value part do it regulary */
464 *dest = value_byte;
465
466 dest++;
467
468
469 _convert = htons(value_len);
470
471 memcpy(dest, &_convert, sizeof(_convert));
472
473 dest += 2;
474
475 for ( _i = value_len; _i; --_i ) {
476 *dest = *_hvit;
477 ++_hvit;
478 ++dest;
479 }
480
481 *length += _total;
482 return dest;
483} 292}
484 293
485 294
486/** 295/**
487 * @brief Convert MSIMessage struct to _sendable_ string. 296 * @brief Parse MSIMessage to send.
488 * 297 *
489 * @param msg The message. 298 * @param msg The message.
490 * @param dest Destination. 299 * @param dest Destination.
491 * @return uint16_t It's final size. 300 * @return uint16_t Its final size.
492 */ 301 */
493static uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest ) 302uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
494{ 303{
495#define CLEAN_ASSIGN(added, var, field, header)\
496 if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
497
498 if (msg == NULL) { 304 if (msg == NULL) {
499 LOGGER_ERROR("Empty message!"); 305 LOGGER_ERROR("No message!");
500 return 0; 306 return 0;
501 } 307 }
502 308
503 if (dest == NULL ) { 309 if (dest == NULL ) {
504 LOGGER_ERROR("Empty destination!"); 310 LOGGER_ERROR("No destination!");
505 return 0; 311 return 0;
506 } 312 }
507 313
508 uint8_t *_iterated = dest; 314 uint8_t *it = dest;
509 uint16_t _size = 0; 315 uint16_t size = 0;
510 316
511 CLEAN_ASSIGN ( _size, _iterated, VERSION_FIELD, msg->version ); 317 if (msg->request.exists) {
512 CLEAN_ASSIGN ( _size, _iterated, REQUEST_FIELD, msg->request ); 318 uint8_t cast = msg->request.value;
513 CLEAN_ASSIGN ( _size, _iterated, RESPONSE_FIELD, msg->response ); 319 it = format_output(it, IDRequest, &cast, 1, &size);
514 CLEAN_ASSIGN ( _size, _iterated, CALLTYPE_FIELD, msg->calltype ); 320 }
515 CLEAN_ASSIGN ( _size, _iterated, INFO_FIELD, msg->info ); 321
516 CLEAN_ASSIGN ( _size, _iterated, CALLID_FIELD, msg->callid ); 322 if (msg->response.exists) {
517 CLEAN_ASSIGN ( _size, _iterated, REASON_FIELD, msg->reason ); 323 uint8_t cast = msg->response.value;
518 324 it = format_output(it, IDResponse, &cast, 1, &size);
519 *_iterated = end_byte; 325 }
520 _size ++; 326
327 if (msg->calltype.exists) {
328 uint8_t cast = msg->calltype.value;
329 it = format_output(it, IDCallType, &cast, 1, &size);
330 }
331
332 if (msg->callid.exists) {
333 it = format_output(it, IDCallId, &msg->callid.value, sizeof(msg->callid.value), &size);
334 }
335
336 if (msg->reason.exists) {
337 it = format_output(it, IDReason, &msg->reason.value, sizeof(msg->reason.value), &size);
338 }
339
340 *it = 0;
341 size ++;
521 342
522 return _size; 343 return size;
523} 344}
524 345
525 346
526#define GENERIC_SETTER_DEFINITION(header) \ 347void msi_msg_set_calltype ( MSIMessage* msg, const MSICallType value )
527void msi_msg_set_##header ( MSIMessage* _msg, const uint8_t* header_value, uint16_t _size ) \ 348{
528{ if ( !_msg || !header_value) { LOGGER_WARNING("No setter values!"); return; } \ 349 if ( !msg ) return;
529 free(_msg->header.header_value); \ 350 msg->calltype.exists = 1;
530 ALLOCATE_HEADER( _msg->header, header_value, _size )} 351 msg->calltype.value = value;
531 352}
532GENERIC_SETTER_DEFINITION ( calltype )
533GENERIC_SETTER_DEFINITION ( reason )
534GENERIC_SETTER_DEFINITION ( info )
535GENERIC_SETTER_DEFINITION ( callid )
536 353
354void msi_msg_set_reason ( MSIMessage* msg, const MSIReasonStrType value )
355{
356 if ( !msg ) return;
357 msg->reason.exists = 1;
358 memcpy(msg->reason.value, value, sizeof(MSIReasonStrType));
359}
537 360
361void msi_msg_set_callid ( MSIMessage* msg, const MSICallIDType value )
362{
363 if ( !msg ) return;
364 msg->callid.exists = 1;
365 memcpy(msg->callid.value, value, sizeof(MSICallIDType));
366}
538 367
539 368
540typedef struct _Timer { 369typedef struct _Timer {
@@ -666,7 +495,7 @@ static int timer_release ( TimerHandler *timers_container, int idx , int lock_mu
666 495
667 timers_container->size--; 496 timers_container->size--;
668 497
669 LOGGER_DEBUG("Popped index: %d, current size: %d ", idx, timers_container->size); 498 LOGGER_DEBUG("Popped id: %d, current size: %d ", idx, timers_container->size);
670 499
671 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex); 500 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
672 501
@@ -691,15 +520,15 @@ static void *timer_poll( void *arg )
691 520
692 uint64_t time = current_time_monotonic(); 521 uint64_t time = current_time_monotonic();
693 522
694 if ( handler->timers[0] && handler->timers[0]->timeout < time ) { 523 while ( handler->timers[0] && handler->timers[0]->timeout < time ) {
695 pthread_t _tid; 524 pthread_t tid;
696 525
697 struct timer_function_args *args = malloc(sizeof(struct timer_function_args)); 526 struct timer_function_args *args = malloc(sizeof(struct timer_function_args));
698 args->arg1 = handler->timers[0]->func_arg1; 527 args->arg1 = handler->timers[0]->func_arg1;
699 args->arg2 = handler->timers[0]->func_arg2; 528 args->arg2 = handler->timers[0]->func_arg2;
700 529
701 if ( 0 != pthread_create(&_tid, NULL, handler->timers[0]->func, args) || 530 if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) ||
702 0 != pthread_detach(_tid) ) { 531 0 != pthread_detach(tid) ) {
703 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout); 532 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout);
704 free(args); 533 free(args);
705 } else { 534 } else {
@@ -833,9 +662,9 @@ typedef enum {
833 * @param error_code The code. 662 * @param error_code The code.
834 * @return const uint8_t* The string. 663 * @return const uint8_t* The string.
835 */ 664 */
836static inline__ const uint8_t *stringify_error ( MSICallError error_code ) 665static inline__ const uint8_t* stringify_error ( MSICallError error_code )
837{ 666{
838 static const uint8_t *strings[] = { 667 static const uint8_t* strings[] = {
839 ( uint8_t *) "", 668 ( uint8_t *) "",
840 ( uint8_t *) "Using dead call", 669 ( uint8_t *) "Using dead call",
841 ( uint8_t *) "Call id not set to any call", 670 ( uint8_t *) "Call id not set to any call",
@@ -848,29 +677,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code )
848 return strings[error_code]; 677 return strings[error_code];
849} 678}
850 679
851
852/**
853 * @brief Convert error_code into string.
854 *
855 * @param error_code The code.
856 * @return const uint8_t* The string.
857 */
858static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
859{
860 static const uint8_t *strings[] = {
861 ( uint8_t *) "",
862 ( uint8_t *) "1",
863 ( uint8_t *) "2",
864 ( uint8_t *) "3",
865 ( uint8_t *) "4",
866 ( uint8_t *) "5",
867 ( uint8_t *) "6"
868 };
869
870 return strings[error_code];
871}
872
873
874/** 680/**
875 * @brief Speaks for it self. 681 * @brief Speaks for it self.
876 * 682 *
@@ -883,17 +689,17 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
883 */ 689 */
884static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 690static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
885{ 691{
886 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN ); 692 msi_msg_set_callid ( msg, call->id );
887 693
888 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 694 uint8_t msg_string_final [MSI_MAXMSG_SIZE];
889 uint16_t _length = message_to_send ( msg, _msg_string_final ); 695 uint16_t length = parse_send ( msg, msg_string_final );
890 696
891 if (!_length) { 697 if (!length) {
892 LOGGER_WARNING("Parsing message failed; nothing sent!"); 698 LOGGER_WARNING("Parsing message failed; nothing sent!");
893 return -1; 699 return -1;
894 } 700 }
895 701
896 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) { 702 if ( m_msi_packet(session->messenger_handle, to, msg_string_final, length) ) {
897 LOGGER_DEBUG("Sent message"); 703 LOGGER_DEBUG("Sent message");
898 return 0; 704 return 0;
899 } 705 }
@@ -901,6 +707,12 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
901 return -1; 707 return -1;
902} 708}
903 709
710inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to )
711{
712 MSIMessage *msg = msi_new_message ( TypeResponse, response );
713 send_message ( session, call, msg, to );
714 free ( msg );
715}
904 716
905/** 717/**
906 * @brief Determine 'bigger' call id 718 * @brief Determine 'bigger' call id
@@ -913,7 +725,7 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
913 */ 725 */
914static int call_id_bigger( const uint8_t *first, const uint8_t *second) 726static int call_id_bigger( const uint8_t *first, const uint8_t *second)
915{ 727{
916 return (memcmp(first, second, CALL_ID_LEN) < 0); 728 return (memcmp(first, second, sizeof(MSICallIDType)) < 0);
917} 729}
918 730
919 731
@@ -923,23 +735,17 @@ static int call_id_bigger( const uint8_t *first, const uint8_t *second)
923 * @param session Control session. 735 * @param session Control session.
924 * @param msg The message. 736 * @param msg The message.
925 * @param peer_id The peer. 737 * @param peer_id The peer.
926 * @return void 738 * @return -1, 0
927 */ 739 */
928static void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id ) 740static int flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
929{ 741{
930 if ( msg->calltype.header_value ) { 742 if ( msg->calltype.exists ) {
931 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 743 call->type_peer[peer_id] = msg->calltype.value;
932 744 return 0;
933 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 745 }
934 hdrval[msg->calltype.size] = '\0';
935
936 if ( strcmp ( ( const char *) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
937 call->type_peer[peer_id] = type_audio;
938 746
939 } else if ( strcmp ( ( const char *) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 747 LOGGER_WARNING("No call type header!");
940 call->type_peer[peer_id] = type_video; 748 return -1;
941 } else {} /* Error */
942 } else {} /* Error */
943} 749}
944 750
945static int terminate_call ( MSISession *session, MSICall *call ); 751static int terminate_call ( MSISession *session, MSICall *call );
@@ -960,7 +766,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_num
960 766
961 for ( ; i < session->calls[j]->peer_count; i ++ ) 767 for ( ; i < session->calls[j]->peer_count; i ++ )
962 if ( session->calls[j]->peers[i] == friend_num ) { 768 if ( session->calls[j]->peers[i] == friend_num ) {
963 invoke_callback(j, MSI_OnPeerTimeout); 769 invoke_callback(session, j, MSI_OnPeerTimeout);
964 terminate_call(session, session->calls[j]); 770 terminate_call(session, session->calls[j]);
965 LOGGER_DEBUG("Remote: %d timed out!", friend_num); 771 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
966 return; /* TODO: On group calls change behaviour */ 772 return; /* TODO: On group calls change behaviour */
@@ -981,12 +787,7 @@ static MSICall *find_call ( MSISession *session, uint8_t *call_id )
981 uint32_t i = 0; 787 uint32_t i = 0;
982 788
983 for (; i < session->max_calls; i ++ ) 789 for (; i < session->max_calls; i ++ )
984 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { 790 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, sizeof(session->calls[i]->id)) == 0 ) {
985 LOGGER_SCOPE(
986 char tmp[CALL_ID_LEN + 1] = {'\0'};
987 memcpy(tmp, session->calls[i]->id, CALL_ID_LEN);
988 LOGGER_DEBUG("Found call id: %s", tmp);
989 );
990 return session->calls[i]; 791 return session->calls[i];
991 } 792 }
992 793
@@ -1011,18 +812,11 @@ static int send_error ( MSISession *session, MSICall *call, MSICallError errid,
1011 812
1012 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id); 813 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
1013 814
1014 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 815 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
1015
1016 const uint8_t *_error_code_str = stringify_error_code ( errid );
1017 816
1018 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char *) _error_code_str ) ); 817 msi_msg_set_reason ( msg_error, stringify_error(errid) );
1019 send_message ( session, call, _msg_error, to ); 818 send_message ( session, call, msg_error, to );
1020 free_message ( _msg_error ); 819 free ( msg_error );
1021
1022 session->last_error_id = errid;
1023 session->last_error_str = stringify_error ( errid );
1024
1025 /* invoke_callback(call->call_idx, MSI_OnError); */
1026 820
1027 return 0; 821 return 0;
1028} 822}
@@ -1131,8 +925,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1131 return -1; 925 return -1;
1132 } 926 }
1133 927
1134 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
1135
1136 LOGGER_DEBUG("Terminated call id: %d", call->call_idx); 928 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
1137 /* Check event loop and cancel timed events if there are any 929 /* Check event loop and cancel timed events if there are any
1138 * NOTE: This has to be done before possibly 930 * NOTE: This has to be done before possibly
@@ -1156,9 +948,6 @@ static int terminate_call ( MSISession *session, MSICall *call )
1156 948
1157 free ( call ); 949 free ( call );
1158 950
1159 if ( rc != EBUSY ) /* Unlock if locked by this call */
1160 pthread_mutex_unlock(&session->mutex);
1161
1162 return 0; 951 return 0;
1163} 952}
1164 953
@@ -1178,21 +967,21 @@ static void *handle_timeout ( void *arg )
1178 struct timer_function_args *args = arg; 967 struct timer_function_args *args = arg;
1179 int call_index = args->arg2; 968 int call_index = args->arg2;
1180 MSISession *session = args->arg1; 969 MSISession *session = args->arg1;
1181 MSICall *_call = session->calls[call_index]; 970 MSICall *call = session->calls[call_index];
1182 971
1183 if (_call) { 972 if (call) {
1184 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id); 973 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
1185 974
1186 invoke_callback(call_index, MSI_OnRequestTimeout); 975 invoke_callback(session, call_index, MSI_OnRequestTimeout);
1187 } 976 }
1188 977
1189 if ( _call && _call->session ) { 978 if ( call && call->session ) {
1190 979
1191 /* TODO: Cancel all? */ 980 /* TODO: Cancel all? */
1192 /* uint16_t _it = 0; 981 /* uint16_t _it = 0;
1193 * for ( ; _it < _session->call->peer_count; _it++ ) */ 982 * for ( ; _it < _session->call->peer_count; _it++ ) */
1194 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" ); 983 msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" );
1195 /*terminate_call(_call->session, _call);*/ 984 /*terminate_call(call->session, call);*/
1196 } 985 }
1197 986
1198 free(arg); 987 free(arg);
@@ -1203,38 +992,60 @@ static void *handle_timeout ( void *arg )
1203/********** Request handlers **********/ 992/********** Request handlers **********/
1204static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg ) 993static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
1205{ 994{
1206 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new"); 995 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
1207 996
1208 pthread_mutex_lock(&session->mutex); 997 pthread_mutex_lock(&session->mutex);
1209 998
999 if (!msg->calltype.exists) {/**/
1000 LOGGER_WARNING("Peer sent invalid call type!");
1001 send_error ( session, call, error_no_callid, msg->friend_id );
1002 pthread_mutex_unlock(&session->mutex);
1003 return 0;
1004 }
1210 1005
1211 if ( call ) { 1006 if ( call ) {
1212 if ( call->peers[0] == msg->friend_id ) { 1007 if ( call->peers[0] == msg->friend_id ) {
1213 /* The glare case. A calls B when at the same time 1008 if (call->state == call_inviting) {
1214 * B calls A. Who has advantage is set bey calculating 1009 /* The glare case. A calls B when at the same time
1215 * 'bigger' Call id and then that call id is being used in 1010 * B calls A. Who has advantage is set bey calculating
1216 * future. User with 'bigger' Call id has the advantage 1011 * 'bigger' Call id and then that call id is being used in
1217 * as in he will wait the response from the other. 1012 * future. User with 'bigger' Call id has the advantage
1218 */ 1013 * as in he will wait the response from the other.
1219 1014 */
1220 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1015 LOGGER_DEBUG("Glare case; Peer: %d", call->peers[0]);
1221 1016
1222 /* Terminate call; peer will timeout(call) if call initialization (magically) fails */ 1017 if ( call_id_bigger (call->id, msg->callid.value) == 1 ) { /* Peer has advantage */
1223 terminate_call(session, call); 1018
1224 1019 /* Terminate call; peer will timeout(call) if call initialization fails */
1225 call = init_call ( session, 1, 0 ); 1020 terminate_call(session, call);
1021
1022 call = init_call ( session, 1, 0 );
1023
1024 if ( !call ) {
1025 pthread_mutex_unlock(&session->mutex);
1026 LOGGER_ERROR("Starting call");
1027 return 0;
1028 }
1226 1029
1227 if ( !call ) { 1030 } else {
1031 pthread_mutex_unlock(&session->mutex);
1032 return 0; /* Wait for ringing from peer */
1033 }
1034 } else if (call->state == call_active) {
1035 /* Request for media change; call callback and send starting response */
1036 if (flush_peer_type(call, msg, 0) != 0) { /**/
1037 LOGGER_WARNING("Peer sent invalid call type!");
1038 send_error ( session, call, error_no_callid, msg->friend_id );
1228 pthread_mutex_unlock(&session->mutex); 1039 pthread_mutex_unlock(&session->mutex);
1229 LOGGER_ERROR("Starting call");
1230 return 0; 1040 return 0;
1231 } 1041 }
1232 1042
1233 } else { 1043 LOGGER_DEBUG("Set new call type: %s", call->type_peer[0] == type_audio ? "audio" : "video");
1044 send_reponse(session, call, starting, msg->friend_id);
1234 pthread_mutex_unlock(&session->mutex); 1045 pthread_mutex_unlock(&session->mutex);
1235 return 0; /* Wait for ringing from peer */ 1046 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1047 return 1;
1236 } 1048 }
1237
1238 } else { 1049 } else {
1239 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ 1050 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
1240 terminate_call(session, call); 1051 terminate_call(session, call);
@@ -1251,27 +1062,25 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1251 } 1062 }
1252 } 1063 }
1253 1064
1254 if ( !msg->callid.header_value ) { 1065 if ( !msg->callid.exists ) {
1255 send_error ( session, call, error_no_callid, msg->friend_id ); 1066 send_error ( session, call, error_no_callid, msg->friend_id );
1256 terminate_call(session, call); 1067 terminate_call(session, call);
1257 pthread_mutex_unlock(&session->mutex); 1068 pthread_mutex_unlock(&session->mutex);
1258 return 0; 1069 return 0;
1259 } 1070 }
1260 1071
1261 memcpy ( call->id, msg->callid.header_value, CALL_ID_LEN ); 1072 memcpy ( call->id, msg->callid.value, sizeof(msg->callid.value) );
1262 call->state = call_starting; 1073 call->state = call_starting;
1263 1074
1264 add_peer( call, msg->friend_id); 1075 add_peer( call, msg->friend_id);
1265 1076
1266 flush_peer_type ( call, msg, 0 ); 1077 flush_peer_type ( call, msg, 0 );
1267 1078
1268 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1079 send_reponse(session, call, ringing, msg->friend_id);
1269 send_message ( session, call, _msg_ringing, msg->friend_id );
1270 free_message ( _msg_ringing );
1271 1080
1272 pthread_mutex_unlock(&session->mutex); 1081 pthread_mutex_unlock(&session->mutex);
1273 1082
1274 invoke_callback(call->call_idx, MSI_OnInvite); 1083 invoke_callback(session, call->call_idx, MSI_OnInvite);
1275 1084
1276 return 1; 1085 return 1;
1277} 1086}
@@ -1283,17 +1092,15 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
1283 return 0; 1092 return 0;
1284 } 1093 }
1285 1094
1286 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id ); 1095 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
1287 1096
1288 pthread_mutex_lock(&session->mutex); 1097 pthread_mutex_lock(&session->mutex);
1289 1098
1290 call->state = call_active; 1099 call->state = call_active;
1291 1100
1292 flush_peer_type ( call, msg, 0 );
1293
1294 pthread_mutex_unlock(&session->mutex); 1101 pthread_mutex_unlock(&session->mutex);
1295 1102
1296 invoke_callback(call->call_idx, MSI_OnStart); 1103 invoke_callback(session, call->call_idx, MSI_OnStart);
1297 return 1; 1104 return 1;
1298} 1105}
1299 1106
@@ -1304,20 +1111,17 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
1304 return 0; 1111 return 0;
1305 } 1112 }
1306 1113
1307 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id); 1114 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->call_idx);
1308 1115
1116 invoke_callback(session, call->call_idx, MSI_OnReject);
1117
1309 pthread_mutex_lock(&session->mutex); 1118 pthread_mutex_lock(&session->mutex);
1310 1119
1311 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1120 send_reponse(session, call, ending, msg->friend_id);
1312 send_message ( session, call, _msg_ending, msg->friend_id ); 1121 terminate_call(session, call);
1313 free_message ( _msg_ending );
1314
1315 1122
1316 pthread_mutex_unlock(&session->mutex); 1123 pthread_mutex_unlock(&session->mutex);
1317 1124
1318 invoke_callback(call->call_idx, MSI_OnReject);
1319
1320 terminate_call(session, call);
1321 return 1; 1125 return 1;
1322} 1126}
1323 1127
@@ -1328,16 +1132,16 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
1328 return 0; 1132 return 0;
1329 } 1133 }
1330 1134
1331 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id ); 1135 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->call_idx);
1332 1136
1333 pthread_mutex_lock(&session->mutex); 1137 invoke_callback(session, call->call_idx, MSI_OnCancel);
1334
1335 /* Act as end message */
1336
1337 pthread_mutex_unlock(&session->mutex);
1338 invoke_callback(call->call_idx, MSI_OnCancel);
1339 1138
1139 pthread_mutex_lock(&session->mutex);
1140
1340 terminate_call ( session, call ); 1141 terminate_call ( session, call );
1142
1143 pthread_mutex_unlock(&session->mutex);
1144
1341 return 1; 1145 return 1;
1342} 1146}
1343 1147
@@ -1348,19 +1152,17 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
1348 return 0; 1152 return 0;
1349 } 1153 }
1350 1154
1351 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id ); 1155 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
1352 1156
1157 invoke_callback(session, call->call_idx, MSI_OnEnd);
1353 pthread_mutex_lock(&session->mutex); 1158 pthread_mutex_lock(&session->mutex);
1354 1159
1355 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1160 send_reponse(session, call, ending, msg->friend_id);
1356 send_message ( session, call, _msg_ending, msg->friend_id ); 1161 terminate_call ( session, call );
1357 free_message ( _msg_ending ); 1162
1358
1359 pthread_mutex_unlock(&session->mutex); 1163 pthread_mutex_unlock(&session->mutex);
1360 1164
1361 invoke_callback(call->call_idx, MSI_OnEnd);
1362 1165
1363 terminate_call ( session, call );
1364 return 1; 1166 return 1;
1365} 1167}
1366 1168
@@ -1380,40 +1182,57 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
1380 return 0; 1182 return 0;
1381 } 1183 }
1382 1184
1383 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); 1185 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx );
1384 1186
1385 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, 1187 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx,
1386 call->ringing_tout_ms ); 1188 call->ringing_tout_ms );
1387 1189
1388 pthread_mutex_unlock(&session->mutex); 1190 pthread_mutex_unlock(&session->mutex);
1389 1191
1390 invoke_callback(call->call_idx, MSI_OnRinging); 1192 invoke_callback(session, call->call_idx, MSI_OnRinging);
1391 return 1; 1193 return 1;
1392} 1194}
1393static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) 1195static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1394{ 1196{
1395 if ( !call ) { 1197 if ( !call ) {
1396 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 1198 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
1397 return 0; 1199 return 0;
1398 } 1200 }
1399 1201
1400 pthread_mutex_lock(&session->mutex); 1202 pthread_mutex_lock(&session->mutex);
1401 1203
1402 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id ); 1204 if ( call->state == call_active ) { /* Change media */
1205
1206 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1207 pthread_mutex_unlock(&session->mutex);
1208
1209 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1210
1211 } else if ( call->state == call_inviting ) {
1212 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
1403 1213
1404 call->state = call_active; 1214 call->state = call_active;
1405 1215
1406 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1216 MSIMessage *msg_start = msi_new_message ( TypeRequest, start );
1407 send_message ( session, call, _msg_start, msg->friend_id ); 1217 send_message ( session, call, msg_start, msg->friend_id );
1408 free_message ( _msg_start ); 1218 free ( msg_start );
1409 1219
1410 flush_peer_type ( call, msg, 0 ); 1220
1221 flush_peer_type ( call, msg, 0 );
1411 1222
1223 /* This is here in case of glare */
1224 timer_release ( session->timer_handler, call->ringing_timer_id, 1 );
1225
1226 pthread_mutex_unlock(&session->mutex);
1412 1227
1413 timer_release ( session->timer_handler, call->ringing_timer_id, 1 ); 1228 invoke_callback(session, call->call_idx, MSI_OnStarting);
1414 pthread_mutex_unlock(&session->mutex); 1229 } else {
1415 1230 LOGGER_ERROR("Invalid call state");
1416 invoke_callback(call->call_idx, MSI_OnStarting); 1231 terminate_call(session, call );
1232 pthread_mutex_unlock(&session->mutex);
1233 return 0;
1234 }
1235
1417 return 1; 1236 return 1;
1418} 1237}
1419static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg ) 1238static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
@@ -1423,25 +1242,19 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
1423 return 0; 1242 return 0;
1424 } 1243 }
1425 1244
1426 pthread_mutex_lock(&session->mutex); 1245 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
1427
1428 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id );
1429
1430 /* Stop timer */
1431 timer_release ( session->timer_handler, call->request_timer_id, 1 );
1432 1246
1433 pthread_mutex_unlock(&session->mutex); 1247 invoke_callback(session, call->call_idx, MSI_OnEnding);
1434
1435 invoke_callback(call->call_idx, MSI_OnEnding);
1436 1248
1437 /* Terminate call */ 1249 /* Terminate call */
1250 pthread_mutex_lock(&session->mutex);
1438 terminate_call ( session, call ); 1251 terminate_call ( session, call );
1252 pthread_mutex_unlock(&session->mutex);
1439 1253
1440 return 1; 1254 return 1;
1441} 1255}
1442static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg ) 1256static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1443{ 1257{
1444 pthread_mutex_lock(&session->mutex);
1445 1258
1446 if ( !call ) { 1259 if ( !call ) {
1447 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1260 LOGGER_WARNING("Handling 'error' on non-existing call!");
@@ -1449,20 +1262,19 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1449 return -1; 1262 return -1;
1450 } 1263 }
1451 1264
1452 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id ); 1265 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1453 1266
1267 invoke_callback(session, call->call_idx, MSI_OnEnding);
1268
1269 pthread_mutex_lock(&session->mutex);
1454 /* Handle error accordingly */ 1270 /* Handle error accordingly */
1455 if ( msg->reason.header_value ) { 1271 if ( msg->reason.exists ) {
1456 session->last_error_id = atoi ( ( const char *) msg->reason.header_value ); 1272 /* TODO */
1457 session->last_error_str = stringify_error ( session->last_error_id );
1458 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1459 } 1273 }
1460 1274
1461 pthread_mutex_unlock(&session->mutex);
1462
1463 invoke_callback(call->call_idx, MSI_OnEnding);
1464
1465 terminate_call ( session, call ); 1275 terminate_call ( session, call );
1276
1277 pthread_mutex_unlock(&session->mutex);
1466 1278
1467 return 1; 1279 return 1;
1468} 1280}
@@ -1514,7 +1326,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1514 return; 1326 return;
1515 } 1327 }
1516 1328
1517 msg = parse_message ( data, length ); 1329 msg = parse_recv ( data, length );
1518 1330
1519 if ( !msg ) { 1331 if ( !msg ) {
1520 LOGGER_WARNING("Error parsing message"); 1332 LOGGER_WARNING("Error parsing message");
@@ -1527,79 +1339,38 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1527 1339
1528 1340
1529 /* Find what call */ 1341 /* Find what call */
1530 MSICall *call = msg->callid.header_value ? find_call(session, msg->callid.header_value ) : NULL; 1342 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
1531 1343
1532 /* Now handle message */ 1344 /* Now handle message */
1533 1345
1534 if ( msg->request.header_value ) { /* Handle request */ 1346 if ( msg->request.exists ) { /* Handle request */
1535 1347
1536 if ( msg->response.size > 32 ) { 1348 switch(msg->request.value) {
1537 LOGGER_WARNING("Header size too big"); 1349 case invite: handle_recv_invite ( session, call, msg ); break;
1538 goto free_end; 1350 case start: handle_recv_start ( session, call, msg ); break;
1539 } 1351 case cancel: handle_recv_cancel ( session, call, msg ); break;
1540 1352 case reject: handle_recv_reject ( session, call, msg ); break;
1541 uint8_t _request_value[32]; 1353 case end: handle_recv_end ( session, call, msg ); break;
1542
1543 memcpy(_request_value, msg->request.header_value, msg->request.size);
1544 _request_value[msg->request.size] = '\0';
1545
1546 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1547 handle_recv_invite ( session, call, msg );
1548
1549 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1550 handle_recv_start ( session, call, msg );
1551
1552 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1553 handle_recv_cancel ( session, call, msg );
1554
1555 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1556 handle_recv_reject ( session, call, msg );
1557
1558 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1559 handle_recv_end ( session, call, msg );
1560 } else {
1561 LOGGER_WARNING("Uknown request");
1562 goto free_end;
1563 }
1564
1565 } else if ( msg->response.header_value ) { /* Handle response */
1566
1567 if ( msg->response.size > 32 ) {
1568 LOGGER_WARNING("Header size too big");
1569 goto free_end;
1570 } 1354 }
1355
1356 } else if ( msg->response.exists ) { /* Handle response */
1571 1357
1572 /* Got response so cancel timer */ 1358 /* Got response so cancel timer */
1573 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 ); 1359 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 );
1574 1360
1575 uint8_t _response_value[32]; 1361 switch(msg->response.value) {
1576 1362 case ringing: handle_recv_ringing ( session, call, msg ); break;
1577 memcpy(_response_value, msg->response.header_value, msg->response.size); 1363 case starting: handle_recv_starting ( session, call, msg ); break;
1578 _response_value[msg->response.size] = '\0'; 1364 case ending: handle_recv_ending ( session, call, msg ); break;
1579 1365 case error: handle_recv_error ( session, call, msg ); break;
1580 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1581 handle_recv_ringing ( session, call, msg );
1582
1583 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1584 handle_recv_starting ( session, call, msg );
1585
1586 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1587 handle_recv_ending ( session, call, msg );
1588
1589 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1590 handle_recv_error ( session, call, msg );
1591
1592 } else {
1593 LOGGER_WARNING("Uknown response");
1594 goto free_end;
1595 } 1366 }
1596 1367
1597 } else { 1368 } else {
1598 LOGGER_WARNING("Invalid message: no resp nor requ headers"); 1369 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1599 } 1370 }
1600 1371
1601free_end: 1372free_end:
1602 free_message ( msg ); 1373 free ( msg );
1603} 1374}
1604 1375
1605 1376
@@ -1610,10 +1381,10 @@ free_end:
1610 * @param id The id. 1381 * @param id The id.
1611 * @return void 1382 * @return void
1612 */ 1383 */
1613void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata ) 1384void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1614{ 1385{
1615 callbacks[id].function = callback; 1386 session->callbacks[id].function = callback;
1616 callbacks[id].data = userdata; 1387 session->callbacks[id].data = userdata;
1617} 1388}
1618 1389
1619 1390
@@ -1660,7 +1431,7 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1660 1431
1661 retu->frequ = 10000; /* default value? */ 1432 retu->frequ = 10000; /* default value? */
1662 retu->call_timeout = 30000; /* default value? */ 1433 retu->call_timeout = 30000; /* default value? */
1663 1434
1664 1435
1665 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 1436 m_callback_msi_packet(messenger, msi_handle_packet, retu );
1666 1437
@@ -1731,37 +1502,40 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type
1731 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 1502 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1732 1503
1733 1504
1734 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */ 1505 int i = 0;
1506 for (; i < session->max_calls; i ++)
1507 if (session->calls[i] && session->calls[i]->peers[0] == friend_id) {
1508 LOGGER_ERROR("Already in a call with friend %d", friend_id);
1509 pthread_mutex_unlock(&session->mutex);
1510 return -1;
1511 }
1512
1513
1514 MSICall *call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1735 1515
1736 if ( !_call ) { 1516 if ( !call ) {
1737 pthread_mutex_unlock(&session->mutex); 1517 pthread_mutex_unlock(&session->mutex);
1738 LOGGER_ERROR("Cannot handle more calls"); 1518 LOGGER_ERROR("Cannot handle more calls");
1739 return -1; 1519 return -1;
1740 } 1520 }
1741 1521
1742 *call_index = _call->call_idx; 1522 *call_index = call->call_idx;
1743 1523
1744 t_randomstr ( _call->id, CALL_ID_LEN ); 1524 t_randomstr ( call->id, sizeof(call->id) );
1745 1525
1746 add_peer(_call, friend_id ); 1526 add_peer ( call, friend_id );
1747 1527
1748 _call->type_local = call_type; 1528 call->type_local = call_type;
1749 1529
1750 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1530 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1751 1531
1752 /* Do whatever with message */ 1532 msi_msg_set_calltype(msg_invite, call_type);
1753 if ( call_type == type_audio ) { 1533 send_message ( session, call, msg_invite, friend_id );
1754 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1534 free( msg_invite );
1755 } else {
1756 msi_msg_set_calltype ( _msg_invite, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1757 }
1758 1535
1759 send_message ( session, _call, _msg_invite, friend_id ); 1536 call->state = call_inviting;
1760 free_message ( _msg_invite );
1761 1537
1762 _call->state = call_inviting; 1538 call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout );
1763
1764 _call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, _call->call_idx, m_deftout );
1765 1539
1766 LOGGER_DEBUG("Invite sent"); 1540 LOGGER_DEBUG("Invite sent");
1767 1541
@@ -1791,23 +1565,22 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1791 return -1; 1565 return -1;
1792 } 1566 }
1793 1567
1794 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) { 1568 if ( session->calls[call_index]->state != call_active ) {
1795 LOGGER_ERROR("No call with such index or call is not active!"); 1569 LOGGER_ERROR("No call with such index or call is not active!");
1796 pthread_mutex_unlock(&session->mutex); 1570 pthread_mutex_unlock(&session->mutex);
1797 return -1; 1571 return -1;
1798 } 1572 }
1799 1573
1800 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1574 MSIMessage *msg_end = msi_new_message ( TypeRequest, end );
1801 1575
1802 /* hangup for each peer */ 1576 /* hangup for each peer */
1803 int _it = 0; 1577 int it = 0;
1804 1578 for ( ; it < session->calls[call_index]->peer_count; it ++ )
1805 for ( ; _it < session->calls[call_index]->peer_count; _it ++ ) 1579 send_message ( session, session->calls[call_index], msg_end, session->calls[call_index]->peers[it] );
1806 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1807 1580
1808 session->calls[call_index]->state = call_hanged_up; 1581 session->calls[call_index]->state = call_hanged_up;
1809 1582
1810 free_message ( _msg_end ); 1583 free ( msg_end );
1811 1584
1812 session->calls[call_index]->request_timer_id = 1585 session->calls[call_index]->request_timer_id =
1813 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1586 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
@@ -1836,24 +1609,16 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1836 return -1; 1609 return -1;
1837 } 1610 }
1838 1611
1839 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1612 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
1840 1613
1841 session->calls[call_index]->type_local = call_type; 1614 session->calls[call_index]->type_local = call_type;
1842 1615
1843 if ( call_type == type_audio ) { 1616 msi_msg_set_calltype(msg_starting, call_type);
1844 msi_msg_set_calltype 1617 send_message ( session, session->calls[call_index], msg_starting, 0 );
1845 ( _msg_starting, ( const uint8_t *) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) ); 1618 free ( msg_starting );
1846 } else {
1847 msi_msg_set_calltype
1848 ( _msg_starting, ( const uint8_t *) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1849 }
1850
1851 send_message ( session, session->calls[call_index], _msg_starting,
1852 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1853 free_message ( _msg_starting );
1854 1619
1855 session->calls[call_index]->state = call_active; 1620 session->calls[call_index]->state = call_active;
1856 1621
1857 pthread_mutex_unlock(&session->mutex); 1622 pthread_mutex_unlock(&session->mutex);
1858 return 0; 1623 return 0;
1859} 1624}
@@ -1870,7 +1635,7 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type
1870int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1635int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1871{ 1636{
1872 pthread_mutex_lock(&session->mutex); 1637 pthread_mutex_lock(&session->mutex);
1873 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown"); 1638 LOGGER_DEBUG("Session: %p Canceling call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
1874 1639
1875 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1640 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1876 LOGGER_ERROR("Invalid call index!"); 1641 LOGGER_ERROR("Invalid call index!");
@@ -1878,12 +1643,18 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1878 return -1; 1643 return -1;
1879 } 1644 }
1880 1645
1881 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1646 MSIMessage *msg_cancel = msi_new_message ( TypeRequest, cancel );
1882 1647
1883 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason)); 1648#if 0
1649 if ( reason && strlen(reason) < sizeof(MSIReasonStrType) ) {
1650 MSIReasonStrType reason_cast = {0};
1651 memcpy(reason_cast, reason, strlen(reason));
1652 msi_msg_set_reason(msg_cancel, reason_cast);
1653 }
1654#endif
1884 1655
1885 send_message ( session, session->calls[call_index], _msg_cancel, peer ); 1656 send_message ( session, session->calls[call_index], msg_cancel, peer );
1886 free_message ( _msg_cancel ); 1657 free ( msg_cancel );
1887 1658
1888 /*session->calls[call_index]->state = call_hanged_up; 1659 /*session->calls[call_index]->state = call_hanged_up;
1889 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session, call_index, m_deftout );*/ 1660 session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session, call_index, m_deftout );*/
@@ -1901,7 +1672,7 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1901 * @param call_id To which call is this action handled. 1672 * @param call_id To which call is this action handled.
1902 * @return int 1673 * @return int
1903 */ 1674 */
1904int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason ) 1675int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1905{ 1676{
1906 pthread_mutex_lock(&session->mutex); 1677 pthread_mutex_lock(&session->mutex);
1907 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown"); 1678 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown");
@@ -1912,16 +1683,19 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1912 return -1; 1683 return -1;
1913 } 1684 }
1914 1685
1915 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1686 MSIMessage *msg_reject = msi_new_message ( TypeRequest, reject );
1916 1687
1917 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1688 if ( reason ) {
1689 MSIReasonStrType reason_cast = {0};
1690 memcpy(reason_cast, reason, strlen(reason));
1691 msi_msg_set_reason(msg_reject, reason_cast);
1692 }
1918 1693
1919 send_message ( session, session->calls[call_index], _msg_reject, 1694 send_message ( session, session->calls[call_index], msg_reject,
1920 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] ); 1695 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1921 free_message ( _msg_reject ); 1696 free ( msg_reject );
1922 1697
1923 session->calls[call_index]->state = call_hanged_up; 1698 session->calls[call_index]->state = call_hanged_up;
1924
1925 session->calls[call_index]->request_timer_id = 1699 session->calls[call_index]->request_timer_id =
1926 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1700 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout );
1927 1701
@@ -1931,6 +1705,57 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason
1931 1705
1932 1706
1933/** 1707/**
1708 * @brief Send invite request to friend_id.
1709 *
1710 * @param session Control session.
1711 * @param call_index Call index.
1712 * @param call_type Type of the call. Audio or Video(both audio and video)
1713 * @param rngsec Ringing timeout.
1714 * @param friend_id The friend.
1715 * @return int
1716 */
1717int msi_change_type(MSISession* session, int32_t call_index, MSICallType call_type)
1718{
1719 pthread_mutex_lock(&session->mutex);
1720
1721 LOGGER_DEBUG("Changing media on call: %d", call_index);
1722
1723 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1724 LOGGER_ERROR("Invalid call index!");
1725 pthread_mutex_unlock(&session->mutex);
1726 return -1;
1727 }
1728
1729 MSICall *call = session->calls[call_index];
1730 if ( call->state != call_active ) {
1731 LOGGER_ERROR("Call is not active!");
1732 pthread_mutex_unlock(&session->mutex);
1733 return -1;
1734 }
1735
1736 if ( call->type_local == call_type ) {
1737 LOGGER_ERROR("Call is already set to the requested type!");
1738 pthread_mutex_unlock(&session->mutex);
1739 return -1;
1740 }
1741
1742 call->type_local = call_type;
1743
1744 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1745
1746 msi_msg_set_calltype ( msg_invite, call_type );
1747 send_message ( session, call, msg_invite, call->peers[0] );
1748 free ( msg_invite );
1749
1750 LOGGER_DEBUG("Request for media change sent");
1751
1752 pthread_mutex_unlock(&session->mutex);
1753
1754 return 0;
1755}
1756
1757
1758/**
1934 * @brief Terminate the current call. 1759 * @brief Terminate the current call.
1935 * 1760 *
1936 * @param session Control session. 1761 * @param session Control session.