2014-07-21 07:10:57 +08:00
|
|
|
/** msi.c
|
2014-02-17 09:01:30 +08:00
|
|
|
*
|
2015-02-18 06:34:40 +08:00
|
|
|
* Copyright (C) 2013-2015 Tox project All Rights Reserved.
|
2014-01-25 08:32:33 +08:00
|
|
|
*
|
|
|
|
* This file is part of Tox.
|
|
|
|
*
|
|
|
|
* Tox is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Tox is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
|
2015-07-21 10:21:53 +08:00
|
|
|
#include "msi.h"
|
2014-04-28 01:21:26 +08:00
|
|
|
#include "../toxcore/logger.h"
|
2014-05-31 23:27:22 +08:00
|
|
|
#include "../toxcore/util.h"
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2014-06-23 06:22:01 +08:00
|
|
|
#include <stdbool.h>
|
2015-02-19 06:23:46 +08:00
|
|
|
#include <assert.h>
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
#define MSI_MAXMSG_SIZE 256
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Protocol:
|
|
|
|
*
|
2014-07-21 07:10:57 +08:00
|
|
|
* |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|
|
2014-01-25 08:32:33 +08:00
|
|
|
*/
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
typedef enum {
|
|
|
|
IDRequest = 1,
|
2015-02-17 06:30:20 +08:00
|
|
|
IDError,
|
2015-02-16 05:41:10 +08:00
|
|
|
IDCapabilities,
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
} MSIHeaderID;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
2015-10-11 05:54:23 +08:00
|
|
|
requ_init,
|
2015-02-21 08:07:22 +08:00
|
|
|
requ_push,
|
|
|
|
requ_pop,
|
|
|
|
} MSIRequest;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
#define GENERIC_HEADER(header, val_type) \
|
2015-02-16 05:41:10 +08:00
|
|
|
typedef struct { \
|
2015-02-19 06:23:46 +08:00
|
|
|
val_type value; \
|
|
|
|
bool exists; \
|
2015-02-18 06:34:40 +08:00
|
|
|
} MSIHeader##header
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
GENERIC_HEADER (Request, MSIRequest);
|
|
|
|
GENERIC_HEADER (Error, MSIError);
|
|
|
|
GENERIC_HEADER (Capabilities, uint8_t);
|
2014-02-17 09:01:30 +08:00
|
|
|
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
typedef struct {
|
|
|
|
MSIHeaderRequest request;
|
2015-02-17 06:30:20 +08:00
|
|
|
MSIHeaderError error;
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIHeaderCapabilities capabilities;
|
2014-01-25 08:32:33 +08:00
|
|
|
} MSIMessage;
|
|
|
|
|
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
void msg_init (MSIMessage *dest, MSIRequest request);
|
2015-10-11 05:54:23 +08:00
|
|
|
int msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length);
|
|
|
|
uint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length);
|
|
|
|
static int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg);
|
|
|
|
int send_error (Messenger *m, uint32_t friend_number, MSIError error);
|
|
|
|
static int invoke_callback(MSICall *call, MSICallbackID cb);
|
|
|
|
static MSICall *get_call (MSISession *session, uint32_t friend_number);
|
|
|
|
MSICall *new_call (MSISession *session, uint32_t friend_number);
|
|
|
|
void kill_call (MSICall *call);
|
2015-04-29 07:01:25 +08:00
|
|
|
void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);
|
2015-10-11 05:54:23 +08:00
|
|
|
void handle_init (MSICall *call, const MSIMessage *msg);
|
|
|
|
void handle_push (MSICall *call, const MSIMessage *msg);
|
|
|
|
void handle_pop (MSICall *call, const MSIMessage *msg);
|
|
|
|
void handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object);
|
2015-02-19 06:23:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Public functions
|
|
|
|
*/
|
2015-10-11 05:54:23 +08:00
|
|
|
void msi_register_callback (MSISession *session, msi_action_cb *callback, MSICallbackID id)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-10-11 05:54:23 +08:00
|
|
|
if (!session)
|
|
|
|
return;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
session->callbacks[id] = callback;
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
MSISession *msi_new (Messenger *m)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-04-29 07:01:25 +08:00
|
|
|
if (m == NULL) {
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_ERROR("Could not init session on empty messenger!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
MSISession *retu = calloc (sizeof (MSISession), 1);
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
if (retu == NULL) {
|
|
|
|
LOGGER_ERROR("Allocation failed! Program might misbehave!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
if (create_recursive_mutex(retu->mutex) != 0) {
|
|
|
|
LOGGER_ERROR("Failed to init mutex! Program might misbehave");
|
|
|
|
free(retu);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
retu->messenger = m;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
m_callback_msi_packet(m, handle_msi_packet, retu);
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
/* This is called when remote terminates session */
|
2015-04-29 07:01:25 +08:00
|
|
|
m_callback_connectionstatus_internal_av(m, on_peer_status, retu);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_DEBUG("New msi session: %p ", retu);
|
|
|
|
return retu;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msi_kill (MSISession *session)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
|
|
|
if (session == NULL) {
|
|
|
|
LOGGER_ERROR("Tried to terminate non-existing session");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL);
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
if (pthread_mutex_trylock(session->mutex) != 0) {
|
|
|
|
LOGGER_ERROR ("Failed to aquire lock on msi mutex");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
if (session->calls) {
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_pop);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
MSICall *it = get_call(session, session->calls_head);
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
for (; it; it = it->next) {
|
2015-04-29 07:01:25 +08:00
|
|
|
send_message(session->messenger, it->friend_number, &msg);
|
2015-02-19 06:23:46 +08:00
|
|
|
kill_call(it); /* This will eventually free session->calls */
|
|
|
|
}
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
pthread_mutex_destroy(session->mutex);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_DEBUG("Terminated session: %p", session);
|
2015-10-11 05:54:23 +08:00
|
|
|
free (session);
|
2015-02-19 06:23:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msi_invite (MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-10-11 05:54:23 +08:00
|
|
|
if (!session)
|
|
|
|
return -1;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_number);
|
|
|
|
|
|
|
|
if (pthread_mutex_trylock(session->mutex) != 0) {
|
|
|
|
LOGGER_ERROR ("Failed to aquire lock on msi mutex");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
if (get_call(session, friend_number) != NULL) {
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_ERROR("Already in a call");
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
(*call) = new_call (session, friend_number);
|
|
|
|
|
|
|
|
if (*call == NULL) {
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return -1;
|
2015-03-02 01:45:04 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
(*call)->self_capabilities = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
2015-10-11 05:54:23 +08:00
|
|
|
msg_init(&msg, requ_init);
|
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
msg.capabilities.exists = true;
|
|
|
|
msg.capabilities.value = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
send_message ((*call)->session->messenger, (*call)->friend_number, &msg);
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
(*call)->state = msi_CallRequesting;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_DEBUG("Invite sent");
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msi_hangup (MSICall *call)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-10-11 05:54:23 +08:00
|
|
|
if (!call || !call->session)
|
|
|
|
return -1;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_number);
|
|
|
|
|
|
|
|
MSISession *session = call->session;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
if (pthread_mutex_trylock(session->mutex) != 0) {
|
|
|
|
LOGGER_ERROR ("Failed to aquire lock on msi mutex");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call->state == msi_CallInactive) {
|
2015-05-13 04:16:00 +08:00
|
|
|
LOGGER_ERROR("Call is in invalid state!");
|
|
|
|
pthread_mutex_unlock(session->mutex);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_pop);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
send_message (session->messenger, call->friend_number, &msg);
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
kill_call(call);
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msi_answer (MSICall *call, uint8_t capabilities)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-10-11 05:54:23 +08:00
|
|
|
if (!call || !call->session)
|
|
|
|
return -1;
|
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_number);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
MSISession *session = call->session;
|
|
|
|
|
|
|
|
if (pthread_mutex_trylock(session->mutex) != 0) {
|
|
|
|
LOGGER_ERROR ("Failed to aquire lock on msi mutex");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call->state != msi_CallRequested) {
|
|
|
|
/* Though sending in invalid state will not cause anything wierd
|
2015-02-21 08:07:22 +08:00
|
|
|
* Its better to not do it like a maniac */
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_ERROR("Call is in invalid state!");
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
call->self_capabilities = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_push);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
msg.capabilities.exists = true;
|
|
|
|
msg.capabilities.value = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
send_message (session->messenger, call->friend_number, &msg);
|
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
call->state = msi_CallActive;
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msi_change_capabilities(MSICall *call, uint8_t capabilities)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
2015-10-11 05:54:23 +08:00
|
|
|
if (!call || !call->session)
|
|
|
|
return -1;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_number);
|
|
|
|
|
|
|
|
MSISession *session = call->session;
|
|
|
|
|
|
|
|
if (pthread_mutex_trylock(session->mutex) != 0) {
|
|
|
|
LOGGER_ERROR ("Failed to aquire lock on msi mutex");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call->state != msi_CallActive) {
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_ERROR("Call is in invalid state!");
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
call->self_capabilities = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_push);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
msg.capabilities.exists = true;
|
|
|
|
msg.capabilities.value = capabilities;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
send_message (call->session->messenger, call->friend_number, &msg);
|
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-19 06:23:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private functions
|
|
|
|
*/
|
2015-10-11 05:54:23 +08:00
|
|
|
void msg_init(MSIMessage *dest, MSIRequest request)
|
2015-02-21 08:07:22 +08:00
|
|
|
{
|
|
|
|
memset(dest, 0, sizeof(*dest));
|
|
|
|
dest->request.exists = true;
|
|
|
|
dest->request.value = request;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length)
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-18 06:34:40 +08:00
|
|
|
/* Parse raw data received from socket into MSIMessage struct */
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
#define CHECK_SIZE(bytes, constraint, size) \
|
2015-02-18 06:34:40 +08:00
|
|
|
if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \
|
2015-10-11 05:54:23 +08:00
|
|
|
if (bytes[1] != size) { LOGGER_ERROR("Invalid data size!"); return -1; }
|
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
#define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \
|
2015-10-11 05:54:23 +08:00
|
|
|
if (bytes[2] > enum_high) { LOGGER_ERROR("Failed enum high limit!"); return -1; }
|
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
#define SET_UINT8(bytes, header) do { \
|
2015-02-16 05:41:10 +08:00
|
|
|
header.value = bytes[2]; \
|
2015-02-18 06:34:40 +08:00
|
|
|
header.exists = true; \
|
2015-02-16 05:41:10 +08:00
|
|
|
bytes += 3; \
|
|
|
|
} while(0)
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
#define SET_UINT16(bytes, header) do { \
|
|
|
|
memcpy(&header.value, bytes + 2, 2);\
|
|
|
|
header.exists = true; \
|
|
|
|
bytes += 4; \
|
|
|
|
} while(0)
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(dest);
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
if (length == 0 || data[length - 1]) { /* End byte must have value 0 */
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_ERROR("Invalid end byte");
|
2014-02-07 07:10:55 +08:00
|
|
|
return -1;
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
memset(dest, 0, sizeof(*dest));
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
const uint8_t *it = data;
|
|
|
|
int size_constraint = length;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
while (*it) {/* until end byte is hit */
|
2014-07-21 07:10:57 +08:00
|
|
|
switch (*it) {
|
2014-07-22 23:20:55 +08:00
|
|
|
case IDRequest:
|
2015-02-17 06:30:20 +08:00
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
2015-02-21 08:07:22 +08:00
|
|
|
CHECK_ENUM_HIGH(it, requ_pop);
|
2015-02-18 06:34:40 +08:00
|
|
|
SET_UINT8(it, dest->request);
|
2014-02-17 09:01:30 +08:00
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
case IDError:
|
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
2015-03-02 01:45:04 +08:00
|
|
|
CHECK_ENUM_HIGH(it, msi_EUndisclosed);
|
2015-02-18 06:34:40 +08:00
|
|
|
SET_UINT8(it, dest->error);
|
2014-02-17 09:01:30 +08:00
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case IDCapabilities:
|
2015-02-17 06:30:20 +08:00
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
2015-02-18 06:34:40 +08:00
|
|
|
SET_UINT8(it, dest->capabilities);
|
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-07-22 23:20:55 +08:00
|
|
|
default:
|
|
|
|
LOGGER_ERROR("Invalid id byte");
|
|
|
|
return -1;
|
|
|
|
break;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
if (dest->request.exists == false) {
|
|
|
|
LOGGER_ERROR("Invalid request field!");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
#undef CHECK_SIZE
|
|
|
|
#undef CHECK_ENUM_HIGH
|
2015-02-18 06:34:40 +08:00
|
|
|
#undef SET_UINT8
|
|
|
|
#undef SET_UINT16
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
uint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length)
|
2014-01-25 08:32:33 +08:00
|
|
|
{
|
2015-02-18 06:34:40 +08:00
|
|
|
/* Parse a single header for sending */
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(dest);
|
|
|
|
assert(value);
|
|
|
|
assert(value_len);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-07-22 23:20:55 +08:00
|
|
|
*dest = id;
|
|
|
|
dest ++;
|
|
|
|
*dest = value_len;
|
|
|
|
dest ++;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
memcpy(dest, value, value_len);
|
2014-06-15 22:36:57 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
*length += (2 + value_len);
|
2014-06-15 22:36:57 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
return dest + value_len; /* Set to next position ready to be written */
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg)
|
2015-02-18 06:34:40 +08:00
|
|
|
{
|
|
|
|
/* Parse and send message */
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(m);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
uint8_t parsed [MSI_MAXMSG_SIZE];
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
uint8_t *it = parsed;
|
2014-07-21 07:10:57 +08:00
|
|
|
uint16_t size = 0;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if (msg->request.exists) {
|
|
|
|
uint8_t cast = msg->request.value;
|
2015-10-11 05:54:23 +08:00
|
|
|
it = msg_parse_header_out(IDRequest, it, &cast,
|
2015-02-20 07:23:38 +08:00
|
|
|
sizeof(cast), &size);
|
2015-02-21 08:07:22 +08:00
|
|
|
} else {
|
|
|
|
LOGGER_DEBUG("Must have request field");
|
|
|
|
return -1;
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (msg->error.exists) {
|
2015-02-21 08:07:22 +08:00
|
|
|
uint8_t cast = msg->error.value;
|
2015-10-11 05:54:23 +08:00
|
|
|
it = msg_parse_header_out(IDError, it, &cast,
|
2015-02-21 08:07:22 +08:00
|
|
|
sizeof(cast), &size);
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
if (msg->capabilities.exists) {
|
2015-10-11 05:54:23 +08:00
|
|
|
it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value,
|
2015-02-20 07:23:38 +08:00
|
|
|
sizeof(msg->capabilities.value), &size);
|
2014-07-27 01:29:49 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (it == parsed) {
|
2015-02-18 06:34:40 +08:00
|
|
|
LOGGER_WARNING("Parsing message failed; empty message");
|
2014-04-28 01:21:26 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
*it = 0;
|
|
|
|
size ++;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (m_msi_packet(m, friend_number, parsed, size)) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_DEBUG("Sent message");
|
|
|
|
return 0;
|
|
|
|
}
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-04-28 01:21:26 +08:00
|
|
|
return -1;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int send_error (Messenger *m, uint32_t friend_number, MSIError error)
|
2014-11-18 07:46:46 +08:00
|
|
|
{
|
2015-02-18 06:34:40 +08:00
|
|
|
/* Send error message */
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(m);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_number);
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_pop);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
msg.error.exists = true;
|
|
|
|
msg.error.value = error;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
send_message (m, friend_number, &msg);
|
2014-11-18 07:46:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
int invoke_callback(MSICall *call, MSICallbackID cb)
|
2015-02-19 06:23:46 +08:00
|
|
|
{
|
|
|
|
assert(call);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (call->session->callbacks[cb]) {
|
2015-02-19 06:23:46 +08:00
|
|
|
LOGGER_DEBUG("Invoking callback function: %d", cb);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (call->session->callbacks[cb] (call->session->av, call) != 0) {
|
2015-03-02 01:45:04 +08:00
|
|
|
LOGGER_WARNING("Callback state handling failed, sending error");
|
2015-02-21 08:07:22 +08:00
|
|
|
goto FAILURE;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
return 0;
|
2015-02-19 06:23:46 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
FAILURE:
|
|
|
|
/* If no callback present or error happened while handling,
|
2015-03-02 01:45:04 +08:00
|
|
|
* an error message will be sent to friend
|
2015-02-21 08:07:22 +08:00
|
|
|
*/
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-03-02 01:45:04 +08:00
|
|
|
if (call->error == msi_ENone)
|
|
|
|
call->error = msi_EHandle;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
return -1;
|
2015-02-19 06:23:46 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
static MSICall *get_call (MSISession *session, uint32_t friend_number)
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(session);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
if (session->calls == NULL || session->calls_tail < friend_number)
|
2015-02-17 06:30:20 +08:00
|
|
|
return NULL;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
return session->calls[friend_number];
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
MSICall *new_call (MSISession *session, uint32_t friend_number)
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(session);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
MSICall *rc = calloc(sizeof(MSICall), 1);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (rc == NULL)
|
|
|
|
return NULL;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-20 07:23:38 +08:00
|
|
|
rc->session = session;
|
2015-04-29 07:01:25 +08:00
|
|
|
rc->friend_number = friend_number;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (session->calls == NULL) { /* Creating */
|
2015-10-11 05:54:23 +08:00
|
|
|
session->calls = calloc (sizeof(MSICall *), friend_number + 1);
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (session->calls == NULL) {
|
|
|
|
free(rc);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls_tail = session->calls_head = friend_number;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
} else if (session->calls_tail < friend_number) { /* Appending */
|
2015-10-23 21:59:21 +08:00
|
|
|
void *tmp = realloc(session->calls, sizeof(MSICall *) * (friend_number + 1));
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (tmp == NULL) {
|
|
|
|
free(rc);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
session->calls = tmp;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
/* Set fields in between to null */
|
2015-04-30 06:40:30 +08:00
|
|
|
uint32_t i = session->calls_tail + 1;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
for (; i < friend_number; i ++)
|
2015-02-17 06:30:20 +08:00
|
|
|
session->calls[i] = NULL;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
rc->prev = session->calls[session->calls_tail];
|
|
|
|
session->calls[session->calls_tail]->next = rc;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls_tail = friend_number;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
} else if (session->calls_head > friend_number) { /* Inserting at front */
|
2015-02-17 06:30:20 +08:00
|
|
|
rc->next = session->calls[session->calls_head];
|
|
|
|
session->calls[session->calls_head]->prev = rc;
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls_head = friend_number;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls[friend_number] = rc;
|
2015-02-17 06:30:20 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
void kill_call (MSICall *call)
|
2015-02-17 06:30:20 +08:00
|
|
|
{
|
2015-03-02 01:45:04 +08:00
|
|
|
/* Assume that session mutex is locked */
|
2015-10-11 05:54:23 +08:00
|
|
|
if (call == NULL)
|
2015-02-17 06:30:20 +08:00
|
|
|
return;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-03-02 01:45:04 +08:00
|
|
|
LOGGER_DEBUG("Killing call: %p", call);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
MSISession *session = call->session;
|
|
|
|
|
|
|
|
MSICall *prev = call->prev;
|
|
|
|
MSICall *next = call->next;
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (prev)
|
|
|
|
prev->next = next;
|
|
|
|
else if (next)
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls_head = next->friend_number;
|
2015-03-02 01:45:04 +08:00
|
|
|
else goto CLEAR_CONTAINER;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (next)
|
|
|
|
next->prev = prev;
|
|
|
|
else if (prev)
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls_tail = prev->friend_number;
|
2015-03-02 01:45:04 +08:00
|
|
|
else goto CLEAR_CONTAINER;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
session->calls[call->friend_number] = NULL;
|
2015-02-17 06:30:20 +08:00
|
|
|
free(call);
|
|
|
|
return;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-03-02 01:45:04 +08:00
|
|
|
CLEAR_CONTAINER:
|
2015-02-17 06:30:20 +08:00
|
|
|
session->calls_head = session->calls_tail = 0;
|
|
|
|
free(session->calls);
|
|
|
|
free(call);
|
2015-03-02 01:45:04 +08:00
|
|
|
session->calls = NULL;
|
2015-02-17 06:30:20 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data)
|
2014-11-18 07:46:46 +08:00
|
|
|
{
|
2015-02-19 06:23:46 +08:00
|
|
|
(void)m;
|
|
|
|
MSISession *session = data;
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
switch (status) {
|
2015-02-19 06:23:46 +08:00
|
|
|
case 0: { /* Friend is now offline */
|
2015-04-29 07:01:25 +08:00
|
|
|
LOGGER_DEBUG("Friend %d is now offline", friend_number);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2015-10-11 05:54:23 +08:00
|
|
|
MSICall *call = get_call(session, friend_number);
|
|
|
|
|
2015-03-02 01:45:04 +08:00
|
|
|
if (call == NULL) {
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-17 06:30:20 +08:00
|
|
|
return;
|
2015-03-02 01:45:04 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */
|
2015-02-17 06:30:20 +08:00
|
|
|
kill_call(call);
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2014-11-18 07:46:46 +08:00
|
|
|
}
|
|
|
|
break;
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-11-04 02:42:05 +08:00
|
|
|
void handle_init (MSICall *call, const MSIMessage *msg)
|
2015-02-17 06:30:20 +08:00
|
|
|
{
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(call);
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'init' friend: %d", call->session, call->friend_number);
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-02-18 06:34:40 +08:00
|
|
|
if (!msg->capabilities.exists) {
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_WARNING("Session: %p Invalid capabilities on 'init'");
|
2015-03-02 01:45:04 +08:00
|
|
|
call->error = msi_EInvalidMessage;
|
2015-02-21 08:07:22 +08:00
|
|
|
goto FAILURE;
|
2015-02-18 06:34:40 +08:00
|
|
|
}
|
2015-11-04 02:42:05 +08:00
|
|
|
|
|
|
|
switch (call->state) {
|
2015-02-21 08:07:22 +08:00
|
|
|
case msi_CallInactive: {
|
|
|
|
/* Call requested */
|
|
|
|
call->peer_capabilities = msg->capabilities.value;
|
|
|
|
call->state = msi_CallRequested;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (invoke_callback(call, msi_OnInvite) == -1)
|
2015-02-21 08:07:22 +08:00
|
|
|
goto FAILURE;
|
2015-10-11 05:54:23 +08:00
|
|
|
}
|
|
|
|
break;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
case msi_CallActive: {
|
2015-10-11 05:54:23 +08:00
|
|
|
/* If peer sent init while the call is already
|
|
|
|
* active it's probable that he is trying to
|
|
|
|
* re-call us while the call is not terminated
|
|
|
|
* on our side. We can assume that in this case
|
|
|
|
* we can automatically answer the re-call.
|
|
|
|
*/
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_INFO("Friend is recalling us");
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
MSIMessage msg;
|
|
|
|
msg_init(&msg, requ_push);
|
|
|
|
|
|
|
|
msg.capabilities.exists = true;
|
|
|
|
msg.capabilities.value = call->self_capabilities;
|
|
|
|
|
|
|
|
send_message (call->session->messenger, call->friend_number, &msg);
|
|
|
|
|
|
|
|
/* If peer changed capabilities during re-call they will
|
|
|
|
* be handled accordingly during the next step
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
break;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
default: {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid state on 'init'");
|
|
|
|
call->error = msi_EInvalidState;
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
return;
|
|
|
|
FAILURE:
|
|
|
|
send_error(call->session->messenger, call->friend_number, call->error);
|
|
|
|
kill_call(call);
|
|
|
|
}
|
|
|
|
void handle_push (MSICall *call, const MSIMessage *msg)
|
|
|
|
{
|
|
|
|
assert(call);
|
|
|
|
|
|
|
|
LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number);
|
|
|
|
|
|
|
|
if (!msg->capabilities.exists) {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid capabilities on 'push'");
|
|
|
|
call->error = msi_EInvalidMessage;
|
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (call->state) {
|
|
|
|
case msi_CallActive: {
|
2015-02-21 08:07:22 +08:00
|
|
|
/* Only act if capabilities changed */
|
2015-10-11 05:54:23 +08:00
|
|
|
if (call->peer_capabilities != msg->capabilities.value) {
|
2015-05-23 05:22:31 +08:00
|
|
|
LOGGER_INFO("Friend is changing capabilities to: %u", msg->capabilities.value);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
call->peer_capabilities = msg->capabilities.value;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (invoke_callback(call, msi_OnCapabilities) == -1)
|
2015-02-21 08:07:22 +08:00
|
|
|
goto FAILURE;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
case msi_CallRequesting: {
|
|
|
|
LOGGER_INFO("Friend answered our call");
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
/* Call started */
|
2015-02-19 06:23:46 +08:00
|
|
|
call->peer_capabilities = msg->capabilities.value;
|
2015-02-21 08:07:22 +08:00
|
|
|
call->state = msi_CallActive;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (invoke_callback(call, msi_OnStart) == -1)
|
2015-02-21 08:07:22 +08:00
|
|
|
goto FAILURE;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Pushes during initialization state are ignored */
|
|
|
|
case msi_CallInactive:
|
2015-02-21 08:07:22 +08:00
|
|
|
case msi_CallRequested: {
|
2015-10-11 05:54:23 +08:00
|
|
|
LOGGER_WARNING("Ignoring invalid push");
|
|
|
|
}
|
|
|
|
break;
|
2015-02-19 06:23:46 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
return;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
FAILURE:
|
2015-04-29 07:01:25 +08:00
|
|
|
send_error(call->session->messenger, call->friend_number, call->error);
|
2015-02-17 06:30:20 +08:00
|
|
|
kill_call(call);
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
void handle_pop (MSICall *call, const MSIMessage *msg)
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-19 06:23:46 +08:00
|
|
|
assert(call);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
/* callback errors are ignored */
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
if (msg->error.exists) {
|
|
|
|
LOGGER_WARNING("Friend detected an error: %d", msg->error.value);
|
|
|
|
call->error = msg->error.value;
|
|
|
|
invoke_callback(call, msi_OnError);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-21 08:07:22 +08:00
|
|
|
} else switch (call->state) {
|
2015-11-04 02:42:05 +08:00
|
|
|
case msi_CallInactive: {
|
|
|
|
LOGGER_ERROR("Handling what should be impossible case");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-11-04 02:42:05 +08:00
|
|
|
case msi_CallActive: {
|
|
|
|
/* Hangup */
|
|
|
|
LOGGER_INFO("Friend hung up on us");
|
|
|
|
invoke_callback(call, msi_OnEnd);
|
|
|
|
}
|
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-11-04 02:42:05 +08:00
|
|
|
case msi_CallRequesting: {
|
|
|
|
/* Reject */
|
|
|
|
LOGGER_INFO("Friend rejected our call");
|
|
|
|
invoke_callback(call, msi_OnEnd);
|
|
|
|
}
|
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-11-04 02:42:05 +08:00
|
|
|
case msi_CallRequested: {
|
|
|
|
/* Cancel */
|
|
|
|
LOGGER_INFO("Friend canceled call invite");
|
|
|
|
invoke_callback(call, msi_OnEnd);
|
|
|
|
}
|
|
|
|
break;
|
2015-10-11 05:54:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
kill_call (call);
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
void handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object)
|
2014-02-01 19:52:48 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_DEBUG("Got msi message");
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2014-07-03 22:58:00 +08:00
|
|
|
MSISession *session = object;
|
2015-02-18 06:34:40 +08:00
|
|
|
MSIMessage msg;
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
if (msg_parse_in (&msg, data, length) == -1) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_WARNING("Error parsing message");
|
2015-04-29 07:01:25 +08:00
|
|
|
send_error(m, friend_number, msi_EInvalidMessage);
|
2014-04-28 01:21:26 +08:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
LOGGER_DEBUG("Successfully parsed message");
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2015-04-29 07:01:25 +08:00
|
|
|
MSICall *call = get_call(session, friend_number);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (call == NULL) {
|
2015-10-11 05:54:23 +08:00
|
|
|
if (msg.request.value != requ_init) {
|
2015-04-29 07:01:25 +08:00
|
|
|
send_error(m, friend_number, msi_EStrayMessage);
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-17 06:30:20 +08:00
|
|
|
return;
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-04-29 07:01:25 +08:00
|
|
|
call = new_call(session, friend_number);
|
2015-10-11 05:54:23 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (call == NULL) {
|
2015-04-29 07:01:25 +08:00
|
|
|
send_error(m, friend_number, msi_ESystem);
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2015-02-17 06:30:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-10-11 05:54:23 +08:00
|
|
|
|
|
|
|
switch (msg.request.value) {
|
|
|
|
case requ_init:
|
|
|
|
handle_init(call, &msg);
|
|
|
|
break;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
case requ_push:
|
|
|
|
handle_push(call, &msg);
|
|
|
|
break;
|
2015-11-04 02:42:05 +08:00
|
|
|
|
2015-10-11 05:54:23 +08:00
|
|
|
case requ_pop:
|
|
|
|
handle_pop(call, &msg); /* always kills the call */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-04-22 08:09:37 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2014-04-17 00:08:44 +08:00
|
|
|
}
|