diff options
Diffstat (limited to 'toxav/msi.c')
-rw-r--r-- | toxav/msi.c | 105 |
1 files changed, 63 insertions, 42 deletions
diff --git a/toxav/msi.c b/toxav/msi.c index dd9f5fba..41f33c7f 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -40,33 +40,37 @@ | |||
40 | * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}| | 40 | * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}| |
41 | */ | 41 | */ |
42 | 42 | ||
43 | typedef enum { | 43 | typedef enum MSIHeaderID { |
44 | ID_REQUEST = 1, | 44 | ID_REQUEST = 1, |
45 | ID_ERROR, | 45 | ID_ERROR, |
46 | ID_CAPABILITIES, | 46 | ID_CAPABILITIES, |
47 | } MSIHeaderID; | 47 | } MSIHeaderID; |
48 | 48 | ||
49 | 49 | ||
50 | typedef enum { | 50 | typedef enum MSIRequest { |
51 | REQU_INIT, | 51 | REQU_INIT, |
52 | REQU_PUSH, | 52 | REQU_PUSH, |
53 | REQU_POP, | 53 | REQU_POP, |
54 | } MSIRequest; | 54 | } MSIRequest; |
55 | 55 | ||
56 | 56 | ||
57 | #define GENERIC_HEADER(header, val_type) \ | 57 | typedef struct MSIHeaderRequest { |
58 | typedef struct { \ | 58 | MSIRequest value; |
59 | val_type value; \ | 59 | bool exists; |
60 | bool exists; \ | 60 | } MSIHeaderRequest; |
61 | } MSIHeader##header | ||
62 | 61 | ||
62 | typedef struct MSIHeaderError { | ||
63 | MSIError value; | ||
64 | bool exists; | ||
65 | } MSIHeaderError; | ||
63 | 66 | ||
64 | GENERIC_HEADER(Request, MSIRequest); | 67 | typedef struct MSIHeaderCapabilities { |
65 | GENERIC_HEADER(Error, MSIError); | 68 | uint8_t value; |
66 | GENERIC_HEADER(Capabilities, uint8_t); | 69 | bool exists; |
70 | } MSIHeaderCapabilities; | ||
67 | 71 | ||
68 | 72 | ||
69 | typedef struct { | 73 | typedef struct MSIMessage { |
70 | MSIHeaderRequest request; | 74 | MSIHeaderRequest request; |
71 | MSIHeaderError error; | 75 | MSIHeaderError error; |
72 | MSIHeaderCapabilities capabilities; | 76 | MSIHeaderCapabilities capabilities; |
@@ -185,14 +189,14 @@ int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint | |||
185 | return -1; | 189 | return -1; |
186 | } | 190 | } |
187 | 191 | ||
188 | (*call) = new_call(session, friend_number); | 192 | MSICall *temp = new_call(session, friend_number); |
189 | 193 | ||
190 | if (*call == nullptr) { | 194 | if (temp == nullptr) { |
191 | pthread_mutex_unlock(session->mutex); | 195 | pthread_mutex_unlock(session->mutex); |
192 | return -1; | 196 | return -1; |
193 | } | 197 | } |
194 | 198 | ||
195 | (*call)->self_capabilities = capabilities; | 199 | temp->self_capabilities = capabilities; |
196 | 200 | ||
197 | MSIMessage msg; | 201 | MSIMessage msg; |
198 | msg_init(&msg, REQU_INIT); | 202 | msg_init(&msg, REQU_INIT); |
@@ -200,9 +204,11 @@ int msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint | |||
200 | msg.capabilities.exists = true; | 204 | msg.capabilities.exists = true; |
201 | msg.capabilities.value = capabilities; | 205 | msg.capabilities.value = capabilities; |
202 | 206 | ||
203 | send_message((*call)->session->messenger, (*call)->friend_number, &msg); | 207 | send_message(temp->session->messenger, temp->friend_number, &msg); |
204 | 208 | ||
205 | (*call)->state = MSI_CALL_REQUESTING; | 209 | temp->state = MSI_CALL_REQUESTING; |
210 | |||
211 | *call = temp; | ||
206 | 212 | ||
207 | LOGGER_DEBUG(session->messenger->log, "Invite sent"); | 213 | LOGGER_DEBUG(session->messenger->log, "Invite sent"); |
208 | pthread_mutex_unlock(session->mutex); | 214 | pthread_mutex_unlock(session->mutex); |
@@ -328,18 +334,27 @@ int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint1 | |||
328 | { | 334 | { |
329 | /* Parse raw data received from socket into MSIMessage struct */ | 335 | /* Parse raw data received from socket into MSIMessage struct */ |
330 | 336 | ||
331 | #define CHECK_SIZE(bytes, constraint, size) \ | 337 | #define CHECK_SIZE(bytes, constraint, size) \ |
332 | if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR(log, "Read over length!"); return -1; } \ | 338 | do { \ |
333 | if (bytes[1] != size) { LOGGER_ERROR(log, "Invalid data size!"); return -1; } | 339 | constraint -= 2 + size; \ |
334 | 340 | if (constraint < 1) { \ | |
335 | #define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \ | 341 | LOGGER_ERROR(log, "Read over length!"); \ |
336 | if (bytes[2] > enum_high) { LOGGER_ERROR(log, "Failed enum high limit!"); return -1; } | 342 | return -1; \ |
337 | 343 | } \ | |
338 | #define SET_UINT8(type, bytes, header) do { \ | 344 | if (bytes[1] != size) { \ |
339 | header.value = (type)bytes[2]; \ | 345 | LOGGER_ERROR(log, "Invalid data size!"); \ |
340 | header.exists = true; \ | 346 | return -1; \ |
341 | bytes += 3; \ | 347 | } \ |
342 | } while(0) | 348 | } while (0) |
349 | |||
350 | /* Assumes size == 1 */ | ||
351 | #define CHECK_ENUM_HIGH(bytes, enum_high) \ | ||
352 | do { \ | ||
353 | if (bytes[2] > enum_high) { \ | ||
354 | LOGGER_ERROR(log, "Failed enum high limit!"); \ | ||
355 | return -1; \ | ||
356 | } \ | ||
357 | } while (0) | ||
343 | 358 | ||
344 | assert(dest); | 359 | assert(dest); |
345 | 360 | ||
@@ -358,18 +373,24 @@ int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint1 | |||
358 | case ID_REQUEST: | 373 | case ID_REQUEST: |
359 | CHECK_SIZE(it, size_constraint, 1); | 374 | CHECK_SIZE(it, size_constraint, 1); |
360 | CHECK_ENUM_HIGH(it, REQU_POP); | 375 | CHECK_ENUM_HIGH(it, REQU_POP); |
361 | SET_UINT8(MSIRequest, it, dest->request); | 376 | dest->request.value = (MSIRequest)it[2]; |
377 | dest->request.exists = true; | ||
378 | it += 3; | ||
362 | break; | 379 | break; |
363 | 380 | ||
364 | case ID_ERROR: | 381 | case ID_ERROR: |
365 | CHECK_SIZE(it, size_constraint, 1); | 382 | CHECK_SIZE(it, size_constraint, 1); |
366 | CHECK_ENUM_HIGH(it, MSI_E_UNDISCLOSED); | 383 | CHECK_ENUM_HIGH(it, MSI_E_UNDISCLOSED); |
367 | SET_UINT8(MSIError, it, dest->error); | 384 | dest->error.value = (MSIError)it[2]; |
385 | dest->error.exists = true; | ||
386 | it += 3; | ||
368 | break; | 387 | break; |
369 | 388 | ||
370 | case ID_CAPABILITIES: | 389 | case ID_CAPABILITIES: |
371 | CHECK_SIZE(it, size_constraint, 1); | 390 | CHECK_SIZE(it, size_constraint, 1); |
372 | SET_UINT8(uint8_t, it, dest->capabilities); | 391 | dest->capabilities.value = it[2]; |
392 | dest->capabilities.exists = true; | ||
393 | it += 3; | ||
373 | break; | 394 | break; |
374 | 395 | ||
375 | default: | 396 | default: |
@@ -383,11 +404,10 @@ int msg_parse_in(const Logger *log, MSIMessage *dest, const uint8_t *data, uint1 | |||
383 | return -1; | 404 | return -1; |
384 | } | 405 | } |
385 | 406 | ||
386 | return 0; | ||
387 | |||
388 | #undef CHECK_SIZE | ||
389 | #undef CHECK_ENUM_HIGH | 407 | #undef CHECK_ENUM_HIGH |
390 | #undef SET_UINT8 | 408 | #undef CHECK_SIZE |
409 | |||
410 | return 0; | ||
391 | } | 411 | } |
392 | uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length) | 412 | uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length) |
393 | { | 413 | { |
@@ -397,9 +417,9 @@ uint8_t *msg_parse_header_out(MSIHeaderID id, uint8_t *dest, const void *value, | |||
397 | assert(value_len); | 417 | assert(value_len); |
398 | 418 | ||
399 | *dest = id; | 419 | *dest = id; |
400 | dest ++; | 420 | ++dest; |
401 | *dest = value_len; | 421 | *dest = value_len; |
402 | dest ++; | 422 | ++dest; |
403 | 423 | ||
404 | memcpy(dest, value, value_len); | 424 | memcpy(dest, value, value_len); |
405 | 425 | ||
@@ -443,7 +463,7 @@ int send_message(Messenger *m, uint32_t friend_number, const MSIMessage *msg) | |||
443 | } | 463 | } |
444 | 464 | ||
445 | *it = 0; | 465 | *it = 0; |
446 | size ++; | 466 | ++size; |
447 | 467 | ||
448 | if (m_msi_packet(m, friend_number, parsed, size)) { | 468 | if (m_msi_packet(m, friend_number, parsed, size)) { |
449 | LOGGER_DEBUG(m->log, "Sent message"); | 469 | LOGGER_DEBUG(m->log, "Sent message"); |
@@ -526,7 +546,8 @@ MSICall *new_call(MSISession *session, uint32_t friend_number) | |||
526 | return nullptr; | 546 | return nullptr; |
527 | } | 547 | } |
528 | 548 | ||
529 | session->calls_tail = session->calls_head = friend_number; | 549 | session->calls_tail = friend_number; |
550 | session->calls_head = friend_number; | ||
530 | } else if (session->calls_tail < friend_number) { /* Appending */ | 551 | } else if (session->calls_tail < friend_number) { /* Appending */ |
531 | MSICall **tmp = (MSICall **)realloc(session->calls, sizeof(MSICall *) * (friend_number + 1)); | 552 | MSICall **tmp = (MSICall **)realloc(session->calls, sizeof(MSICall *) * (friend_number + 1)); |
532 | 553 | ||
@@ -540,7 +561,7 @@ MSICall *new_call(MSISession *session, uint32_t friend_number) | |||
540 | /* Set fields in between to null */ | 561 | /* Set fields in between to null */ |
541 | uint32_t i = session->calls_tail + 1; | 562 | uint32_t i = session->calls_tail + 1; |
542 | 563 | ||
543 | for (; i < friend_number; i ++) { | 564 | for (; i < friend_number; ++i) { |
544 | session->calls[i] = nullptr; | 565 | session->calls[i] = nullptr; |
545 | } | 566 | } |
546 | 567 | ||
@@ -592,14 +613,14 @@ void kill_call(MSICall *call) | |||
592 | return; | 613 | return; |
593 | 614 | ||
594 | CLEAR_CONTAINER: | 615 | CLEAR_CONTAINER: |
595 | session->calls_head = session->calls_tail = 0; | 616 | session->calls_head = 0; |
617 | session->calls_tail = 0; | ||
596 | free(session->calls); | 618 | free(session->calls); |
597 | free(call); | 619 | free(call); |
598 | session->calls = nullptr; | 620 | session->calls = nullptr; |
599 | } | 621 | } |
600 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data) | 622 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data) |
601 | { | 623 | { |
602 | (void)m; | ||
603 | MSISession *session = (MSISession *)data; | 624 | MSISession *session = (MSISession *)data; |
604 | 625 | ||
605 | switch (status) { | 626 | switch (status) { |