2014-07-21 07:10:57 +08:00
|
|
|
/** msi.c
|
2014-02-17 09:01:30 +08:00
|
|
|
*
|
2014-01-25 08:32:33 +08:00
|
|
|
* Copyright (C) 2013 Tox project All Rights Reserved.
|
|
|
|
*
|
|
|
|
* 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 */
|
|
|
|
|
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
|
|
|
|
2014-02-10 06:06:44 +08:00
|
|
|
#include "msi.h"
|
2014-03-23 02:33:56 +08:00
|
|
|
|
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>
|
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
|
|
|
|
|
|
|
/* Define default timeout for a request.
|
|
|
|
* There is no behavior specified by the msi on what will
|
|
|
|
* client do on timeout, but to call timeout callback.
|
|
|
|
*/
|
|
|
|
#define m_deftout 10000 /* in milliseconds */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
IDResponse,
|
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
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
/**
|
|
|
|
* Headers
|
|
|
|
*/
|
2014-07-21 07:10:57 +08:00
|
|
|
typedef enum {
|
2015-02-16 05:41:10 +08:00
|
|
|
type_request,
|
|
|
|
type_response,
|
2014-07-21 07:10:57 +08:00
|
|
|
} MSIMessageType;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
typedef enum {
|
2015-02-16 05:41:10 +08:00
|
|
|
requ_invite,
|
|
|
|
requ_start,
|
|
|
|
requ_reject,
|
|
|
|
requ_end,
|
2014-01-25 08:32:33 +08:00
|
|
|
} MSIRequest;
|
|
|
|
|
|
|
|
typedef enum {
|
2015-02-16 05:41:10 +08:00
|
|
|
resp_ringing,
|
|
|
|
resp_starting,
|
|
|
|
resp_error,
|
2014-01-25 08:32:33 +08:00
|
|
|
} MSIResponse;
|
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
#define GENERIC_HEADER(header, val_type) \
|
2015-02-16 05:41:10 +08:00
|
|
|
typedef struct { \
|
2014-07-21 07:10:57 +08:00
|
|
|
val_type value; \
|
|
|
|
_Bool exists; \
|
2014-01-25 08:32:33 +08:00
|
|
|
} MSIHeader##header;
|
|
|
|
|
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
GENERIC_HEADER ( Request, MSIRequest )
|
|
|
|
GENERIC_HEADER ( Response, MSIResponse )
|
2015-02-17 06:30:20 +08:00
|
|
|
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;
|
|
|
|
MSIHeaderResponse response;
|
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-17 06:30:20 +08:00
|
|
|
static void invoke_callback(MSICall* c, MSICallbackID i)
|
2014-03-12 05:59:20 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( c->session->callbacks[i] ) {
|
2014-11-18 07:46:46 +08:00
|
|
|
LOGGER_DEBUG("Invoking callback function: %d", i);
|
2015-02-17 06:30:20 +08:00
|
|
|
c->session->callbacks[i] ( c->session->agent_handler, c );
|
2015-02-16 05:41:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create the message.
|
|
|
|
*/
|
|
|
|
static MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
|
|
|
|
{
|
|
|
|
MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
|
|
|
|
|
|
|
|
if ( retu == NULL ) {
|
|
|
|
LOGGER_WARNING("Allocation failed! Program might misbehave!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type == type_request ) {
|
|
|
|
retu->request.exists = 1;
|
|
|
|
retu->request.value = type_value;
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
} else {
|
|
|
|
retu->response.exists = 1;
|
|
|
|
retu->response.value = type_value;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2015-02-16 05:41:10 +08:00
|
|
|
|
|
|
|
return retu;
|
2014-03-12 05:59:20 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
/**
|
2015-02-16 05:41:10 +08:00
|
|
|
* Parse raw data received from socket into MSIMessage struct.
|
2014-01-25 08:32:33 +08:00
|
|
|
*/
|
2014-07-20 10:08:05 +08:00
|
|
|
static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
#define CHECK_SIZE(bytes, constraint, size) \
|
|
|
|
if ((constraint -= 3) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \
|
|
|
|
if ( bytes[1] != size ) { LOGGER_ERROR("Invalid data size!"); return -1; }
|
|
|
|
|
|
|
|
#define CHECK_ENUM_HIGH(bytes, enum_high) \
|
|
|
|
if ( bytes[2] > enum_high ) { LOGGER_ERROR("Failed enum high limit!"); return -1; }
|
|
|
|
|
|
|
|
#define SET_VALUES(bytes, header) do { \
|
2015-02-16 05:41:10 +08:00
|
|
|
header.value = bytes[2]; \
|
|
|
|
header.exists = 1; \
|
|
|
|
bytes += 3; \
|
|
|
|
} while(0)
|
2014-05-26 00:27:48 +08:00
|
|
|
|
|
|
|
|
2014-04-28 01:21:26 +08:00
|
|
|
if ( msg == NULL ) {
|
|
|
|
LOGGER_ERROR("Could not parse message: no storage!");
|
2014-06-01 03:02:50 +08:00
|
|
|
return -1;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +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
|
|
|
}
|
2014-02-17 09:01:30 +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
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
while ( *it ) {/* until end byte is hit */
|
|
|
|
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);
|
|
|
|
CHECK_ENUM_HIGH(it, requ_end);
|
|
|
|
SET_VALUES(it, msg->request);
|
2014-02-17 09:01:30 +08:00
|
|
|
break;
|
2015-02-16 05:41:10 +08:00
|
|
|
|
2014-07-22 23:20:55 +08:00
|
|
|
case IDResponse:
|
2015-02-17 06:30:20 +08:00
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
|
|
|
CHECK_ENUM_HIGH(it, resp_error);
|
|
|
|
SET_VALUES(it, msg->response);
|
2014-07-22 23:20:55 +08:00
|
|
|
it += 3;
|
2014-02-17 09:01:30 +08:00
|
|
|
break;
|
2015-02-16 05:41:10 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
case IDError:
|
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
|
|
|
CHECK_ENUM_HIGH(it, msi_ErrUndisclosed);
|
|
|
|
SET_VALUES(it, msg->error);
|
2014-02-17 09:01:30 +08:00
|
|
|
break;
|
2015-02-16 05:41:10 +08:00
|
|
|
|
|
|
|
case IDCapabilities:
|
2015-02-17 06:30:20 +08:00
|
|
|
CHECK_SIZE(it, size_constraint, 1);
|
|
|
|
SET_VALUES(it, msg->capabilities);
|
2014-07-27 01:29:49 +08:00
|
|
|
break;
|
2015-02-16 05:41:10 +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
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
#undef SET_VALUES
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-11-18 07:46:46 +08:00
|
|
|
* Parse data from handle_packet.
|
2014-01-25 08:32:33 +08:00
|
|
|
*/
|
2015-02-16 05:41:10 +08:00
|
|
|
static MSIMessage *parse_in ( const uint8_t *data, uint16_t length )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
if ( data == NULL ) {
|
|
|
|
LOGGER_WARNING("Tried to parse empty message!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if ( retu == NULL ) {
|
2014-06-28 10:13:38 +08:00
|
|
|
LOGGER_WARNING("Allocation failed! Program might misbehave!");
|
2014-04-28 01:21:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if ( parse_raw_data ( retu, data, length ) == -1 ) {
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( retu );
|
2014-01-25 08:32:33 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
return retu;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-11-18 07:46:46 +08:00
|
|
|
* Speaks for itself.
|
2014-01-25 08:32:33 +08:00
|
|
|
*/
|
2015-02-16 05:41:10 +08:00
|
|
|
static uint8_t *prepare_header ( MSIHeaderID id, uint8_t *dest, const void *value,
|
|
|
|
uint8_t value_len, uint16_t *length )
|
2014-01-25 08:32:33 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
if ( dest == NULL ) {
|
|
|
|
LOGGER_ERROR("No destination space!");
|
2014-06-28 10:13:38 +08:00
|
|
|
return NULL;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if (value == NULL || value_len == 0) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_ERROR("Empty header value");
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-05-26 00:27:48 +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-02-16 05:41:10 +08:00
|
|
|
* Parse MSIMessage to send. Returns size in bytes of the parsed message
|
2014-01-25 08:32:33 +08:00
|
|
|
*/
|
2015-02-16 05:41:10 +08:00
|
|
|
static uint16_t parse_out ( MSIMessage *msg, uint8_t *dest )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
if (msg == NULL) {
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_ERROR("No message!");
|
2014-04-28 01:21:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-04-28 01:21:26 +08:00
|
|
|
if (dest == NULL ) {
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_ERROR("No destination!");
|
2014-04-28 01:21:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
uint8_t *it = dest;
|
|
|
|
uint16_t size = 0;
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if (msg->request.exists) {
|
|
|
|
uint8_t cast = msg->request.value;
|
2015-02-16 05:41:10 +08:00
|
|
|
it = prepare_header(IDRequest, it, &cast, 1, &size);
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
if (msg->response.exists) {
|
|
|
|
uint8_t cast = msg->response.value;
|
2015-02-16 05:41:10 +08:00
|
|
|
it = prepare_header(IDResponse, it, &cast, 1, &size);
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (msg->error.exists) {
|
|
|
|
it = prepare_header(IDError, it, &msg->error.value, sizeof(msg->error.value), &size);
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
if (msg->capabilities.exists) {
|
|
|
|
it = prepare_header(IDCapabilities, it, &msg->capabilities.value,
|
|
|
|
sizeof(msg->capabilities.value), &size);
|
2014-07-27 01:29:49 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
*it = 0;
|
|
|
|
size ++;
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
return size;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
static int send_message ( MSICall *call, MSIMessage *msg, uint32_t to )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-16 05:41:10 +08:00
|
|
|
uint8_t parsed [MSI_MAXMSG_SIZE];
|
|
|
|
uint16_t length = parse_out ( msg, parsed );
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
if ( !length ) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_WARNING("Parsing message failed; nothing sent!");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-16 05:41:10 +08:00
|
|
|
|
|
|
|
if ( m_msi_packet(call->session->messenger_handle, to, parsed, length) ) {
|
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-02-16 05:41:10 +08:00
|
|
|
static int send_reponse ( MSICall *call, MSIResponse response, uint32_t to )
|
2014-07-21 07:10:57 +08:00
|
|
|
{
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg = msi_new_message ( type_response, response );
|
|
|
|
int ret = send_message ( call, msg, to );
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( msg );
|
2014-07-22 23:24:47 +08:00
|
|
|
return ret;
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static int send_error ( MSICall *call, MSIError error, uint32_t to )
|
2014-11-18 07:46:46 +08:00
|
|
|
{
|
|
|
|
if (!call) {
|
|
|
|
LOGGER_WARNING("Cannot handle error on 'null' call");
|
|
|
|
return -1;
|
|
|
|
}
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
LOGGER_DEBUG("Sending error: %d on call: %d", error, call->call_idx);
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_error = msi_new_message ( type_response, resp_error );
|
|
|
|
|
|
|
|
if (!msg_error)
|
|
|
|
return -1;
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
msg_error->error.exists = 1;
|
|
|
|
msg_error->error.value = error;
|
2015-02-16 05:41:10 +08:00
|
|
|
|
|
|
|
send_message ( call, msg_error, to );
|
2014-11-18 07:46:46 +08:00
|
|
|
free ( msg_error );
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static MSICall *get_call ( MSISession *session, uint32_t friend_id )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if (session->calls == NULL || session->calls_tail < friend_id)
|
|
|
|
return NULL;
|
2015-02-16 05:41:10 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
return session->calls[friend_id];
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static MSICall *new_call ( MSISession *session, uint32_t friend_id )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
MSICall *rc = calloc(sizeof(MSICall), 1);
|
|
|
|
|
|
|
|
if (rc == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
rc->friend_id = friend_id;
|
|
|
|
|
|
|
|
if (session->calls == NULL) { /* Creating */
|
|
|
|
session->calls = calloc (sizeof(MSICall*), friend_id + 1);
|
|
|
|
|
|
|
|
if (session->calls == NULL) {
|
|
|
|
free(rc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->calls_tail = session->calls_head = friend_id;
|
|
|
|
|
|
|
|
} else if (session->calls_tail < friend_id) { /* Appending */
|
|
|
|
void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_id + 1);
|
|
|
|
|
|
|
|
if (tmp == NULL) {
|
|
|
|
free(rc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
session->calls = tmp;
|
|
|
|
|
|
|
|
/* Set fields in between to null */
|
|
|
|
int32_t i = session->calls_tail;
|
|
|
|
for (; i < friend_id; i ++)
|
|
|
|
session->calls[i] = NULL;
|
|
|
|
|
|
|
|
rc->prev = session->calls[session->calls_tail];
|
|
|
|
session->calls[session->calls_tail]->next = rc;
|
|
|
|
|
|
|
|
session->calls_tail = friend_id;
|
|
|
|
|
|
|
|
} else if (session->calls_head > friend_id) { /* Inserting at front */
|
|
|
|
rc->next = session->calls[session->calls_head];
|
|
|
|
session->calls[session->calls_head]->prev = rc;
|
|
|
|
session->calls_head = friend_id;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
session->calls[friend_id] = rc;
|
|
|
|
return rc;
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static void kill_call ( MSICall *call )
|
|
|
|
{
|
|
|
|
if ( call == NULL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
MSISession* session = call->session;
|
|
|
|
|
|
|
|
MSICall* prev = call->prev;
|
|
|
|
MSICall* next = call->next;
|
|
|
|
|
|
|
|
if (prev)
|
|
|
|
prev->next = next;
|
|
|
|
else if (next)
|
|
|
|
session->calls_head = next->friend_id;
|
|
|
|
else goto CLEAR;
|
|
|
|
|
|
|
|
if (next)
|
|
|
|
next->prev = prev;
|
|
|
|
else if (prev)
|
|
|
|
session->calls_tail = prev->friend_id;
|
|
|
|
else goto CLEAR;
|
|
|
|
|
|
|
|
session->calls[call->friend_id] = NULL;
|
|
|
|
free(call);
|
|
|
|
return;
|
|
|
|
|
|
|
|
CLEAR:
|
|
|
|
session->calls_head = session->calls_tail = 0;
|
|
|
|
free(session->calls);
|
|
|
|
session->calls = NULL;
|
|
|
|
free(call);
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static void handle_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p)
|
2014-11-18 07:46:46 +08:00
|
|
|
{
|
|
|
|
(void)messenger;
|
|
|
|
MSISession *session = session_p;
|
2014-11-25 09:24:59 +08:00
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
switch ( status ) {
|
|
|
|
case 0: { /* Went offline */
|
2015-02-17 06:30:20 +08:00
|
|
|
MSICall* call = get_call(session, friend_id);
|
|
|
|
|
|
|
|
if (call == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
invoke_callback(call, msi_OnPeerTimeout);
|
|
|
|
kill_call(call);
|
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;
|
|
|
|
}
|
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2014-05-31 07:11:28 +08:00
|
|
|
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
/********** Request handlers **********/
|
|
|
|
static int handle_recv_invite ( MSICall *call, MSIMessage *msg )
|
|
|
|
{
|
|
|
|
if ( call == NULL ) {
|
|
|
|
LOGGER_WARNING("Session: %p Handling 'invite' on no call");
|
|
|
|
return -1;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
MSISession* session = call->session;
|
|
|
|
|
|
|
|
LOGGER_DEBUG("Session: %p Handling 'invite' friend: %d", call->session, call->friend_id);
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if ( call->state == msi_CallRequesting ) {
|
|
|
|
/* The rare glare case.
|
|
|
|
* Send starting and wait for starting by the other side.
|
|
|
|
* The peer will do the same.
|
|
|
|
* When you receive starting from peer send started.
|
|
|
|
* Don't notice the app until the start is received.
|
|
|
|
*/
|
|
|
|
|
|
|
|
LOGGER_DEBUG("Glare detected!");
|
|
|
|
|
|
|
|
MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting );
|
|
|
|
|
|
|
|
call->capabilities &= msg->capabilities;
|
|
|
|
|
|
|
|
msg_starting->capabilities.value = call->capabilities;
|
|
|
|
msg_starting->capabilities.exists = 1;
|
|
|
|
|
|
|
|
send_message ( call, msg_starting, call->friend_id );
|
|
|
|
free ( msg_starting );
|
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
call->capabilities = msg->capabilities;
|
2015-01-25 06:29:54 +08:00
|
|
|
call->state = msi_CallRequested;
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
send_reponse(call, resp_ringing, call->friend_id);
|
|
|
|
invoke_callback(call, msi_OnInvite);
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2014-07-20 10:08:05 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_start ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call == NULL ) {
|
2014-06-23 06:22:01 +08:00
|
|
|
LOGGER_WARNING("Session: %p Handling 'start' on no call");
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-06-23 06:22:01 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid call state on 'start'");
|
|
|
|
/* TODO send error */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-08-04 06:15:00 +08:00
|
|
|
(void)msg;
|
2014-08-05 01:49:53 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id );
|
2014-05-31 07:11:28 +08:00
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
call->state = msi_CallActive;
|
2015-02-17 06:30:20 +08:00
|
|
|
invoke_callback(call, msi_OnStart);
|
|
|
|
|
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2014-07-20 10:08:05 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_reject ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call == NULL ) {
|
2014-06-23 06:22:01 +08:00
|
|
|
LOGGER_WARNING("Session: %p Handling 'start' on no call");
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-06-23 06:22:01 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
2014-08-04 06:15:00 +08:00
|
|
|
(void)msg;
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if ( call->state != msi_CallRequesting ) {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid call state on 'reject'");
|
|
|
|
/* TODO send error */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id);
|
2014-08-05 01:49:53 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
invoke_callback(call, msi_OnReject);
|
|
|
|
kill_call(call);
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2014-07-20 10:08:05 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_end ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
(void)msg;
|
|
|
|
|
|
|
|
if ( call == NULL ) {
|
2014-06-23 06:22:01 +08:00
|
|
|
LOGGER_WARNING("Session: %p Handling 'start' on no call");
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-06-23 06:22:01 +08:00
|
|
|
}
|
2014-06-23 07:54:40 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id);
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
invoke_callback(call, msi_OnEnd);
|
|
|
|
kill_call ( call );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/********** Response handlers **********/
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_ringing ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call == NULL ) {
|
2014-06-23 06:22:01 +08:00
|
|
|
LOGGER_WARNING("Session: %p Handling 'start' on no call");
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-05-30 05:57:58 +08:00
|
|
|
}
|
2014-05-31 07:11:28 +08:00
|
|
|
|
2014-08-04 06:15:00 +08:00
|
|
|
(void)msg;
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if ( call->state != msi_CallRequesting ) {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid call state on 'ringing'");
|
|
|
|
/* TODO send error */
|
|
|
|
return -1;
|
2014-06-27 05:42:37 +08:00
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
invoke_callback(call, msi_OnRinging);
|
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_starting ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call == NULL ) {
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
2014-05-30 05:57:58 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
|
|
|
|
LOGGER_WARNING("Session: %p Invalid call state on 'starting'");
|
|
|
|
/* TODO send error */
|
|
|
|
return -1;
|
2014-05-30 05:57:58 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
MSIMessage *msg_start = msi_new_message ( type_request, requ_start );
|
|
|
|
send_message ( call, msg_start, call->friend_id );
|
|
|
|
free ( msg_start );
|
|
|
|
|
|
|
|
if (call->state == msi_CallRequesting) {
|
|
|
|
call->state = msi_CallActive;
|
|
|
|
invoke_callback(call, msi_OnStart);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise it's a glare case so don't start until 'start' is recved */
|
|
|
|
|
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
static int handle_recv_error ( MSICall *call, MSIMessage *msg )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call == NULL ) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_WARNING("Handling 'error' on non-existing call!");
|
|
|
|
return -1;
|
|
|
|
}
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
invoke_callback(call, msi_OnError);
|
2014-05-31 07:11:28 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
/* TODO Handle error accordingly */
|
2014-05-31 07:11:28 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2014-02-01 19:52:48 +08:00
|
|
|
/**
|
2014-11-18 07:46:46 +08:00
|
|
|
* BASIC call flow:
|
2014-02-01 19:52:48 +08:00
|
|
|
*
|
|
|
|
* ALICE BOB
|
|
|
|
* | invite --> |
|
|
|
|
* | |
|
|
|
|
* | <-- ringing |
|
|
|
|
* | |
|
|
|
|
* | <-- starting |
|
|
|
|
* | |
|
|
|
|
* | start --> |
|
|
|
|
* | |
|
|
|
|
* | <-- MEDIA TRANS --> |
|
|
|
|
* | |
|
|
|
|
* | end --> |
|
|
|
|
* | |
|
|
|
|
* | <-- ending |
|
|
|
|
*
|
|
|
|
* Alice calls Bob by sending invite packet.
|
|
|
|
* Bob recvs the packet and sends an ringing packet;
|
|
|
|
* which notifies Alice that her invite is acknowledged.
|
|
|
|
* Ringing screen shown on both sides.
|
|
|
|
* Bob accepts the invite for a call by sending starting packet.
|
|
|
|
* Alice recvs the starting packet and sends the started packet to
|
|
|
|
* inform Bob that she recved the starting packet.
|
|
|
|
* Now the media transmission is established ( i.e. RTP transmission ).
|
|
|
|
* Alice hangs up and sends end packet.
|
|
|
|
* Bob recves the end packet and sends ending packet
|
|
|
|
* as the acknowledgement that the call is ending.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
2015-02-17 06:30:20 +08:00
|
|
|
static void msi_handle_packet ( Messenger *messenger, int friend_id, 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-02-17 06:30:20 +08:00
|
|
|
|
2014-02-01 19:52:48 +08:00
|
|
|
/* Unused */
|
|
|
|
(void)messenger;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-07-03 22:58:00 +08:00
|
|
|
MSISession *session = object;
|
|
|
|
MSIMessage *msg;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
msg = parse_in ( data, length );
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-07-03 22:58:00 +08:00
|
|
|
if ( !msg ) {
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_WARNING("Error parsing message");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
LOGGER_DEBUG("Successfully parsed message");
|
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
MSICall *call = get_call(session, friend_id);
|
|
|
|
|
|
|
|
if (call == NULL) {
|
|
|
|
if (msg->request != requ_invite) {
|
|
|
|
/* TODO send error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
call = new_call(session, friend_id);
|
|
|
|
if (call == NULL) {
|
|
|
|
/* TODO send error */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
|
2014-02-01 19:52:48 +08:00
|
|
|
/* Now handle message */
|
2015-02-17 06:30:20 +08:00
|
|
|
int rc = 0;
|
2014-07-21 07:10:57 +08:00
|
|
|
if ( msg->request.exists ) { /* Handle request */
|
2014-07-22 23:20:55 +08:00
|
|
|
switch (msg->request.value) {
|
2015-02-16 05:41:10 +08:00
|
|
|
case requ_invite:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_invite ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case requ_start:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_start ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case requ_reject:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_reject ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case requ_end:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_end ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-02-01 19:52:48 +08:00
|
|
|
}
|
2014-07-21 07:10:57 +08:00
|
|
|
} else if ( msg->response.exists ) { /* Handle response */
|
2014-07-22 23:20:55 +08:00
|
|
|
switch (msg->response.value) {
|
2015-02-16 05:41:10 +08:00
|
|
|
case resp_ringing:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_ringing ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case resp_starting:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_starting ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
case resp_error:
|
2015-02-17 06:30:20 +08:00
|
|
|
rc = handle_recv_error ( call, msg );
|
2014-07-22 23:20:55 +08:00
|
|
|
break;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LOGGER_WARNING("Invalid message: no resp nor requ headers");
|
2015-02-17 06:30:20 +08:00
|
|
|
/* TODO send error */
|
|
|
|
rc = -1;
|
2014-02-01 19:52:48 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if (rc == -1)
|
|
|
|
kill_call(call);
|
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( msg );
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2014-02-01 19:52:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
|
|
|
|
/********** User functions **********/
|
2015-02-16 05:41:10 +08:00
|
|
|
void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id)
|
2014-01-25 08:32:33 +08:00
|
|
|
{
|
2015-02-16 05:41:10 +08:00
|
|
|
session->callbacks[id] = callback;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSISession *msi_new ( Messenger *messenger )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
if (messenger == NULL) {
|
|
|
|
LOGGER_ERROR("Could not init session on empty messenger!");
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-07-05 21:11:25 +08:00
|
|
|
MSISession *retu = calloc ( sizeof ( MSISession ), 1 );
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-07-05 21:11:25 +08:00
|
|
|
if (retu == NULL) {
|
2014-06-28 10:13:38 +08:00
|
|
|
LOGGER_ERROR("Allocation failed! Program might misbehave!");
|
2014-05-26 00:27:48 +08:00
|
|
|
return NULL;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
if (create_recursive_mutex(retu->mutex) != 0) {
|
|
|
|
LOGGER_ERROR("Failed to init mutex! Program might misbehave");
|
2015-02-17 06:30:20 +08:00
|
|
|
free(retu);
|
|
|
|
return NULL;
|
2014-11-29 20:42:19 +08:00
|
|
|
}
|
2014-11-30 05:09:24 +08:00
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
retu->messenger_handle = messenger;
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-07-05 21:11:25 +08:00
|
|
|
m_callback_msi_packet(messenger, msi_handle_packet, retu );
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2014-02-16 03:44:33 +08:00
|
|
|
/* This is called when remote terminates session */
|
2014-07-05 21:11:25 +08:00
|
|
|
m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu);
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
LOGGER_DEBUG("New msi session: %p ", retu);
|
2014-07-05 21:11:25 +08:00
|
|
|
return retu;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
int msi_kill ( MSISession *session )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-04-28 01:21:26 +08:00
|
|
|
if (session == NULL) {
|
|
|
|
LOGGER_ERROR("Tried to terminate non-existing session");
|
|
|
|
return -1;
|
2014-03-23 02:33:56 +08:00
|
|
|
}
|
2014-02-17 09:01:30 +08:00
|
|
|
|
|
|
|
m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if (session->calls) {
|
|
|
|
MSIMessage *msg_end = msi_new_message ( type_request, requ_end );
|
|
|
|
|
|
|
|
MSICall* it = get_call(session, session->calls_head);
|
|
|
|
for (; it; it = it->next) {
|
|
|
|
send_message(it, msg_end, it->friend_id);
|
|
|
|
kill_call(it);
|
2014-05-26 00:27:48 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
free(msg_end);
|
|
|
|
}
|
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
|
|
|
pthread_mutex_destroy(session->mutex);
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2014-05-03 07:46:03 +08:00
|
|
|
LOGGER_DEBUG("Terminated session: %p", session);
|
2014-01-25 08:32:33 +08:00
|
|
|
free ( session );
|
2014-11-29 20:42:19 +08:00
|
|
|
return 0;
|
2014-01-25 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-05-03 07:46:03 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
if (get_call(session, friend_id) != NULL) {
|
|
|
|
LOGGER_ERROR("Already in a call");
|
|
|
|
return -1;
|
2014-05-24 22:02:01 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
*call = new_call ( session, friend_id );
|
2014-02-17 09:01:30 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( *call == NULL )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
*call->capabilities = capabilities;
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
msg_invite->capabilities.value = capabilities;
|
|
|
|
msg_invite->capabilities.exists = 1;
|
|
|
|
|
|
|
|
send_message ( *call, msg_invite, friend_id );
|
2014-07-21 07:10:57 +08:00
|
|
|
free( msg_invite );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
*call->state = msi_CallRequesting;
|
|
|
|
|
2014-04-28 01:21:26 +08:00
|
|
|
LOGGER_DEBUG("Invite sent");
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
int msi_hangup ( MSICall* call )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-05-03 07:46:03 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
|
2015-02-17 06:30:20 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_end = msi_new_message ( type_request, requ_end );
|
2015-02-17 06:30:20 +08:00
|
|
|
send_message ( call, msg_end, call->friend_id );
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( msg_end );
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
kill_call(call);
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
int msi_answer ( MSICall* call, uint8_t capabilities )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-05-03 07:46:03 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call->state != msi_CallRequested ) {
|
2014-11-29 20:42:19 +08:00
|
|
|
LOGGER_ERROR("Call is in invalid state!");
|
2015-02-17 06:30:20 +08:00
|
|
|
return -1;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
call->capabilities = capabilities;
|
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting );
|
2015-02-17 06:30:20 +08:00
|
|
|
|
|
|
|
msg_starting->capabilities.value = capabilities;
|
|
|
|
msg_starting->capabilities.exists = 1;
|
|
|
|
|
|
|
|
send_message ( call, msg_starting, call->friend_id );
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( msg_starting );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
int msi_reject ( MSICall* call )
|
2014-02-17 09:01:30 +08:00
|
|
|
{
|
2014-07-22 04:11:59 +08:00
|
|
|
LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown");
|
2014-05-26 00:27:48 +08:00
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
if ( call->state != msi_CallRequested ) {
|
2014-11-29 20:42:19 +08:00
|
|
|
LOGGER_ERROR("Call is in invalid state!");
|
|
|
|
return msi_ErrorInvalidState;
|
2014-04-28 01:21:26 +08:00
|
|
|
}
|
2014-01-25 08:32:33 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_reject = msi_new_message ( type_request, requ_reject );
|
2015-02-17 06:30:20 +08:00
|
|
|
send_message ( call, msg_reject, call->friend_id );
|
2014-07-21 07:10:57 +08:00
|
|
|
free ( msg_reject );
|
2014-01-25 08:32:33 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-17 06:30:20 +08:00
|
|
|
int msi_change_csettings( MSICall* call, uint8_t capabilities )
|
2014-07-21 07:10:57 +08:00
|
|
|
{
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_lock(session->mutex);
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_DEBUG("Changing media on call: %d", call_index);
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
MSICall *call = session->calls[call_index];
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
if ( call->state != msi_CallActive ) {
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_ERROR("Call is not active!");
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
|
|
|
return msi_ErrorInvalidState;
|
2014-07-21 07:10:57 +08:00
|
|
|
}
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-27 01:29:49 +08:00
|
|
|
MSICSettings *local = &call->csettings_local;
|
2014-07-27 09:26:32 +08:00
|
|
|
|
|
|
|
if (
|
2014-11-18 07:46:46 +08:00
|
|
|
local->call_type == csettings->call_type &&
|
|
|
|
local->video_bitrate == csettings->video_bitrate &&
|
|
|
|
local->max_video_width == csettings->max_video_width &&
|
|
|
|
local->max_video_height == csettings->max_video_height &&
|
|
|
|
local->audio_bitrate == csettings->audio_bitrate &&
|
|
|
|
local->audio_frame_duration == csettings->audio_frame_duration &&
|
|
|
|
local->audio_sample_rate == csettings->audio_sample_rate &&
|
|
|
|
local->audio_channels == csettings->audio_channels ) {
|
2014-07-27 01:29:49 +08:00
|
|
|
LOGGER_ERROR("Call is already set accordingly!");
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2014-07-21 07:10:57 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-11-18 07:46:46 +08:00
|
|
|
*local = *csettings;
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2015-02-16 05:41:10 +08:00
|
|
|
MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-27 01:29:49 +08:00
|
|
|
msi_msg_set_csettings ( msg_invite, local );
|
2014-07-21 07:10:57 +08:00
|
|
|
send_message ( session, call, msg_invite, call->peers[0] );
|
|
|
|
free ( msg_invite );
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-07-21 07:10:57 +08:00
|
|
|
LOGGER_DEBUG("Request for media change sent");
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-11-29 20:42:19 +08:00
|
|
|
pthread_mutex_unlock(session->mutex);
|
2014-07-22 23:20:55 +08:00
|
|
|
|
2014-01-25 08:32:33 +08:00
|
|
|
return 0;
|
2015-02-17 06:30:20 +08:00
|
|
|
}
|