diff options
Diffstat (limited to 'toxav/msi.c')
-rw-r--r-- | toxav/msi.c | 703 |
1 files changed, 345 insertions, 358 deletions
diff --git a/toxav/msi.c b/toxav/msi.c index c1342950..cc855613 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -33,9 +33,11 @@ | |||
33 | #include <string.h> | 33 | #include <string.h> |
34 | #include <stdlib.h> | 34 | #include <stdlib.h> |
35 | #include <stdbool.h> | 35 | #include <stdbool.h> |
36 | #include <assert.h> | ||
36 | 37 | ||
37 | #define MSI_MAXMSG_SIZE 256 | 38 | #define MSI_MAXMSG_SIZE 256 |
38 | 39 | ||
40 | /* TODO send error on any calloc or etc */ | ||
39 | 41 | ||
40 | /** | 42 | /** |
41 | * Protocol: | 43 | * Protocol: |
@@ -63,14 +65,13 @@ typedef enum { | |||
63 | typedef enum { | 65 | typedef enum { |
64 | resp_ringing, | 66 | resp_ringing, |
65 | resp_starting, | 67 | resp_starting, |
66 | resp_error, | ||
67 | } MSIResponse; | 68 | } MSIResponse; |
68 | 69 | ||
69 | 70 | ||
70 | #define GENERIC_HEADER(header, val_type) \ | 71 | #define GENERIC_HEADER(header, val_type) \ |
71 | typedef struct { \ | 72 | typedef struct { \ |
72 | val_type value; \ | 73 | val_type value; \ |
73 | bool exists; \ | 74 | bool exists; \ |
74 | } MSIHeader##header | 75 | } MSIHeader##header |
75 | 76 | ||
76 | 77 | ||
@@ -92,7 +93,207 @@ typedef struct { | |||
92 | } MSIMessage; | 93 | } MSIMessage; |
93 | 94 | ||
94 | 95 | ||
95 | static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | 96 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); |
97 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); | ||
98 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ); | ||
99 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ); | ||
100 | static void invoke_callback(MSICall* call, MSICallbackID cb); | ||
101 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ); | ||
102 | MSICall *new_call ( MSISession *session, uint32_t friend_id ); | ||
103 | void kill_call ( MSICall *call ); | ||
104 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data); | ||
105 | int handle_recv_invite ( MSICall *call, const MSIMessage *msg ); | ||
106 | int handle_recv_start ( MSICall *call, const MSIMessage *msg ); | ||
107 | int handle_recv_reject ( MSICall *call, const MSIMessage *msg ); | ||
108 | int handle_recv_end ( MSICall *call, const MSIMessage *msg ); | ||
109 | int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ); | ||
110 | int handle_recv_starting ( MSICall *call, const MSIMessage *msg ); | ||
111 | int handle_recv_error ( MSICall *call, const MSIMessage *msg ); | ||
112 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ); | ||
113 | |||
114 | |||
115 | /** | ||
116 | * Public functions | ||
117 | */ | ||
118 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | ||
119 | { | ||
120 | session->callbacks[id] = callback; | ||
121 | } | ||
122 | MSISession *msi_new ( Messenger *messenger ) | ||
123 | { | ||
124 | if (messenger == NULL) { | ||
125 | LOGGER_ERROR("Could not init session on empty messenger!"); | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); | ||
130 | |||
131 | if (retu == NULL) { | ||
132 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | if (create_recursive_mutex(retu->mutex) != 0) { | ||
137 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | ||
138 | free(retu); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | retu->messenger = messenger; | ||
143 | |||
144 | m_callback_msi_packet(messenger, handle_msi_packet, retu ); | ||
145 | |||
146 | /* This is called when remote terminates session */ | ||
147 | m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu); | ||
148 | |||
149 | LOGGER_DEBUG("New msi session: %p ", retu); | ||
150 | return retu; | ||
151 | } | ||
152 | int msi_kill ( MSISession *session ) | ||
153 | { | ||
154 | if (session == NULL) { | ||
155 | LOGGER_ERROR("Tried to terminate non-existing session"); | ||
156 | return -1; | ||
157 | } | ||
158 | |||
159 | m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL); | ||
160 | pthread_mutex_lock(session->mutex); | ||
161 | |||
162 | if (session->calls) { | ||
163 | MSIMessage msg_end; | ||
164 | msg_end.request.exists = true; | ||
165 | msg_end.request.value = requ_end; | ||
166 | |||
167 | MSICall* it = get_call(session, session->calls_head); | ||
168 | for (; it; it = it->next) { | ||
169 | send_message(session->messenger, it->friend_id, &msg_end); | ||
170 | kill_call(it); /* This will eventually free session->calls */ | ||
171 | } | ||
172 | } | ||
173 | |||
174 | pthread_mutex_unlock(session->mutex); | ||
175 | pthread_mutex_destroy(session->mutex); | ||
176 | |||
177 | LOGGER_DEBUG("Terminated session: %p", session); | ||
178 | free ( session ); | ||
179 | return 0; | ||
180 | } | ||
181 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) | ||
182 | { | ||
183 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | ||
184 | |||
185 | if (get_call(session, friend_id) != NULL) { | ||
186 | LOGGER_ERROR("Already in a call"); | ||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | (*call) = new_call ( session, friend_id ); | ||
191 | |||
192 | if ( *call == NULL ) | ||
193 | return -1; | ||
194 | |||
195 | (*call)->self_capabilities = capabilities; | ||
196 | |||
197 | MSIMessage msg_invite; | ||
198 | msg_invite.request.exists = true; | ||
199 | msg_invite.request.value = requ_invite; | ||
200 | |||
201 | msg_invite.capabilities.exists = true; | ||
202 | msg_invite.capabilities.value = capabilities; | ||
203 | |||
204 | msg_invite.mvfsz.exists = true; | ||
205 | msg_invite.mvfsz.value = htons(D_MVFSZ); | ||
206 | |||
207 | msg_invite.mvfpsz.exists = true; | ||
208 | msg_invite.mvfpsz.value = htons(D_MVFPSZ); | ||
209 | |||
210 | send_message ( (*call)->session->messenger, (*call)->friend_id, &msg_invite ); | ||
211 | |||
212 | (*call)->state = msi_CallRequesting; | ||
213 | |||
214 | LOGGER_DEBUG("Invite sent"); | ||
215 | return 0; | ||
216 | } | ||
217 | int msi_hangup ( MSICall* call ) | ||
218 | { | ||
219 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); | ||
220 | |||
221 | MSIMessage msg_end; | ||
222 | msg_end.request.exists = true; | ||
223 | msg_end.request.value = requ_end; | ||
224 | send_message ( call->session->messenger, call->friend_id, &msg_end ); | ||
225 | |||
226 | kill_call(call); | ||
227 | return 0; | ||
228 | } | ||
229 | int msi_answer ( MSICall* call, uint8_t capabilities ) | ||
230 | { | ||
231 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); | ||
232 | |||
233 | if ( call->state != msi_CallRequested ) { | ||
234 | LOGGER_ERROR("Call is in invalid state!"); | ||
235 | return -1; | ||
236 | } | ||
237 | |||
238 | call->self_capabilities = capabilities; | ||
239 | |||
240 | MSIMessage msg_starting; | ||
241 | msg_starting.response.exists = true; | ||
242 | msg_starting.response.value = resp_starting; | ||
243 | |||
244 | msg_starting.capabilities.exists = true; | ||
245 | msg_starting.capabilities.value = capabilities; | ||
246 | |||
247 | msg_starting.mvfsz.exists = true; | ||
248 | msg_starting.mvfsz.value = htons(D_MVFSZ); | ||
249 | |||
250 | msg_starting.mvfpsz.exists = true; | ||
251 | msg_starting.mvfpsz.value = htons(D_MVFPSZ); | ||
252 | |||
253 | send_message ( call->session->messenger, call->friend_id, &msg_starting ); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | int msi_reject ( MSICall* call ) | ||
258 | { | ||
259 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | ||
260 | |||
261 | if ( call->state != msi_CallRequested ) { | ||
262 | LOGGER_ERROR("Call is in invalid state!"); | ||
263 | return -1; | ||
264 | } | ||
265 | |||
266 | MSIMessage msg_reject; | ||
267 | msg_reject.request.exists = true; | ||
268 | msg_reject.request.value = requ_reject; | ||
269 | |||
270 | send_message ( call->session->messenger, call->friend_id, &msg_reject ); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | int msi_change_csettings( MSICall* call, uint8_t capabilities ) | ||
275 | { | ||
276 | call->self_capabilities = capabilities; | ||
277 | |||
278 | MSIMessage msg_invite; | ||
279 | msg_invite.request.exists = true; | ||
280 | msg_invite.request.value = requ_invite; | ||
281 | |||
282 | msg_invite.capabilities.exists = true; | ||
283 | msg_invite.capabilities.value = capabilities; | ||
284 | |||
285 | send_message ( call->session->messenger, call->friend_id, &msg_invite ); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | |||
291 | |||
292 | /** | ||
293 | * Private functions | ||
294 | */ | ||
295 | |||
296 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | ||
96 | { | 297 | { |
97 | /* Parse raw data received from socket into MSIMessage struct */ | 298 | /* Parse raw data received from socket into MSIMessage struct */ |
98 | 299 | ||
@@ -116,10 +317,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
116 | } while(0) | 317 | } while(0) |
117 | 318 | ||
118 | 319 | ||
119 | if ( dest == NULL ) { | 320 | assert(dest); |
120 | LOGGER_ERROR("Could not parse message: no storage!"); | ||
121 | return -1; | ||
122 | } | ||
123 | 321 | ||
124 | if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ | 322 | if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ |
125 | LOGGER_ERROR("Invalid end byte"); | 323 | LOGGER_ERROR("Invalid end byte"); |
@@ -139,7 +337,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
139 | 337 | ||
140 | case IDResponse: | 338 | case IDResponse: |
141 | CHECK_SIZE(it, size_constraint, 1); | 339 | CHECK_SIZE(it, size_constraint, 1); |
142 | CHECK_ENUM_HIGH(it, resp_error); | 340 | CHECK_ENUM_HIGH(it, resp_starting); |
143 | SET_UINT8(it, dest->response); | 341 | SET_UINT8(it, dest->response); |
144 | it += 3; | 342 | it += 3; |
145 | break; | 343 | break; |
@@ -179,22 +377,13 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
179 | #undef SET_UINT8 | 377 | #undef SET_UINT8 |
180 | #undef SET_UINT16 | 378 | #undef SET_UINT16 |
181 | } | 379 | } |
182 | 380 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ) | |
183 | static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value, | ||
184 | uint8_t value_len, uint16_t *length ) | ||
185 | { | 381 | { |
186 | /* Parse a single header for sending */ | 382 | /* Parse a single header for sending */ |
383 | assert(dest); | ||
384 | assert(value); | ||
385 | assert(value_len); | ||
187 | 386 | ||
188 | if ( dest == NULL ) { | ||
189 | LOGGER_ERROR("No destination space!"); | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | if (value == NULL || value_len == 0) { | ||
194 | LOGGER_ERROR("Empty header value"); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | *dest = id; | 387 | *dest = id; |
199 | dest ++; | 388 | dest ++; |
200 | *dest = value_len; | 389 | *dest = value_len; |
@@ -206,20 +395,10 @@ static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value, | |||
206 | 395 | ||
207 | return dest + value_len; /* Set to next position ready to be written */ | 396 | return dest + value_len; /* Set to next position ready to be written */ |
208 | } | 397 | } |
209 | 398 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) | |
210 | |||
211 | |||
212 | static void call_invoke_callback(MSICall* call, MSICallbackID cb) | ||
213 | { | ||
214 | if ( call->session->callbacks[cb] ) { | ||
215 | LOGGER_DEBUG("Invoking callback function: %d", cb); | ||
216 | call->session->callbacks[cb] ( call->session->agent_handler, call ); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static int call_send_message ( MSICall *call, const MSIMessage *msg ) | ||
221 | { | 399 | { |
222 | /* Parse and send message */ | 400 | /* Parse and send message */ |
401 | assert(m); | ||
223 | 402 | ||
224 | uint8_t parsed [MSI_MAXMSG_SIZE]; | 403 | uint8_t parsed [MSI_MAXMSG_SIZE]; |
225 | 404 | ||
@@ -228,33 +407,33 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg ) | |||
228 | 407 | ||
229 | if (msg->request.exists) { | 408 | if (msg->request.exists) { |
230 | uint8_t cast = msg->request.value; | 409 | uint8_t cast = msg->request.value; |
231 | it = parse_header(IDRequest, it, &cast, | 410 | it = msg_parse_header_out(IDRequest, it, &cast, |
232 | sizeof(cast), &size); | 411 | sizeof(cast), &size); |
233 | } | 412 | } |
234 | 413 | ||
235 | if (msg->response.exists) { | 414 | if (msg->response.exists) { |
236 | uint8_t cast = msg->response.value; | 415 | uint8_t cast = msg->response.value; |
237 | it = parse_header(IDResponse, it, &cast, | 416 | it = msg_parse_header_out(IDResponse, it, &cast, |
238 | sizeof(cast), &size); | 417 | sizeof(cast), &size); |
239 | } | 418 | } |
240 | 419 | ||
241 | if (msg->error.exists) { | 420 | if (msg->error.exists) { |
242 | it = parse_header(IDError, it, &msg->error.value, | 421 | it = msg_parse_header_out(IDError, it, &msg->error.value, |
243 | sizeof(msg->error.value), &size); | 422 | sizeof(msg->error.value), &size); |
244 | } | 423 | } |
245 | 424 | ||
246 | if (msg->capabilities.exists) { | 425 | if (msg->capabilities.exists) { |
247 | it = parse_header(IDCapabilities, it, &msg->capabilities.value, | 426 | it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value, |
248 | sizeof(msg->capabilities.value), &size); | 427 | sizeof(msg->capabilities.value), &size); |
249 | } | 428 | } |
250 | 429 | ||
251 | if (msg->mvfsz.exists) { | 430 | if (msg->mvfsz.exists) { |
252 | it = parse_header(IDMVFSZ, it, &msg->mvfsz.value, | 431 | it = msg_parse_header_out(IDMVFSZ, it, &msg->mvfsz.value, |
253 | sizeof(msg->mvfsz.value), &size); | 432 | sizeof(msg->mvfsz.value), &size); |
254 | } | 433 | } |
255 | 434 | ||
256 | if (msg->mvfpsz.exists) { | 435 | if (msg->mvfpsz.exists) { |
257 | it = parse_header(IDMVFPSZ, it, &msg->mvfpsz.value, | 436 | it = msg_parse_header_out(IDMVFPSZ, it, &msg->mvfpsz.value, |
258 | sizeof(msg->mvfpsz.value), &size); | 437 | sizeof(msg->mvfpsz.value), &size); |
259 | } | 438 | } |
260 | 439 | ||
@@ -266,47 +445,50 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg ) | |||
266 | return -1; | 445 | return -1; |
267 | } | 446 | } |
268 | 447 | ||
269 | if ( m_msi_packet(call->session->messenger_handle, call->friend_id, parsed, size) ) { | 448 | if ( m_msi_packet(m, friend_id, parsed, size) ) { |
270 | LOGGER_DEBUG("Sent message"); | 449 | LOGGER_DEBUG("Sent message"); |
271 | return 0; | 450 | return 0; |
272 | } | 451 | } |
273 | 452 | ||
274 | return -1; | 453 | return -1; |
275 | } | 454 | } |
276 | 455 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ) | |
277 | static int call_send_error ( MSICall *call, MSIError error ) | ||
278 | { | 456 | { |
279 | /* Send error message */ | 457 | /* Send error message */ |
458 | assert(m); | ||
280 | 459 | ||
281 | if (!call) { | 460 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id); |
282 | LOGGER_WARNING("Cannot handle error on 'null' call"); | ||
283 | return -1; | ||
284 | } | ||
285 | |||
286 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, call->friend_id); | ||
287 | 461 | ||
288 | MSIMessage msg_error; | 462 | MSIMessage msg_error; |
289 | msg_error.response.exists = true; | ||
290 | msg_error.response.value = resp_error; | ||
291 | 463 | ||
292 | msg_error.error.exists = true; | 464 | msg_error.error.exists = true; |
293 | msg_error.error.value = error; | 465 | msg_error.error.value = error; |
294 | 466 | ||
295 | call_send_message ( call, &msg_error ); | 467 | send_message ( m, friend_id, &msg_error ); |
296 | return 0; | 468 | return 0; |
297 | } | 469 | } |
298 | 470 | static void invoke_callback(MSICall* call, MSICallbackID cb) | |
299 | 471 | { | |
472 | assert(call); | ||
473 | |||
474 | if ( call->session->callbacks[cb] ) { | ||
475 | LOGGER_DEBUG("Invoking callback function: %d", cb); | ||
476 | call->session->callbacks[cb] ( call->session->av, call ); | ||
477 | } | ||
478 | } | ||
300 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) | 479 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) |
301 | { | 480 | { |
481 | assert(session); | ||
482 | |||
302 | if (session->calls == NULL || session->calls_tail < friend_id) | 483 | if (session->calls == NULL || session->calls_tail < friend_id) |
303 | return NULL; | 484 | return NULL; |
304 | 485 | ||
305 | return session->calls[friend_id]; | 486 | return session->calls[friend_id]; |
306 | } | 487 | } |
307 | 488 | MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |
308 | static MSICall *new_call ( MSISession *session, uint32_t friend_id ) | ||
309 | { | 489 | { |
490 | assert(session); | ||
491 | |||
310 | MSICall *rc = calloc(sizeof(MSICall), 1); | 492 | MSICall *rc = calloc(sizeof(MSICall), 1); |
311 | 493 | ||
312 | if (rc == NULL) | 494 | if (rc == NULL) |
@@ -353,8 +535,7 @@ static MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |||
353 | session->calls[friend_id] = rc; | 535 | session->calls[friend_id] = rc; |
354 | return rc; | 536 | return rc; |
355 | } | 537 | } |
356 | 538 | void kill_call ( MSICall *call ) | |
357 | static void kill_call ( MSICall *call ) | ||
358 | { | 539 | { |
359 | if ( call == NULL ) | 540 | if ( call == NULL ) |
360 | return; | 541 | return; |
@@ -386,22 +567,21 @@ CLEAR: | |||
386 | session->calls = NULL; | 567 | session->calls = NULL; |
387 | free(call); | 568 | free(call); |
388 | } | 569 | } |
389 | 570 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) | |
390 | |||
391 | |||
392 | static void on_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p) | ||
393 | { | 571 | { |
394 | (void)messenger; | 572 | (void)m; |
395 | MSISession *session = session_p; | 573 | MSISession *session = data; |
396 | 574 | ||
397 | switch ( status ) { | 575 | switch ( status ) { |
398 | case 0: { /* Went offline */ | 576 | case 0: { /* Friend is now offline */ |
577 | LOGGER_DEBUG("Friend %d is now offline", friend_id); | ||
578 | |||
399 | MSICall* call = get_call(session, friend_id); | 579 | MSICall* call = get_call(session, friend_id); |
400 | 580 | ||
401 | if (call == NULL) | 581 | if (call == NULL) |
402 | return; | 582 | return; |
403 | 583 | ||
404 | call_invoke_callback(call, msi_OnPeerTimeout); | 584 | invoke_callback(call, msi_OnPeerTimeout); |
405 | kill_call(call); | 585 | kill_call(call); |
406 | } | 586 | } |
407 | break; | 587 | break; |
@@ -410,16 +590,9 @@ static void on_remote_connection_change(Messenger *messenger, int friend_id, uin | |||
410 | break; | 590 | break; |
411 | } | 591 | } |
412 | } | 592 | } |
413 | 593 | int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |
414 | |||
415 | |||
416 | /********** Request handlers **********/ | ||
417 | static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | ||
418 | { | 594 | { |
419 | if ( call == NULL ) { | 595 | assert(call); |
420 | LOGGER_WARNING("Session: %p Handling 'invite' on no call"); | ||
421 | return -1; | ||
422 | } | ||
423 | 596 | ||
424 | MSISession* session = call->session; | 597 | MSISession* session = call->session; |
425 | 598 | ||
@@ -427,19 +600,7 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
427 | 600 | ||
428 | if (!msg->capabilities.exists) { | 601 | if (!msg->capabilities.exists) { |
429 | LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); | 602 | LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); |
430 | /* TODO send error */ | 603 | call->error = msi_InvalidMessage; |
431 | return -1; | ||
432 | } | ||
433 | |||
434 | if (!msg->mvfsz.exists) { | ||
435 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
436 | /* TODO send error */ | ||
437 | return -1; | ||
438 | } | ||
439 | |||
440 | if (!msg->mvfpsz.exists) { | ||
441 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
442 | /* TODO send error */ | ||
443 | return -1; | 604 | return -1; |
444 | } | 605 | } |
445 | 606 | ||
@@ -456,14 +617,32 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
456 | 617 | ||
457 | LOGGER_DEBUG("Glare detected!"); | 618 | LOGGER_DEBUG("Glare detected!"); |
458 | 619 | ||
459 | call->peer_capabilities = msg->capabilities; | 620 | if (!msg->mvfsz.exists) { |
621 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
622 | call->error = msi_InvalidMessage; | ||
623 | return -1; | ||
624 | } | ||
625 | |||
626 | if (!msg->mvfpsz.exists) { | ||
627 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
628 | call->error = msi_InvalidMessage; | ||
629 | return -1; | ||
630 | } | ||
631 | |||
632 | call->peer_capabilities = msg->capabilities.value; | ||
460 | 633 | ||
461 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 634 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
462 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 635 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
463 | 636 | ||
637 | if (call->peer_mvfsz > call->peer_mvfpsz) { | ||
638 | LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'"); | ||
639 | call->error = msi_InvalidParam; | ||
640 | return -1; | ||
641 | } | ||
642 | |||
464 | /* Send response */ | 643 | /* Send response */ |
465 | response.response.value = resp_starting; | 644 | response.response.value = resp_starting; |
466 | call_send_message ( call, &response ); | 645 | send_message ( call->session->messenger, call->friend_id, &response ); |
467 | 646 | ||
468 | return 0; | 647 | return 0; |
469 | } else if ( call->state == msi_CallActive ) { | 648 | } else if ( call->state == msi_CallActive ) { |
@@ -473,21 +652,33 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
473 | */ | 652 | */ |
474 | LOGGER_DEBUG("Peer is changing capabilities"); | 653 | LOGGER_DEBUG("Peer is changing capabilities"); |
475 | 654 | ||
476 | call->peer_capabilities = msg->capabilities; | ||
477 | |||
478 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | ||
479 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | ||
480 | |||
481 | /* Send response */ | 655 | /* Send response */ |
482 | response.response.value = resp_starting; | 656 | response.response.value = resp_starting; |
483 | call_send_message ( call, &response ); | 657 | send_message ( call->session->messenger, call->friend_id, &response ); |
484 | 658 | ||
659 | if ( call->peer_capabilities != msg->capabilities.value) { | ||
660 | /* Only invoke callback if capabilities changed */ | ||
661 | call->peer_capabilities = msg->capabilities.value; | ||
662 | invoke_callback(call, msi_OnCapabilities); | ||
663 | } | ||
485 | 664 | ||
486 | call_invoke_callback(call, msi_OnCapabilities); | ||
487 | return 0; | 665 | return 0; |
488 | } | 666 | } |
489 | 667 | ||
490 | call->peer_capabilities = msg->capabilities; | 668 | |
669 | if (!msg->mvfsz.exists) { | ||
670 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
671 | call->error = msi_InvalidMessage; | ||
672 | return -1; | ||
673 | } | ||
674 | |||
675 | if (!msg->mvfpsz.exists) { | ||
676 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
677 | call->error = msi_InvalidMessage; | ||
678 | return -1; | ||
679 | } | ||
680 | |||
681 | call->peer_capabilities = msg->capabilities.value; | ||
491 | 682 | ||
492 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 683 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
493 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 684 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
@@ -496,23 +687,19 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
496 | 687 | ||
497 | /* Send response */ | 688 | /* Send response */ |
498 | response.response.value = resp_ringing; | 689 | response.response.value = resp_ringing; |
499 | call_send_message ( call, &response ); | 690 | send_message ( call->session->messenger, call->friend_id, &response ); |
500 | 691 | ||
501 | 692 | ||
502 | call_invoke_callback(call, msi_OnInvite); | 693 | invoke_callback(call, msi_OnInvite); |
503 | return 0; | 694 | return 0; |
504 | } | 695 | } |
505 | 696 | int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | |
506 | static int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | ||
507 | { | 697 | { |
508 | if ( call == NULL ) { | 698 | assert(call); |
509 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
510 | return -1; | ||
511 | } | ||
512 | 699 | ||
513 | if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { | 700 | if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { |
514 | LOGGER_WARNING("Session: %p Invalid call state on 'start'"); | 701 | LOGGER_WARNING("Session: %p Invalid call state on 'start'"); |
515 | /* TODO send error */ | 702 | call->error = msi_InvalidState; |
516 | return -1; | 703 | return -1; |
517 | } | 704 | } |
518 | 705 | ||
@@ -521,105 +708,88 @@ static int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | |||
521 | LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); | 708 | LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); |
522 | 709 | ||
523 | call->state = msi_CallActive; | 710 | call->state = msi_CallActive; |
524 | call_invoke_callback(call, msi_OnStart); | 711 | invoke_callback(call, msi_OnStart); |
525 | 712 | ||
526 | return 0; | 713 | return 0; |
527 | } | 714 | } |
528 | 715 | int handle_recv_reject ( MSICall *call, const MSIMessage *msg ) | |
529 | static int handle_recv_reject ( MSICall *call, const MSIMessage *msg ) | ||
530 | { | 716 | { |
531 | if ( call == NULL ) { | 717 | assert(call); |
532 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
533 | return -1; | ||
534 | } | ||
535 | 718 | ||
536 | (void)msg; | 719 | (void)msg; |
537 | 720 | ||
538 | if ( call->state != msi_CallRequesting ) { | 721 | if ( call->state != msi_CallRequesting ) { |
539 | LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); | 722 | LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); |
540 | /* TODO send error */ | 723 | call->error = msi_InvalidState; |
541 | return -1; | 724 | return -1; |
542 | } | 725 | } |
543 | 726 | ||
544 | LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); | 727 | LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); |
545 | 728 | ||
546 | call_invoke_callback(call, msi_OnReject); | 729 | invoke_callback(call, msi_OnReject); |
547 | kill_call(call); | 730 | kill_call(call); |
548 | 731 | ||
549 | return 0; | 732 | return 0; |
550 | } | 733 | } |
551 | 734 | int handle_recv_end ( MSICall *call, const MSIMessage *msg ) | |
552 | static int handle_recv_end ( MSICall *call, const MSIMessage *msg ) | ||
553 | { | 735 | { |
554 | (void)msg; | 736 | assert(call); |
555 | 737 | ||
556 | if ( call == NULL ) { | 738 | (void)msg; |
557 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
558 | return -1; | ||
559 | } | ||
560 | 739 | ||
561 | LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); | 740 | LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); |
562 | 741 | ||
563 | call_invoke_callback(call, msi_OnEnd); | 742 | invoke_callback(call, msi_OnEnd); |
564 | kill_call ( call ); | 743 | kill_call ( call ); |
565 | 744 | ||
566 | return 0; | 745 | return 0; |
567 | } | 746 | } |
568 | 747 | int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ) | |
569 | /********** Response handlers **********/ | ||
570 | static int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ) | ||
571 | { | 748 | { |
572 | if ( call == NULL ) { | 749 | assert(call); |
573 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
574 | return -1; | ||
575 | } | ||
576 | 750 | ||
577 | (void)msg; | 751 | (void)msg; |
578 | 752 | ||
579 | if ( call->state != msi_CallRequesting ) { | 753 | if ( call->state != msi_CallRequesting ) { |
580 | LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); | 754 | LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); |
581 | /* TODO send error */ | 755 | call->error = msi_InvalidState; |
582 | return -1; | 756 | return -1; |
583 | } | 757 | } |
584 | 758 | ||
585 | LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); | 759 | LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); |
586 | 760 | ||
587 | call_invoke_callback(call, msi_OnRinging); | 761 | invoke_callback(call, msi_OnRinging); |
588 | return 0; | 762 | return 0; |
589 | } | 763 | } |
590 | 764 | int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |
591 | static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | ||
592 | { | 765 | { |
593 | if ( call == NULL ) { | 766 | assert(call); |
594 | LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call"); | ||
595 | return 0; | ||
596 | } | ||
597 | 767 | ||
598 | if ( call->state == msi_CallActive ) { | 768 | if ( call->state == msi_CallActive ) { |
599 | LOGGER_DEBUG("Capabilities change confirmed"); | 769 | LOGGER_DEBUG("Capabilities change confirmed"); |
600 | return 0; | 770 | return 0; |
601 | } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { | 771 | } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { |
602 | LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); | 772 | LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); |
603 | /* TODO send error */ | 773 | call->error = msi_InvalidState; |
604 | return -1; | 774 | return -1; |
605 | } | 775 | } |
606 | 776 | ||
607 | if (call->state == msi_CallRequesting) { | 777 | if (call->state == msi_CallRequesting) { |
608 | if (!msg->capabilities.exists) { | 778 | if (!msg->capabilities.exists) { |
609 | LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); | 779 | LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); |
610 | /* TODO send error */ | 780 | call->error = msi_InvalidParam; |
611 | return -1; | 781 | return -1; |
612 | } | 782 | } |
613 | 783 | ||
614 | if (!msg->mvfsz.exists) { | 784 | if (!msg->mvfsz.exists) { |
615 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | 785 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); |
616 | /* TODO send error */ | 786 | call->error = msi_InvalidParam; |
617 | return -1; | 787 | return -1; |
618 | } | 788 | } |
619 | 789 | ||
620 | if (!msg->mvfpsz.exists) { | 790 | if (!msg->mvfpsz.exists) { |
621 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | 791 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); |
622 | /* TODO send error */ | 792 | call->error = msi_InvalidParam; |
623 | return -1; | 793 | return -1; |
624 | } | 794 | } |
625 | 795 | ||
@@ -628,8 +798,15 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |||
628 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 798 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
629 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 799 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
630 | 800 | ||
801 | |||
802 | if (call->peer_mvfsz > call->peer_mvfpsz) { | ||
803 | LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'"); | ||
804 | call->error = msi_InvalidParam; | ||
805 | return -1; | ||
806 | } | ||
807 | |||
631 | call->state = msi_CallActive; | 808 | call->state = msi_CallActive; |
632 | call_invoke_callback(call, msi_OnStart); | 809 | invoke_callback(call, msi_OnStart); |
633 | } | 810 | } |
634 | /* Otherwise it's a glare case so don't start until 'start' is recved */ | 811 | /* Otherwise it's a glare case so don't start until 'start' is recved */ |
635 | 812 | ||
@@ -637,65 +814,55 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |||
637 | MSIMessage msg_start; | 814 | MSIMessage msg_start; |
638 | msg_start.request.exists = true; | 815 | msg_start.request.exists = true; |
639 | msg_start.request.value = requ_start; | 816 | msg_start.request.value = requ_start; |
640 | call_send_message ( call, &msg_start ); | 817 | send_message ( call->session->messenger, call->friend_id, &msg_start ); |
641 | 818 | ||
642 | return 0; | 819 | return 0; |
643 | } | 820 | } |
644 | 821 | int handle_recv_error ( MSICall *call, const MSIMessage *msg ) | |
645 | static int handle_recv_error ( MSICall *call, const MSIMessage *msg ) | ||
646 | { | 822 | { |
647 | if ( call == NULL ) { | 823 | assert(call); |
648 | LOGGER_WARNING("Handling 'error' on non-existing call!"); | ||
649 | return -1; | ||
650 | } | ||
651 | 824 | ||
652 | LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); | 825 | LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); |
826 | |||
827 | call->error = msg->error.value; | ||
828 | invoke_callback(call, msi_OnError); | ||
653 | 829 | ||
654 | call_invoke_callback(call, msi_OnError); | 830 | return 0; |
655 | |||
656 | /* TODO Handle error accordingly */ | ||
657 | |||
658 | return -1; | ||
659 | } | 831 | } |
660 | 832 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) | |
661 | static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8_t *data, | ||
662 | uint16_t length, void *object ) | ||
663 | { | 833 | { |
664 | LOGGER_DEBUG("Got msi message"); | 834 | LOGGER_DEBUG("Got msi message"); |
665 | 835 | ||
666 | /* Unused */ | ||
667 | (void)messenger; | ||
668 | |||
669 | MSISession *session = object; | 836 | MSISession *session = object; |
670 | MSIMessage msg; | 837 | MSIMessage msg; |
838 | |||
839 | int rc = 0; | ||
671 | 840 | ||
672 | if ( parse_input ( &msg, data, length ) == -1 ) { | 841 | if ( msg_parse_in ( &msg, data, length ) == -1 ) { |
673 | LOGGER_WARNING("Error parsing message"); | 842 | LOGGER_WARNING("Error parsing message"); |
843 | send_error(m, friend_id, msi_InvalidMessage); | ||
674 | return; | 844 | return; |
675 | } else { | 845 | } else { |
676 | LOGGER_DEBUG("Successfully parsed message"); | 846 | LOGGER_DEBUG("Successfully parsed message"); |
677 | } | 847 | } |
678 | 848 | ||
679 | pthread_mutex_lock(session->mutex); | ||
680 | |||
681 | MSICall *call = get_call(session, friend_id); | 849 | MSICall *call = get_call(session, friend_id); |
682 | 850 | ||
683 | if (call == NULL) { | 851 | if (call == NULL) { |
684 | if (msg.request != requ_invite) { | 852 | if (msg.request.value != requ_invite) { |
685 | /* TODO send error */ | 853 | send_error(m, friend_id, msi_StrayMessage); |
686 | return; | 854 | return; |
687 | } | 855 | } |
688 | 856 | ||
689 | call = new_call(session, friend_id); | 857 | call = new_call(session, friend_id); |
690 | if (call == NULL) { | 858 | if (call == NULL) { |
691 | /* TODO send error */ | 859 | send_error(m, friend_id, msi_SystemError); |
692 | return; | 860 | return; |
693 | } | 861 | } |
694 | } | 862 | } |
695 | 863 | ||
696 | 864 | ||
697 | /* Now handle message */ | 865 | /* Now handle message */ |
698 | int rc = 0; | ||
699 | if ( msg.request.exists ) { /* Handle request */ | 866 | if ( msg.request.exists ) { /* Handle request */ |
700 | switch (msg.request.value) { | 867 | switch (msg.request.value) { |
701 | case requ_invite: | 868 | case requ_invite: |
@@ -723,201 +890,21 @@ static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8 | |||
723 | case resp_starting: | 890 | case resp_starting: |
724 | rc = handle_recv_starting ( call, &msg ); | 891 | rc = handle_recv_starting ( call, &msg ); |
725 | break; | 892 | break; |
726 | |||
727 | case resp_error: | ||
728 | rc = handle_recv_error ( call, &msg ); | ||
729 | break; | ||
730 | } | 893 | } |
894 | } else if (msg.error.exists) { | ||
895 | handle_recv_error ( call, &msg ); | ||
896 | rc = -1; | ||
731 | } else { | 897 | } else { |
732 | LOGGER_WARNING("Invalid message: no resp nor requ headers"); | 898 | LOGGER_WARNING("Invalid message; none of the request, response or error!"); |
733 | /* TODO send error */ | 899 | call->error = msi_InvalidMessage; |
734 | rc = -1; | 900 | rc = -1; |
735 | } | 901 | } |
736 | 902 | ||
737 | if (rc == -1) | ||
738 | kill_call(call); | ||
739 | 903 | ||
740 | pthread_mutex_unlock(session->mutex); | 904 | if (rc == -1) { |
741 | } | 905 | if (call->error != msi_ErrorNone) |
742 | 906 | send_error(m, friend_id, call->error); | |
743 | |||
744 | |||
745 | /********** User functions **********/ | ||
746 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | ||
747 | { | ||
748 | session->callbacks[id] = callback; | ||
749 | } | ||
750 | |||
751 | MSISession *msi_new ( Messenger *messenger ) | ||
752 | { | ||
753 | if (messenger == NULL) { | ||
754 | LOGGER_ERROR("Could not init session on empty messenger!"); | ||
755 | return NULL; | ||
756 | } | ||
757 | |||
758 | MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); | ||
759 | |||
760 | if (retu == NULL) { | ||
761 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
762 | return NULL; | ||
763 | } | ||
764 | |||
765 | if (create_recursive_mutex(retu->mutex) != 0) { | ||
766 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | ||
767 | free(retu); | ||
768 | return NULL; | ||
769 | } | ||
770 | |||
771 | retu->messenger_handle = messenger; | ||
772 | |||
773 | m_callback_msi_packet(messenger, handle_msi_packet, retu ); | ||
774 | |||
775 | /* This is called when remote terminates session */ | ||
776 | m_callback_connectionstatus_internal_av(messenger, on_remote_connection_change, retu); | ||
777 | |||
778 | LOGGER_DEBUG("New msi session: %p ", retu); | ||
779 | return retu; | ||
780 | } | ||
781 | |||
782 | int msi_kill ( MSISession *session ) | ||
783 | { | ||
784 | if (session == NULL) { | ||
785 | LOGGER_ERROR("Tried to terminate non-existing session"); | ||
786 | return -1; | ||
787 | } | ||
788 | |||
789 | m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); | ||
790 | pthread_mutex_lock(session->mutex); | ||
791 | |||
792 | if (session->calls) { | ||
793 | MSIMessage msg_end; | ||
794 | msg_end.request.exists = true; | ||
795 | msg_end.request.value = requ_end; | ||
796 | 907 | ||
797 | MSICall* it = get_call(session, session->calls_head); | 908 | kill_call(call); |
798 | for (; it; it = it->next) { | ||
799 | call_send_message(it, &msg_end); | ||
800 | kill_call(it); /* This will eventually free session->calls */ | ||
801 | } | ||
802 | } | ||
803 | |||
804 | pthread_mutex_unlock(session->mutex); | ||
805 | pthread_mutex_destroy(session->mutex); | ||
806 | |||
807 | LOGGER_DEBUG("Terminated session: %p", session); | ||
808 | free ( session ); | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) | ||
813 | { | ||
814 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | ||
815 | |||
816 | if (get_call(session, friend_id) != NULL) { | ||
817 | LOGGER_ERROR("Already in a call"); | ||
818 | return -1; | ||
819 | } | ||
820 | |||
821 | *call = new_call ( session, friend_id ); | ||
822 | |||
823 | if ( *call == NULL ) | ||
824 | return -1; | ||
825 | |||
826 | *call->self_capabilities = capabilities; | ||
827 | |||
828 | MSIMessage msg_invite; | ||
829 | msg_invite.request.exists = true; | ||
830 | msg_invite.request.value = requ_invite; | ||
831 | |||
832 | msg_invite.capabilities.exists = true; | ||
833 | msg_invite.capabilities.value = capabilities; | ||
834 | |||
835 | msg_invite.mvfsz.exists = true; | ||
836 | msg_invite.mvfsz.value = htons(D_MVFSZ); | ||
837 | |||
838 | msg_invite.mvfpsz.exists = true; | ||
839 | msg_invite.mvfpsz.value = htons(D_MVFPSZ); | ||
840 | |||
841 | call_send_message ( *call, &msg_invite ); | ||
842 | |||
843 | *call->state = msi_CallRequesting; | ||
844 | |||
845 | LOGGER_DEBUG("Invite sent"); | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | int msi_hangup ( MSICall* call ) | ||
850 | { | ||
851 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); | ||
852 | |||
853 | MSIMessage msg_end; | ||
854 | msg_end.request.exists = true; | ||
855 | msg_end.request.value = requ_end; | ||
856 | call_send_message ( call, &msg_end ); | ||
857 | |||
858 | kill_call(call); | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | int msi_answer ( MSICall* call, uint8_t capabilities ) | ||
863 | { | ||
864 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); | ||
865 | |||
866 | if ( call->state != msi_CallRequested ) { | ||
867 | LOGGER_ERROR("Call is in invalid state!"); | ||
868 | return -1; | ||
869 | } | ||
870 | |||
871 | call->self_capabilities = capabilities; | ||
872 | |||
873 | MSIMessage msg_starting; | ||
874 | msg_starting.response.exists = true; | ||
875 | msg_starting.response.value = resp_starting; | ||
876 | |||
877 | msg_starting.capabilities.exists = true; | ||
878 | msg_starting.capabilities.value = capabilities; | ||
879 | |||
880 | msg_starting.mvfsz.exists = true; | ||
881 | msg_starting.mvfsz.value = htons(D_MVFSZ); | ||
882 | |||
883 | msg_starting.mvfpsz.exists = true; | ||
884 | msg_starting.mvfpsz.value = htons(D_MVFPSZ); | ||
885 | |||
886 | call_send_message ( call, &msg_starting ); | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | int msi_reject ( MSICall* call ) | ||
892 | { | ||
893 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | ||
894 | |||
895 | if ( call->state != msi_CallRequested ) { | ||
896 | LOGGER_ERROR("Call is in invalid state!"); | ||
897 | return -1; | ||
898 | } | 909 | } |
899 | |||
900 | MSIMessage msg_reject; | ||
901 | msg_reject.request.exists = true; | ||
902 | msg_reject.request.value = requ_reject; | ||
903 | |||
904 | call_send_message ( call, &msg_reject ); | ||
905 | |||
906 | return 0; | ||
907 | } | 910 | } |
908 | |||
909 | int msi_change_csettings( MSICall* call, uint8_t capabilities ) | ||
910 | { | ||
911 | call->self_capabilities = capabilities; | ||
912 | |||
913 | MSIMessage msg_invite; | ||
914 | msg_invite.request.exists = true; | ||
915 | msg_invite.request.value = requ_invite; | ||
916 | |||
917 | msg_invite.capabilities.exists = true; | ||
918 | msg_invite.capabilities.value = capabilities; | ||
919 | |||
920 | call_send_message ( *call, &msg_invite ); | ||
921 | |||
922 | return 0; | ||
923 | } \ No newline at end of file | ||