- initial import
This commit is contained in:
205
src/libs/android-ifaddrs/ifaddrs.cpp
Normal file
205
src/libs/android-ifaddrs/ifaddrs.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
#include "ifaddrs.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
struct netlinkrequest {
|
||||
nlmsghdr header;
|
||||
ifaddrmsg msg;
|
||||
};
|
||||
|
||||
const int kMaxReadSize = 4096;
|
||||
|
||||
|
||||
int set_ifname(struct ifaddrs* ifaddr, int interface) {
|
||||
char buf[IFNAMSIZ] = {0};
|
||||
char* name = if_indextoname(interface, buf);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ifaddr->ifa_name = new char[strlen(name) + 1];
|
||||
strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_flags(struct ifaddrs* ifaddr) {
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
|
||||
int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
|
||||
close(fd);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
ifaddr->ifa_flags = ifr.ifr_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
|
||||
size_t len) {
|
||||
if (msg->ifa_family == AF_INET) {
|
||||
sockaddr_in* sa = new sockaddr_in;
|
||||
sa->sin_family = AF_INET;
|
||||
memcpy(&sa->sin_addr, data, len);
|
||||
ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
|
||||
} else if (msg->ifa_family == AF_INET6) {
|
||||
sockaddr_in6* sa = new sockaddr_in6;
|
||||
sa->sin6_family = AF_INET6;
|
||||
sa->sin6_scope_id = msg->ifa_index;
|
||||
memcpy(&sa->sin6_addr, data, len);
|
||||
ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
|
||||
char* prefix = NULL;
|
||||
if (family == AF_INET) {
|
||||
sockaddr_in* mask = new sockaddr_in;
|
||||
mask->sin_family = AF_INET;
|
||||
memset(&mask->sin_addr, 0, sizeof(in_addr));
|
||||
ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
|
||||
if (prefixlen > 32) {
|
||||
prefixlen = 32;
|
||||
}
|
||||
prefix = reinterpret_cast<char*>(&mask->sin_addr);
|
||||
} else if (family == AF_INET6) {
|
||||
sockaddr_in6* mask = new sockaddr_in6;
|
||||
mask->sin6_family = AF_INET6;
|
||||
memset(&mask->sin6_addr, 0, sizeof(in6_addr));
|
||||
ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
|
||||
if (prefixlen > 128) {
|
||||
prefixlen = 128;
|
||||
}
|
||||
prefix = reinterpret_cast<char*>(&mask->sin6_addr);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < (prefixlen / 8); i++) {
|
||||
*prefix++ = 0xFF;
|
||||
}
|
||||
char remainder = 0xff;
|
||||
remainder <<= (8 - prefixlen % 8);
|
||||
*prefix = remainder;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
|
||||
size_t len) {
|
||||
if (set_ifname(ifaddr, msg->ifa_index) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (set_flags(ifaddr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (set_addresses(ifaddr, msg, bytes, len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs** result) {
|
||||
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
netlinkrequest ifaddr_request;
|
||||
memset(&ifaddr_request, 0, sizeof(ifaddr_request));
|
||||
ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
|
||||
ifaddr_request.header.nlmsg_type = RTM_GETADDR;
|
||||
ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
|
||||
|
||||
ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
|
||||
if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
struct ifaddrs* start = NULL;
|
||||
struct ifaddrs* current = NULL;
|
||||
char buf[kMaxReadSize];
|
||||
ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
|
||||
while (amount_read > 0) {
|
||||
nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
|
||||
size_t header_size = static_cast<size_t>(amount_read);
|
||||
for ( ; NLMSG_OK(header, header_size);
|
||||
header = NLMSG_NEXT(header, header_size)) {
|
||||
switch (header->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
// Success. Return.
|
||||
*result = start;
|
||||
close(fd);
|
||||
return 0;
|
||||
case NLMSG_ERROR:
|
||||
close(fd);
|
||||
freeifaddrs(start);
|
||||
return -1;
|
||||
case RTM_NEWADDR: {
|
||||
ifaddrmsg* address_msg =
|
||||
reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
|
||||
rtattr* rta = IFA_RTA(address_msg);
|
||||
ssize_t payload_len = IFA_PAYLOAD(header);
|
||||
while (RTA_OK(rta, payload_len)) {
|
||||
if (rta->rta_type == IFA_ADDRESS) {
|
||||
int family = address_msg->ifa_family;
|
||||
if (family == AF_INET || family == AF_INET6) {
|
||||
ifaddrs* newest = new ifaddrs;
|
||||
memset(newest, 0, sizeof(ifaddrs));
|
||||
if (current) {
|
||||
current->ifa_next = newest;
|
||||
} else {
|
||||
start = newest;
|
||||
}
|
||||
if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
|
||||
RTA_PAYLOAD(rta)) != 0) {
|
||||
freeifaddrs(start);
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
current = newest;
|
||||
}
|
||||
}
|
||||
rta = RTA_NEXT(rta, payload_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
amount_read = recv(fd, &buf, kMaxReadSize, 0);
|
||||
}
|
||||
close(fd);
|
||||
freeifaddrs(start);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs* addrs) {
|
||||
struct ifaddrs* last = NULL;
|
||||
struct ifaddrs* cursor = addrs;
|
||||
while (cursor) {
|
||||
delete[] cursor->ifa_name;
|
||||
delete cursor->ifa_addr;
|
||||
delete cursor->ifa_netmask;
|
||||
last = cursor;
|
||||
cursor = cursor->ifa_next;
|
||||
delete last;
|
||||
}
|
||||
}
|
||||
49
src/libs/android-ifaddrs/ifaddrs.h
Normal file
49
src/libs/android-ifaddrs/ifaddrs.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _ANDROID_IFADDRS_H_
|
||||
#define _ANDROID_IFADDRS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// Implementation of getifaddrs for Android.
|
||||
// Fills out a list of ifaddr structs (see below) which contain information
|
||||
// about every network interface available on the host.
|
||||
// See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function).
|
||||
struct ifaddrs {
|
||||
struct ifaddrs* ifa_next;
|
||||
char* ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr* ifa_addr;
|
||||
struct sockaddr* ifa_netmask;
|
||||
// Real ifaddrs has broadcast, point to point and data members.
|
||||
// We don't need them (yet?).
|
||||
};
|
||||
|
||||
int getifaddrs(struct ifaddrs** result);
|
||||
void freeifaddrs(struct ifaddrs* addrs);
|
||||
|
||||
#endif
|
||||
BIN
src/libs/dxguid.lib
Normal file
BIN
src/libs/dxguid.lib
Normal file
Binary file not shown.
13
src/libs/g722/CMakeLists.txt
Normal file
13
src/libs/g722/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
project (g722_codec)
|
||||
|
||||
# Rely on C++ 11
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set (G722_SOURCES
|
||||
g722_bitstream.c
|
||||
g722_decode.c
|
||||
g722_encode.c
|
||||
)
|
||||
|
||||
add_library(g722_codec ${G722_SOURCES})
|
||||
184
src/libs/g722/g722.h
Normal file
184
src/libs/g722/g722.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* g722.h - The ITU G.722 codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2005 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, or
|
||||
* the Lesser GNU General Public License version 2.1, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Based on a single channel G.722 codec which is:
|
||||
*
|
||||
***** Copyright (c) CMU 1993 *****
|
||||
* Computer Science, Speech Group
|
||||
* Chengxiang Lu and Alex Hauptmann
|
||||
*
|
||||
* $Id: g722.h,v 1.17 2008/02/09 15:32:26 steveu Exp $
|
||||
*/
|
||||
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_G722_H_)
|
||||
#define _SPANDSP_G722_H_
|
||||
|
||||
#include "inttypes.h"
|
||||
|
||||
|
||||
/*! \page g722_page G.722 encoding and decoding
|
||||
\section g722_page_sec_1 What does it do?
|
||||
The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
|
||||
specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
|
||||
|
||||
To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
|
||||
support an option for the linear audio to be an 8k samples/second stream. In this mode the
|
||||
codec is considerably faster, and still fully compatible with wideband terminals using G.722.
|
||||
|
||||
\section g722_page_sec_2 How does it work?
|
||||
???.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
G722_SAMPLE_RATE_8000 = 0x0001,
|
||||
G722_PACKED = 0x0002
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
||||
disabled. */
|
||||
int itu_test_mode;
|
||||
/*! TRUE if the G.722 data is packed */
|
||||
int packed;
|
||||
/*! TRUE if encode from 8k samples/second */
|
||||
int eight_k;
|
||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||
int bits_per_sample;
|
||||
|
||||
/*! Signal history for the QMF */
|
||||
int x[24];
|
||||
|
||||
struct
|
||||
{
|
||||
int s;
|
||||
int sp;
|
||||
int sz;
|
||||
int r[3];
|
||||
int a[3];
|
||||
int ap[3];
|
||||
int p[3];
|
||||
int d[7];
|
||||
int b[7];
|
||||
int bp[7];
|
||||
int sg[7];
|
||||
int nb;
|
||||
int det;
|
||||
} band[2];
|
||||
|
||||
unsigned int in_buffer;
|
||||
int in_bits;
|
||||
unsigned int out_buffer;
|
||||
int out_bits;
|
||||
} g722_encode_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
||||
disabled. */
|
||||
int itu_test_mode;
|
||||
/*! TRUE if the G.722 data is packed */
|
||||
int packed;
|
||||
/*! TRUE if decode to 8k samples/second */
|
||||
int eight_k;
|
||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||
int bits_per_sample;
|
||||
|
||||
/*! Signal history for the QMF */
|
||||
int x[24];
|
||||
|
||||
struct
|
||||
{
|
||||
int s;
|
||||
int sp;
|
||||
int sz;
|
||||
int r[3];
|
||||
int a[3];
|
||||
int ap[3];
|
||||
int p[3];
|
||||
int d[7];
|
||||
int b[7];
|
||||
int bp[7];
|
||||
int sg[7];
|
||||
int nb;
|
||||
int det;
|
||||
} band[2];
|
||||
|
||||
unsigned int in_buffer;
|
||||
int in_bits;
|
||||
unsigned int out_buffer;
|
||||
int out_bits;
|
||||
} g722_decode_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*! Initialise an G.722 encode context.
|
||||
\param s The G.722 encode context.
|
||||
\param rate The required bit rate for the G.722 data.
|
||||
The valid rates are 64000, 56000 and 48000.
|
||||
\param options
|
||||
\return A pointer to the G.722 encode context, or NULL for error. */
|
||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
|
||||
|
||||
int g722_encode_release(g722_encode_state_t *s);
|
||||
|
||||
/*! Encode a buffer of linear PCM data to G.722
|
||||
\param s The G.722 context.
|
||||
\param g722_data The G.722 data produced.
|
||||
\param amp The audio sample buffer.
|
||||
\param len The number of samples in the buffer.
|
||||
\return The number of bytes of G.722 data produced. */
|
||||
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
|
||||
|
||||
/*! Initialise an G.722 decode context.
|
||||
\param s The G.722 decode context.
|
||||
\param rate The bit rate of the G.722 data.
|
||||
The valid rates are 64000, 56000 and 48000.
|
||||
\param options
|
||||
\return A pointer to the G.722 decode context, or NULL for error. */
|
||||
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options);
|
||||
|
||||
int g722_decode_release(g722_decode_state_t *s);
|
||||
|
||||
/*! Decode a buffer of G.722 data to linear PCM.
|
||||
\param s The G.722 context.
|
||||
\param amp The audio sample buffer.
|
||||
\param g722_data
|
||||
\param len
|
||||
\return The number of samples returned. */
|
||||
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
137
src/libs/g722/g722_bitstream.c
Normal file
137
src/libs/g722/g722_bitstream.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* bitstream.c - Bitstream composition and decomposition routines.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2006 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the Lesser Lesser GNU General Public License version 2.1.1, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: bitstream.c,v 1.8 2007/08/20 15:22:21 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "inttypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "g722_telephony.h"
|
||||
#include "g722_bitstream.h"
|
||||
|
||||
void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits)
|
||||
{
|
||||
value &= ((1 << bits) - 1);
|
||||
if (s->residue + bits <= 32)
|
||||
{
|
||||
s->bitstream |= (value << s->residue);
|
||||
s->residue += bits;
|
||||
}
|
||||
while (s->residue >= 8)
|
||||
{
|
||||
s->residue -= 8;
|
||||
*(*c)++ = (uint8_t) (s->bitstream & 0xFF);
|
||||
s->bitstream >>= 8;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits)
|
||||
{
|
||||
value &= ((1 << bits) - 1);
|
||||
if (s->residue + bits <= 32)
|
||||
{
|
||||
s->bitstream = (s->bitstream << bits) | value;
|
||||
s->residue += bits;
|
||||
}
|
||||
while (s->residue >= 8)
|
||||
{
|
||||
s->residue -= 8;
|
||||
*(*c)++ = (uint8_t) ((s->bitstream >> s->residue) & 0xFF);
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
while (s->residue < (unsigned int) bits)
|
||||
{
|
||||
x = (unsigned int) *(*c)++;
|
||||
s->bitstream |= (x << s->residue);
|
||||
s->residue += 8;
|
||||
}
|
||||
s->residue -= bits;
|
||||
x = s->bitstream & ((1 << bits) - 1);
|
||||
s->bitstream >>= bits;
|
||||
return x;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
while (s->residue < (unsigned int) bits)
|
||||
{
|
||||
x = (unsigned int) *(*c)++;
|
||||
s->bitstream = (s->bitstream << 8) | x;
|
||||
s->residue += 8;
|
||||
}
|
||||
s->residue -= bits;
|
||||
x = (s->bitstream >> s->residue) & ((1 << bits) - 1);
|
||||
return x;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void bitstream_flush(bitstream_state_t *s, uint8_t **c)
|
||||
{
|
||||
if (s->residue > 0)
|
||||
{
|
||||
*(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF);
|
||||
s->residue = 0;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void bitstream_flush2(bitstream_state_t *s, uint8_t **c)
|
||||
{
|
||||
if (s->residue > 0)
|
||||
{
|
||||
*(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF);
|
||||
s->residue = 0;
|
||||
}
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
bitstream_state_t *bitstream_init(bitstream_state_t *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
s->bitstream = 0;
|
||||
s->residue = 0;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
89
src/libs/g722/g722_bitstream.h
Normal file
89
src/libs/g722/g722_bitstream.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* bitstream.h - Bitstream composition and decomposition routines.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2006 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the Lesser GNU General Public License version 2.1, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: bitstream.h,v 1.8 2007/12/13 11:31:32 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_BITSTREAM_H_)
|
||||
#define _SPANDSP_BITSTREAM_H_
|
||||
|
||||
/*! \page bitstream_page Bitstream composition and decomposition
|
||||
\section bitstream_page_sec_1 What does it do?
|
||||
|
||||
\section bitstream_page_sec_2 How does it work?
|
||||
*/
|
||||
|
||||
/*! Bitstream handler state */
|
||||
typedef struct
|
||||
{
|
||||
/*! The bit stream. */
|
||||
unsigned int bitstream;
|
||||
/*! The residual bits in bitstream. */
|
||||
unsigned int residue;
|
||||
} bitstream_state_t;
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*! \brief Put a chunk of bits into the output buffer.
|
||||
\param s A pointer to the bitstream context.
|
||||
\param c A pointer to the bitstream output buffer.
|
||||
\param value The value to be pushed into the output buffer.
|
||||
\param bits The number of bits of value to be pushed. 1 to 25 bit is valid. */
|
||||
void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits);
|
||||
|
||||
void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits);
|
||||
|
||||
/*! \brief Get a chunk of bits from the input buffer.
|
||||
\param s A pointer to the bitstream context.
|
||||
\param c A pointer to the bitstream input buffer.
|
||||
\param bits The number of bits of value to be grabbed. 1 to 25 bit is valid.
|
||||
\return The value retrieved from the input buffer. */
|
||||
unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits);
|
||||
|
||||
unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits);
|
||||
|
||||
/*! \brief Flush any residual bit to the output buffer.
|
||||
\param s A pointer to the bitstream context.
|
||||
\param c A pointer to the bitstream output buffer. */
|
||||
void bitstream_flush(bitstream_state_t *s, uint8_t **c);
|
||||
|
||||
void bitstream_flush2(bitstream_state_t *s, uint8_t **c);
|
||||
|
||||
/*! \brief Initialise a bitstream context.
|
||||
\param s A pointer to the bitstream context.
|
||||
\return A pointer to the bitstream context. */
|
||||
bitstream_state_t *bitstream_init(bitstream_state_t *s);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
157
src/libs/g722/g722_dc_restore.h
Normal file
157
src/libs/g722/g722_dc_restore.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* dc_restore.h - General telephony routines to restore the zero D.C.
|
||||
* level to audio which has a D.C. bias.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: dc_restore.h,v 1.18 2007/04/08 08:16:17 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_SPANDSP_DC_RESTORE_H_)
|
||||
#define _SPANDSP_DC_RESTORE_H_
|
||||
|
||||
/*! \page dc_restore_page Removing DC bias from a signal
|
||||
|
||||
\section dc_restore_page_sec_1 What does it do?
|
||||
|
||||
Telecoms signals often contain considerable DC, but DC upsets a lot of signal
|
||||
processing functions. Placing a zero DC restorer at the front of the processing
|
||||
chain can often simplify the downstream processing.
|
||||
|
||||
\section dc_restore_page_sec_2 How does it work?
|
||||
|
||||
The DC restorer uses a leaky integrator to provide a long-ish term estimate of
|
||||
the DC bias in the signal. A 32 bit estimate is used for the 16 bit audio, so
|
||||
the noise introduced by the estimation can be keep in the lower bits, and the 16
|
||||
bit DC value, which is subtracted from the signal, is fairly clean. The
|
||||
following code fragment shows the algorithm used. dc_bias is a 32 bit integer,
|
||||
while the sample and the resulting clean_sample are 16 bit integers.
|
||||
|
||||
dc_bias += ((((int32_t) sample << 15) - dc_bias) >> 14);
|
||||
clean_sample = sample - (dc_bias >> 15);
|
||||
*/
|
||||
|
||||
/*!
|
||||
Zero DC restoration descriptor. This defines the working state for a single
|
||||
instance of DC content filter.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int32_t state;
|
||||
} dc_restore_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
static __inline__ void dc_restore_init(dc_restore_state_t *dc)
|
||||
{
|
||||
dc->state = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ int16_t dc_restore(dc_restore_state_t *dc, int16_t sample)
|
||||
{
|
||||
dc->state += ((((int32_t) sample << 15) - dc->state) >> 14);
|
||||
return (int16_t) (sample - (dc->state >> 15));
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc)
|
||||
{
|
||||
return (int16_t) (dc->state >> 15);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ int16_t saturate(int32_t amp)
|
||||
{
|
||||
int16_t amp16;
|
||||
|
||||
/* Hopefully this is optimised for the common case - not clipping */
|
||||
amp16 = (int16_t) amp;
|
||||
if (amp == amp16)
|
||||
return amp16;
|
||||
if (amp > INT16_MAX)
|
||||
return INT16_MAX;
|
||||
return INT16_MIN;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/*#ifdef _MSC_VER
|
||||
__inline float rintf (float flt)
|
||||
{
|
||||
_asm
|
||||
{ fld flt
|
||||
frndint
|
||||
}
|
||||
}
|
||||
|
||||
__inline double rint(double dbl)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
fld dbl
|
||||
frndint
|
||||
}
|
||||
}
|
||||
|
||||
__inline long lrintf (float flt)
|
||||
{
|
||||
long retval;
|
||||
_asm
|
||||
{ fld flt
|
||||
fistp retval
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
static __inline__ int16_t fsaturatef(float famp)
|
||||
{
|
||||
if (famp > 32767.0)
|
||||
return INT16_MAX;
|
||||
if (famp < -32768.0)
|
||||
return INT16_MIN;
|
||||
return (int16_t) rintf(famp);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static __inline__ int16_t fsaturate(double damp)
|
||||
{
|
||||
if (damp > 32767.0)
|
||||
return INT16_MAX;
|
||||
if (damp < -32768.0)
|
||||
return INT16_MIN;
|
||||
return (int16_t) rint(damp);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
403
src/libs/g722/g722_decode.c
Normal file
403
src/libs/g722/g722_decode.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* g722_decode.c - The ITU G.722 codec, decode part.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2005 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, or
|
||||
* the Lesser GNU General Public License version 2.1, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Based in part on a single channel G.722 codec which is:
|
||||
*
|
||||
* Copyright (c) CMU 1993
|
||||
* Computer Science, Speech Group
|
||||
* Chengxiang Lu and Alex Hauptmann
|
||||
*
|
||||
* $Id: g722_decode.c,v 1.20 2008/02/09 15:32:56 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "g722_inttypes.h"
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#include "g722_telephony.h"
|
||||
#include "g722_dc_restore.h"
|
||||
#include "g722.h"
|
||||
|
||||
static void block4(g722_decode_state_t *s, int band, int d);
|
||||
|
||||
static void block4(g722_decode_state_t *s, int band, int d)
|
||||
{
|
||||
int wd1;
|
||||
int wd2;
|
||||
int wd3;
|
||||
int i;
|
||||
|
||||
/* Block 4, RECONS */
|
||||
s->band[band].d[0] = d;
|
||||
s->band[band].r[0] = saturate(s->band[band].s + d);
|
||||
|
||||
/* Block 4, PARREC */
|
||||
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
||||
|
||||
/* Block 4, UPPOL2 */
|
||||
for (i = 0; i < 3; i++)
|
||||
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
||||
wd1 = saturate(s->band[band].a[1] << 2);
|
||||
|
||||
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
||||
if (wd2 > 32767)
|
||||
wd2 = 32767;
|
||||
wd3 = (s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128;
|
||||
wd3 += (wd2 >> 7);
|
||||
wd3 += (s->band[band].a[2]*32512) >> 15;
|
||||
if (wd3 > 12288)
|
||||
wd3 = 12288;
|
||||
else if (wd3 < -12288)
|
||||
wd3 = -12288;
|
||||
s->band[band].ap[2] = wd3;
|
||||
|
||||
/* Block 4, UPPOL1 */
|
||||
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
||||
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
||||
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
||||
wd2 = (s->band[band].a[1]*32640) >> 15;
|
||||
|
||||
s->band[band].ap[1] = saturate(wd1 + wd2);
|
||||
wd3 = saturate(15360 - s->band[band].ap[2]);
|
||||
if (s->band[band].ap[1] > wd3)
|
||||
s->band[band].ap[1] = wd3;
|
||||
else if (s->band[band].ap[1] < -wd3)
|
||||
s->band[band].ap[1] = -wd3;
|
||||
|
||||
/* Block 4, UPZERO */
|
||||
wd1 = (d == 0) ? 0 : 128;
|
||||
s->band[band].sg[0] = d >> 15;
|
||||
for (i = 1; i < 7; i++)
|
||||
{
|
||||
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
||||
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
||||
wd3 = (s->band[band].b[i]*32640) >> 15;
|
||||
s->band[band].bp[i] = saturate(wd2 + wd3);
|
||||
}
|
||||
|
||||
/* Block 4, DELAYA */
|
||||
for (i = 6; i > 0; i--)
|
||||
{
|
||||
s->band[band].d[i] = s->band[band].d[i - 1];
|
||||
s->band[band].b[i] = s->band[band].bp[i];
|
||||
}
|
||||
|
||||
for (i = 2; i > 0; i--)
|
||||
{
|
||||
s->band[band].r[i] = s->band[band].r[i - 1];
|
||||
s->band[band].p[i] = s->band[band].p[i - 1];
|
||||
s->band[band].a[i] = s->band[band].ap[i];
|
||||
}
|
||||
|
||||
/* Block 4, FILTEP */
|
||||
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
||||
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
||||
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
||||
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
||||
s->band[band].sp = saturate(wd1 + wd2);
|
||||
|
||||
/* Block 4, FILTEZ */
|
||||
s->band[band].sz = 0;
|
||||
for (i = 6; i > 0; i--)
|
||||
{
|
||||
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
||||
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
||||
}
|
||||
s->band[band].sz = saturate(s->band[band].sz);
|
||||
|
||||
/* Block 4, PREDIC */
|
||||
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
if (rate == 48000)
|
||||
s->bits_per_sample = 6;
|
||||
else if (rate == 56000)
|
||||
s->bits_per_sample = 7;
|
||||
else
|
||||
s->bits_per_sample = 8;
|
||||
if ((options & G722_SAMPLE_RATE_8000))
|
||||
s->eight_k = TRUE;
|
||||
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
||||
s->packed = TRUE;
|
||||
else
|
||||
s->packed = FALSE;
|
||||
s->band[0].det = 32;
|
||||
s->band[1].det = 8;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g722_decode_release(g722_decode_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len)
|
||||
{
|
||||
static const int wl[8] =
|
||||
{
|
||||
-60, -30, 58, 172, 334, 538, 1198, 3042
|
||||
};
|
||||
static const int rl42[16] =
|
||||
{
|
||||
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
};
|
||||
static const int ilb[32] =
|
||||
{
|
||||
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
||||
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
||||
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
||||
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
||||
3756, 3838, 3922, 4008
|
||||
};
|
||||
static const int wh[3] =
|
||||
{
|
||||
0, -214, 798
|
||||
};
|
||||
static const int rh2[4] =
|
||||
{
|
||||
2, 1, 2, 1
|
||||
};
|
||||
static const int qm2[4] =
|
||||
{
|
||||
-7408, -1616, 7408, 1616
|
||||
};
|
||||
static const int qm4[16] =
|
||||
{
|
||||
0, -20456, -12896, -8968,
|
||||
-6288, -4240, -2584, -1200,
|
||||
20456, 12896, 8968, 6288,
|
||||
4240, 2584, 1200, 0
|
||||
};
|
||||
static const int qm5[32] =
|
||||
{
|
||||
-280, -280, -23352, -17560,
|
||||
-14120, -11664, -9752, -8184,
|
||||
-6864, -5712, -4696, -3784,
|
||||
-2960, -2208, -1520, -880,
|
||||
23352, 17560, 14120, 11664,
|
||||
9752, 8184, 6864, 5712,
|
||||
4696, 3784, 2960, 2208,
|
||||
1520, 880, 280, -280
|
||||
};
|
||||
static const int qm6[64] =
|
||||
{
|
||||
-136, -136, -136, -136,
|
||||
-24808, -21904, -19008, -16704,
|
||||
-14984, -13512, -12280, -11192,
|
||||
-10232, -9360, -8576, -7856,
|
||||
-7192, -6576, -6000, -5456,
|
||||
-4944, -4464, -4008, -3576,
|
||||
-3168, -2776, -2400, -2032,
|
||||
-1688, -1360, -1040, -728,
|
||||
24808, 21904, 19008, 16704,
|
||||
14984, 13512, 12280, 11192,
|
||||
10232, 9360, 8576, 7856,
|
||||
7192, 6576, 6000, 5456,
|
||||
4944, 4464, 4008, 3576,
|
||||
3168, 2776, 2400, 2032,
|
||||
1688, 1360, 1040, 728,
|
||||
432, 136, -432, -136
|
||||
};
|
||||
static const int qmf_coeffs[12] =
|
||||
{
|
||||
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
||||
};
|
||||
int dlowt;
|
||||
int rlow;
|
||||
int ihigh;
|
||||
int dhigh;
|
||||
int rhigh;
|
||||
int xout1;
|
||||
int xout2;
|
||||
int wd1;
|
||||
int wd2;
|
||||
int wd3;
|
||||
int code;
|
||||
int outlen;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
outlen = 0;
|
||||
rhigh = 0;
|
||||
for (j = 0; j < len; )
|
||||
{
|
||||
if (s->packed)
|
||||
{
|
||||
/* Unpack the code bits */
|
||||
if (s->in_bits < s->bits_per_sample)
|
||||
{
|
||||
s->in_buffer |= (g722_data[j++] << s->in_bits);
|
||||
s->in_bits += 8;
|
||||
}
|
||||
code = s->in_buffer & ((1 << s->bits_per_sample) - 1);
|
||||
s->in_buffer >>= s->bits_per_sample;
|
||||
s->in_bits -= s->bits_per_sample;
|
||||
}
|
||||
else
|
||||
{
|
||||
code = g722_data[j++];
|
||||
}
|
||||
|
||||
switch (s->bits_per_sample)
|
||||
{
|
||||
default:
|
||||
case 8:
|
||||
wd1 = code & 0x3F;
|
||||
ihigh = (code >> 6) & 0x03;
|
||||
wd2 = qm6[wd1];
|
||||
wd1 >>= 2;
|
||||
break;
|
||||
case 7:
|
||||
wd1 = code & 0x1F;
|
||||
ihigh = (code >> 5) & 0x03;
|
||||
wd2 = qm5[wd1];
|
||||
wd1 >>= 1;
|
||||
break;
|
||||
case 6:
|
||||
wd1 = code & 0x0F;
|
||||
ihigh = (code >> 4) & 0x03;
|
||||
wd2 = qm4[wd1];
|
||||
break;
|
||||
}
|
||||
/* Block 5L, LOW BAND INVQBL */
|
||||
wd2 = (s->band[0].det*wd2) >> 15;
|
||||
/* Block 5L, RECONS */
|
||||
rlow = s->band[0].s + wd2;
|
||||
/* Block 6L, LIMIT */
|
||||
if (rlow > 16383)
|
||||
rlow = 16383;
|
||||
else if (rlow < -16384)
|
||||
rlow = -16384;
|
||||
|
||||
/* Block 2L, INVQAL */
|
||||
wd2 = qm4[wd1];
|
||||
dlowt = (s->band[0].det*wd2) >> 15;
|
||||
|
||||
/* Block 3L, LOGSCL */
|
||||
wd2 = rl42[wd1];
|
||||
wd1 = (s->band[0].nb*127) >> 7;
|
||||
wd1 += wl[wd2];
|
||||
if (wd1 < 0)
|
||||
wd1 = 0;
|
||||
else if (wd1 > 18432)
|
||||
wd1 = 18432;
|
||||
s->band[0].nb = wd1;
|
||||
|
||||
/* Block 3L, SCALEL */
|
||||
wd1 = (s->band[0].nb >> 6) & 31;
|
||||
wd2 = 8 - (s->band[0].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[0].det = wd3 << 2;
|
||||
|
||||
block4(s, 0, dlowt);
|
||||
|
||||
if (!s->eight_k)
|
||||
{
|
||||
/* Block 2H, INVQAH */
|
||||
wd2 = qm2[ihigh];
|
||||
dhigh = (s->band[1].det*wd2) >> 15;
|
||||
/* Block 5H, RECONS */
|
||||
rhigh = dhigh + s->band[1].s;
|
||||
/* Block 6H, LIMIT */
|
||||
if (rhigh > 16383)
|
||||
rhigh = 16383;
|
||||
else if (rhigh < -16384)
|
||||
rhigh = -16384;
|
||||
|
||||
/* Block 2H, INVQAH */
|
||||
wd2 = rh2[ihigh];
|
||||
wd1 = (s->band[1].nb*127) >> 7;
|
||||
wd1 += wh[wd2];
|
||||
if (wd1 < 0)
|
||||
wd1 = 0;
|
||||
else if (wd1 > 22528)
|
||||
wd1 = 22528;
|
||||
s->band[1].nb = wd1;
|
||||
|
||||
/* Block 3H, SCALEH */
|
||||
wd1 = (s->band[1].nb >> 6) & 31;
|
||||
wd2 = 10 - (s->band[1].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[1].det = wd3 << 2;
|
||||
|
||||
block4(s, 1, dhigh);
|
||||
}
|
||||
|
||||
if (s->itu_test_mode)
|
||||
{
|
||||
amp[outlen++] = (int16_t) (rlow << 1);
|
||||
amp[outlen++] = (int16_t) (rhigh << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->eight_k)
|
||||
{
|
||||
amp[outlen++] = (int16_t) rlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Apply the receive QMF */
|
||||
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0]));
|
||||
s->x[22] = rlow + rhigh;
|
||||
s->x[23] = rlow - rhigh;
|
||||
|
||||
xout1 = 0;
|
||||
xout2 = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
xout2 += s->x[2*i]*qmf_coeffs[i];
|
||||
xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i];
|
||||
}
|
||||
amp[outlen++] = (int16_t) (xout1 >> 12);
|
||||
amp[outlen++] = (int16_t) (xout2 >> 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outlen;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
389
src/libs/g722/g722_encode.c
Normal file
389
src/libs/g722/g722_encode.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* g722_encode.c - The ITU G.722 codec, encode part.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2005 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2, or
|
||||
* the Lesser GNU General Public License version 2.1, as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Based on a single channel 64kbps only G.722 codec which is:
|
||||
*
|
||||
***** Copyright (c) CMU 1993 *****
|
||||
* Computer Science, Speech Group
|
||||
* Chengxiang Lu and Alex Hauptmann
|
||||
*
|
||||
* $Id: g722_encode.c,v 1.18 2008/02/09 15:32:56 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "g722_inttypes.h"
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(HAVE_TGMATH_H)
|
||||
#include <tgmath.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#include "g722_telephony.h"
|
||||
#include "g722_dc_restore.h"
|
||||
#include "g722.h"
|
||||
|
||||
static void block4(g722_encode_state_t *s, int band, int d)
|
||||
{
|
||||
int wd1;
|
||||
int wd2;
|
||||
int wd3;
|
||||
int i;
|
||||
|
||||
/* Block 4, RECONS */
|
||||
s->band[band].d[0] = d;
|
||||
s->band[band].r[0] = saturate(s->band[band].s + d);
|
||||
|
||||
/* Block 4, PARREC */
|
||||
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
||||
|
||||
/* Block 4, UPPOL2 */
|
||||
for (i = 0; i < 3; i++)
|
||||
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
||||
wd1 = saturate(s->band[band].a[1] << 2);
|
||||
|
||||
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
||||
if (wd2 > 32767)
|
||||
wd2 = 32767;
|
||||
wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128);
|
||||
wd3 += (s->band[band].a[2]*32512) >> 15;
|
||||
if (wd3 > 12288)
|
||||
wd3 = 12288;
|
||||
else if (wd3 < -12288)
|
||||
wd3 = -12288;
|
||||
s->band[band].ap[2] = wd3;
|
||||
|
||||
/* Block 4, UPPOL1 */
|
||||
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
||||
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
||||
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
||||
wd2 = (s->band[band].a[1]*32640) >> 15;
|
||||
|
||||
s->band[band].ap[1] = saturate(wd1 + wd2);
|
||||
wd3 = saturate(15360 - s->band[band].ap[2]);
|
||||
if (s->band[band].ap[1] > wd3)
|
||||
s->band[band].ap[1] = wd3;
|
||||
else if (s->band[band].ap[1] < -wd3)
|
||||
s->band[band].ap[1] = -wd3;
|
||||
|
||||
/* Block 4, UPZERO */
|
||||
wd1 = (d == 0) ? 0 : 128;
|
||||
s->band[band].sg[0] = d >> 15;
|
||||
for (i = 1; i < 7; i++)
|
||||
{
|
||||
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
||||
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
||||
wd3 = (s->band[band].b[i]*32640) >> 15;
|
||||
s->band[band].bp[i] = saturate(wd2 + wd3);
|
||||
}
|
||||
|
||||
/* Block 4, DELAYA */
|
||||
for (i = 6; i > 0; i--)
|
||||
{
|
||||
s->band[band].d[i] = s->band[band].d[i - 1];
|
||||
s->band[band].b[i] = s->band[band].bp[i];
|
||||
}
|
||||
|
||||
for (i = 2; i > 0; i--)
|
||||
{
|
||||
s->band[band].r[i] = s->band[band].r[i - 1];
|
||||
s->band[band].p[i] = s->band[band].p[i - 1];
|
||||
s->band[band].a[i] = s->band[band].ap[i];
|
||||
}
|
||||
|
||||
/* Block 4, FILTEP */
|
||||
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
||||
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
||||
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
||||
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
||||
s->band[band].sp = saturate(wd1 + wd2);
|
||||
|
||||
/* Block 4, FILTEZ */
|
||||
s->band[band].sz = 0;
|
||||
for (i = 6; i > 0; i--)
|
||||
{
|
||||
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
||||
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
||||
}
|
||||
s->band[band].sz = saturate(s->band[band].sz);
|
||||
|
||||
/* Block 4, PREDIC */
|
||||
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options)
|
||||
{
|
||||
if (s == NULL)
|
||||
{
|
||||
if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
if (rate == 48000)
|
||||
s->bits_per_sample = 6;
|
||||
else if (rate == 56000)
|
||||
s->bits_per_sample = 7;
|
||||
else
|
||||
s->bits_per_sample = 8;
|
||||
if ((options & G722_SAMPLE_RATE_8000))
|
||||
s->eight_k = TRUE;
|
||||
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
||||
s->packed = TRUE;
|
||||
else
|
||||
s->packed = FALSE;
|
||||
s->band[0].det = 32;
|
||||
s->band[1].det = 8;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g722_encode_release(g722_encode_state_t *s)
|
||||
{
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len)
|
||||
{
|
||||
static const int q6[32] =
|
||||
{
|
||||
0, 35, 72, 110, 150, 190, 233, 276,
|
||||
323, 370, 422, 473, 530, 587, 650, 714,
|
||||
786, 858, 940, 1023, 1121, 1219, 1339, 1458,
|
||||
1612, 1765, 1980, 2195, 2557, 2919, 0, 0
|
||||
};
|
||||
static const int iln[32] =
|
||||
{
|
||||
0, 63, 62, 31, 30, 29, 28, 27,
|
||||
26, 25, 24, 23, 22, 21, 20, 19,
|
||||
18, 17, 16, 15, 14, 13, 12, 11,
|
||||
10, 9, 8, 7, 6, 5, 4, 0
|
||||
};
|
||||
static const int ilp[32] =
|
||||
{
|
||||
0, 61, 60, 59, 58, 57, 56, 55,
|
||||
54, 53, 52, 51, 50, 49, 48, 47,
|
||||
46, 45, 44, 43, 42, 41, 40, 39,
|
||||
38, 37, 36, 35, 34, 33, 32, 0
|
||||
};
|
||||
static const int wl[8] =
|
||||
{
|
||||
-60, -30, 58, 172, 334, 538, 1198, 3042
|
||||
};
|
||||
static const int rl42[16] =
|
||||
{
|
||||
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
};
|
||||
static const int ilb[32] =
|
||||
{
|
||||
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
||||
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
||||
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
||||
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
||||
3756, 3838, 3922, 4008
|
||||
};
|
||||
static const int qm4[16] =
|
||||
{
|
||||
0, -20456, -12896, -8968,
|
||||
-6288, -4240, -2584, -1200,
|
||||
20456, 12896, 8968, 6288,
|
||||
4240, 2584, 1200, 0
|
||||
};
|
||||
static const int qm2[4] =
|
||||
{
|
||||
-7408, -1616, 7408, 1616
|
||||
};
|
||||
static const int qmf_coeffs[12] =
|
||||
{
|
||||
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
||||
};
|
||||
static const int ihn[3] = {0, 1, 0};
|
||||
static const int ihp[3] = {0, 3, 2};
|
||||
static const int wh[3] = {0, -214, 798};
|
||||
static const int rh2[4] = {2, 1, 2, 1};
|
||||
|
||||
int dlow;
|
||||
int dhigh;
|
||||
int el;
|
||||
int wd;
|
||||
int wd1;
|
||||
int ril;
|
||||
int wd2;
|
||||
int il4;
|
||||
int ih2;
|
||||
int wd3;
|
||||
int eh;
|
||||
int mih;
|
||||
int i;
|
||||
int j;
|
||||
/* Low and high band PCM from the QMF */
|
||||
int xlow;
|
||||
int xhigh;
|
||||
int g722_bytes;
|
||||
/* Even and odd tap accumulators */
|
||||
int sumeven;
|
||||
int sumodd;
|
||||
int ihigh;
|
||||
int ilow;
|
||||
int code;
|
||||
|
||||
g722_bytes = 0;
|
||||
xhigh = 0;
|
||||
for (j = 0; j < len; )
|
||||
{
|
||||
if (s->itu_test_mode)
|
||||
{
|
||||
xlow =
|
||||
xhigh = amp[j++] >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->eight_k)
|
||||
{
|
||||
xlow = amp[j++];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Apply the transmit QMF */
|
||||
/* Shuffle the buffer down */
|
||||
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0]));
|
||||
s->x[22] = amp[j++];
|
||||
s->x[23] = amp[j++];
|
||||
|
||||
/* Discard every other QMF output */
|
||||
sumeven = 0;
|
||||
sumodd = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
sumodd += s->x[2*i]*qmf_coeffs[i];
|
||||
sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
|
||||
}
|
||||
xlow = (sumeven + sumodd) >> 13;
|
||||
xhigh = (sumeven - sumodd) >> 13;
|
||||
}
|
||||
}
|
||||
/* Block 1L, SUBTRA */
|
||||
el = saturate(xlow - s->band[0].s);
|
||||
|
||||
/* Block 1L, QUANTL */
|
||||
wd = (el >= 0) ? el : -(el + 1);
|
||||
|
||||
for (i = 1; i < 30; i++)
|
||||
{
|
||||
wd1 = (q6[i]*s->band[0].det) >> 12;
|
||||
if (wd < wd1)
|
||||
break;
|
||||
}
|
||||
ilow = (el < 0) ? iln[i] : ilp[i];
|
||||
|
||||
/* Block 2L, INVQAL */
|
||||
ril = ilow >> 2;
|
||||
wd2 = qm4[ril];
|
||||
dlow = (s->band[0].det*wd2) >> 15;
|
||||
|
||||
/* Block 3L, LOGSCL */
|
||||
il4 = rl42[ril];
|
||||
wd = (s->band[0].nb*127) >> 7;
|
||||
s->band[0].nb = wd + wl[il4];
|
||||
if (s->band[0].nb < 0)
|
||||
s->band[0].nb = 0;
|
||||
else if (s->band[0].nb > 18432)
|
||||
s->band[0].nb = 18432;
|
||||
|
||||
/* Block 3L, SCALEL */
|
||||
wd1 = (s->band[0].nb >> 6) & 31;
|
||||
wd2 = 8 - (s->band[0].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[0].det = wd3 << 2;
|
||||
|
||||
block4(s, 0, dlow);
|
||||
|
||||
if (s->eight_k)
|
||||
{
|
||||
/* Just leave the high bits as zero */
|
||||
code = (0xC0 | ilow) >> (8 - s->bits_per_sample);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Block 1H, SUBTRA */
|
||||
eh = saturate(xhigh - s->band[1].s);
|
||||
|
||||
/* Block 1H, QUANTH */
|
||||
wd = (eh >= 0) ? eh : -(eh + 1);
|
||||
wd1 = (564*s->band[1].det) >> 12;
|
||||
mih = (wd >= wd1) ? 2 : 1;
|
||||
ihigh = (eh < 0) ? ihn[mih] : ihp[mih];
|
||||
|
||||
/* Block 2H, INVQAH */
|
||||
wd2 = qm2[ihigh];
|
||||
dhigh = (s->band[1].det*wd2) >> 15;
|
||||
|
||||
/* Block 3H, LOGSCH */
|
||||
ih2 = rh2[ihigh];
|
||||
wd = (s->band[1].nb*127) >> 7;
|
||||
s->band[1].nb = wd + wh[ih2];
|
||||
if (s->band[1].nb < 0)
|
||||
s->band[1].nb = 0;
|
||||
else if (s->band[1].nb > 22528)
|
||||
s->band[1].nb = 22528;
|
||||
|
||||
/* Block 3H, SCALEH */
|
||||
wd1 = (s->band[1].nb >> 6) & 31;
|
||||
wd2 = 10 - (s->band[1].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[1].det = wd3 << 2;
|
||||
|
||||
block4(s, 1, dhigh);
|
||||
code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample);
|
||||
}
|
||||
|
||||
if (s->packed)
|
||||
{
|
||||
/* Pack the code bits */
|
||||
s->out_buffer |= (code << s->out_bits);
|
||||
s->out_bits += s->bits_per_sample;
|
||||
if (s->out_bits >= 8)
|
||||
{
|
||||
g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF);
|
||||
s->out_bits -= 8;
|
||||
s->out_buffer >>= 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g722_data[g722_bytes++] = (uint8_t) code;
|
||||
}
|
||||
}
|
||||
return g722_bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
103
src/libs/g722/g722_inttypes.h
Normal file
103
src/libs/g722/g722_inttypes.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* inttypes.h - a fudge for MSVC, which lacks this header
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2006 Michael Jerris
|
||||
*
|
||||
*
|
||||
* This file is released in the public domain.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(_INTTYPES_H_)
|
||||
#define _INTTYPES_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if (_MSC_VER >= 1400) // VC8+
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#endif // VC8+
|
||||
|
||||
#include <windows.h>
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
#define inline __inline
|
||||
#define __inline__ __inline
|
||||
#define INT16_MAX 0x7fff
|
||||
#define INT16_MIN (-INT16_MAX - 1)
|
||||
#define _MMX_H_
|
||||
|
||||
/* disable the following warnings
|
||||
* C4100: The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored.
|
||||
* C4200: Non standard extension C zero sized array
|
||||
* C4706: assignment within conditional expression
|
||||
* C4244: conversion from 'type1' to 'type2', possible loss of data
|
||||
* C4295: array is too small to include a terminating null character
|
||||
* C4125: decimal digit terminates octal escape sequence
|
||||
*/
|
||||
#pragma warning(disable:4100 4200 4706 4295 4125)
|
||||
|
||||
//#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#define snprintf _snprintf
|
||||
|
||||
#if !defined(INFINITY)
|
||||
#define INFINITY 0x7fffffff
|
||||
#endif
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define PACKAGE "voipcodecs"
|
||||
#define VERSION "0.0.1andabit"
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-2147483647 - 1)
|
||||
#endif
|
||||
|
||||
#define PRId8 "d"
|
||||
#define PRId16 "d"
|
||||
#ifndef PRId32
|
||||
# define PRId32 "ld"
|
||||
#endif
|
||||
|
||||
#ifndef PRId64
|
||||
# define PRId64 "lld"
|
||||
#endif
|
||||
|
||||
#define PRIu8 "u"
|
||||
#define PRIu16 "u"
|
||||
#ifndef PRIu32
|
||||
# define PRIu32 "lu"
|
||||
#endif
|
||||
#ifndef PRIu64
|
||||
# define PRIu64 "llu"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INTTYPES_H_
|
||||
|
||||
74
src/libs/g722/g722_telephony.h
Normal file
74
src/libs/g722/g722_telephony.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* VoIPcodecs - a series of DSP components for telephony
|
||||
*
|
||||
* telephony.h - some very basic telephony definitions
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the Lesser GNU General Public License version 2.1, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: telephony.h,v 1.10 2007/04/05 19:20:50 steveu Exp $
|
||||
*/
|
||||
|
||||
#if !defined(_SPANDSP_TELEPHONY_H_)
|
||||
#define _SPANDSP_TELEPHONY_H_
|
||||
|
||||
#define SAMPLE_RATE 8000
|
||||
|
||||
/* This is based on A-law, but u-law is only 0.03dB different */
|
||||
#define DBM0_MAX_POWER (3.14f + 3.02f)
|
||||
#define DBM0_MAX_SINE_POWER (3.14f)
|
||||
/* This is based on the ITU definition of dbOv in G.100.1 */
|
||||
#define DBOV_MAX_POWER (0.0f)
|
||||
#define DBOV_MAX_SINE_POWER (-3.02f)
|
||||
|
||||
/*! \brief A handler for pure receive. The buffer cannot be altered. */
|
||||
typedef int (span_rx_handler_t)(void *s, const int16_t amp[], int len);
|
||||
|
||||
/*! \brief A handler for receive, where the buffer can be altered. */
|
||||
typedef int (span_mod_handler_t)(void *s, int16_t amp[], int len);
|
||||
|
||||
/*! \brief A handler for transmit, where the buffer will be filled. */
|
||||
typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len);
|
||||
|
||||
#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
|
||||
|
||||
#if !defined(FALSE)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#if !defined(TRUE)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#if (_MSC_VER >= 1400) // VC8+
|
||||
#define vc_assert(expr) assert(expr);__analysis_assume( expr )
|
||||
#else
|
||||
#define vc_assert(expr) assert(expr)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
/* C++ doesn't seem to have sane rounding functions/macros yet */
|
||||
#ifndef _MSC_VER
|
||||
#define lrint(x) ((long int) (x))
|
||||
#define lrintf(x) ((long int) (x))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
300
src/libs/g722/g722codec.c
Normal file
300
src/libs/g722/g722codec.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* G.722 Plugin codec for OpenH323/OPAL
|
||||
*
|
||||
* Copyright (C) 2008 by Hermon Labs, All Rights Reserved
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Open Phone Abstraction Library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Eugene Mednikov
|
||||
*
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
* $Revision: 23265 $
|
||||
* $Author: rjongbloed $
|
||||
* $Date: 2009-08-25 04:25:58 +0300 (вт, 25 серп 2009) $
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_CODEC_DLL_EXPORTS
|
||||
#include "plugin-config.h"
|
||||
#endif
|
||||
|
||||
#include <codec/opalplugin.h>
|
||||
|
||||
#include "VoIPCodecs/inttypes.h"
|
||||
#include "VoIPCodecs/g722.h"
|
||||
|
||||
|
||||
#define INCLUDE_SDP_16000_VERSION 0
|
||||
|
||||
/* Due to a spec error, clock rate is 8kHz even though this is 16kHz codec,
|
||||
see RFC3551/4.5.2. So some of these values have to be lied about so that
|
||||
the OPAL system gets it right.
|
||||
*/
|
||||
#define CLOCK_RATE 8000 // Clock rate is not samples/second in this case!
|
||||
#define BITS_PER_SECOND 64000 // raw bits per second
|
||||
#define FRAME_TIME 1000 // Microseconds in a millisecond
|
||||
#define SAMPLES_PER_FRAME 16 // Samples in a millisecond
|
||||
#define BYTES_PER_FRAME 8 // Bytes in a millisecond
|
||||
#define MAX_FRAMES_PER_PACKET 90 // 90 milliseconds, which means RTP packets smaller than 1500 bytes typical LAN maximum
|
||||
#define PREF_FRAMES_PER_PACKET 20 // 20 milliseconds
|
||||
|
||||
static const char L16Desc[] = "PCM-16-16kHz"; // Cannot use "L16" as usual, force 16kHz PCM
|
||||
static const char g722[] = "G.722-64k";
|
||||
static const char sdpG722[] = "G722";
|
||||
|
||||
#if INCLUDE_SDP_16000_VERSION
|
||||
static const char g722_16[] = "G.722-16kHz";
|
||||
#endif
|
||||
|
||||
#define PAYLOAD_CODE 9
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void * create_encoder(const struct PluginCodec_Definition * codec)
|
||||
{
|
||||
return g722_encode_init(NULL, BITS_PER_SECOND, 0);
|
||||
}
|
||||
|
||||
static void destroy_encoder(const struct PluginCodec_Definition * codec, void * context)
|
||||
{
|
||||
g722_encode_release(context);
|
||||
}
|
||||
|
||||
static int encode(const struct PluginCodec_Definition * codec,
|
||||
void * context,
|
||||
const void * from,
|
||||
unsigned * fromLen,
|
||||
void * to,
|
||||
unsigned * toLen,
|
||||
unsigned int * flag)
|
||||
{
|
||||
g722_encode_state_t * state = context;
|
||||
|
||||
if (*toLen < *fromLen / 4)
|
||||
return 0; // Destination buffer not big enough
|
||||
|
||||
*toLen = g722_encode(state, to, from, *fromLen / 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void * create_decoder(const struct PluginCodec_Definition * codec)
|
||||
{
|
||||
return g722_decode_init(NULL, BITS_PER_SECOND, 0);
|
||||
}
|
||||
|
||||
static void destroy_decoder(const struct PluginCodec_Definition * codec, void * context)
|
||||
{
|
||||
g722_decode_release(context);
|
||||
}
|
||||
|
||||
|
||||
static int decode(const struct PluginCodec_Definition * codec,
|
||||
void * _context,
|
||||
const void * from,
|
||||
unsigned * fromLen,
|
||||
void * to,
|
||||
unsigned * toLen,
|
||||
unsigned int * flag)
|
||||
{
|
||||
g722_decode_state_t * state = _context;
|
||||
|
||||
if (*toLen < *fromLen * 4)
|
||||
return 0; // Destination buffer not big enough
|
||||
|
||||
*toLen = g722_decode(state, to, from, *fromLen) * 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static struct PluginCodec_information licenseInfo = {
|
||||
1084181196, // timestamp = Mon 10 May 2004 09:26:36 AM UTC
|
||||
|
||||
"Eugene Mednikov", // source code author
|
||||
"1.0", // source code version
|
||||
"em@hermonlabs.com", // source code email
|
||||
"http://www.hermonlabs.com", // source code URL
|
||||
"Copyright (C) 2008 by Hermon Labs, All Rights Reserved", // source code copyright
|
||||
"MPL 1.0", // source code license
|
||||
PluginCodec_License_MPL, // source code license
|
||||
|
||||
"ITU G.722", // codec description
|
||||
"Steve Underwood", // codec author
|
||||
NULL, // codec version
|
||||
"steveu@coppice.org", // codec email
|
||||
NULL, // codec URL
|
||||
NULL, // codec copyright information
|
||||
NULL, // codec license
|
||||
PluginCodec_License_LGPL // codec license code
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static struct PluginCodec_Definition g722CodecDefn[] =
|
||||
{
|
||||
#if INCLUDE_SDP_16000_VERSION
|
||||
// Include a version for SIP/SDP that indicates the more logical, though
|
||||
// incorrect by RFC3551/4.5.2, 16000Hz version of G.722. We use dynamic
|
||||
// payload types to avoid conflict with the compliant 8000Hz version.
|
||||
{
|
||||
// encoder
|
||||
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
|
||||
&licenseInfo, // license information
|
||||
|
||||
PluginCodec_MediaTypeAudio | // audio codec
|
||||
PluginCodec_InputTypeRaw | // raw input data
|
||||
PluginCodec_OutputTypeRaw | // raw output data
|
||||
PluginCodec_RTPTypeDynamic, // specified RTP type
|
||||
|
||||
g722_16, // text decription
|
||||
L16Desc, // source format
|
||||
g722_16, // destination format
|
||||
|
||||
0, // user data
|
||||
|
||||
16000, // samples per second
|
||||
BITS_PER_SECOND, // raw bits per second
|
||||
FRAME_TIME, // microseconds per frame
|
||||
SAMPLES_PER_FRAME, // samples per frame
|
||||
BYTES_PER_FRAME, // bytes per frame
|
||||
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
|
||||
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
|
||||
PAYLOAD_CODE, // IANA RTP payload code
|
||||
sdpG722, // RTP payload name
|
||||
|
||||
create_encoder, // create codec function
|
||||
destroy_encoder, // destroy codec
|
||||
encode, // encode/decode
|
||||
NULL, // codec controls
|
||||
|
||||
0, // h323CapabilityType
|
||||
NULL // h323CapabilityData
|
||||
},
|
||||
|
||||
{
|
||||
// decoder
|
||||
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
|
||||
&licenseInfo, // license information
|
||||
|
||||
PluginCodec_MediaTypeAudio | // audio codec
|
||||
PluginCodec_InputTypeRaw | // raw input data
|
||||
PluginCodec_OutputTypeRaw | // raw output data
|
||||
PluginCodec_RTPTypeDynamic, // specified RTP type
|
||||
|
||||
g722_16, // text decription
|
||||
g722_16, // source format
|
||||
L16Desc, // destination format
|
||||
|
||||
0, // user data
|
||||
|
||||
16000, // samples per second
|
||||
BITS_PER_SECOND, // raw bits per second
|
||||
FRAME_TIME, // microseconds per frame
|
||||
SAMPLES_PER_FRAME, // samples per frame
|
||||
BYTES_PER_FRAME, // bytes per frame
|
||||
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
|
||||
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
|
||||
PAYLOAD_CODE, // IANA RTP payload code
|
||||
sdpG722, // RTP payload name
|
||||
|
||||
create_decoder, // create codec function
|
||||
destroy_decoder, // destroy codec
|
||||
decode, // encode/decode
|
||||
NULL, // codec controls
|
||||
|
||||
0, // h323CapabilityType
|
||||
NULL // h323CapabilityData
|
||||
},
|
||||
#endif
|
||||
|
||||
// Standards compliant version
|
||||
{
|
||||
// encoder
|
||||
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
|
||||
&licenseInfo, // license information
|
||||
|
||||
PluginCodec_MediaTypeAudio | // audio codec
|
||||
PluginCodec_InputTypeRaw | // raw input data
|
||||
PluginCodec_OutputTypeRaw | // raw output data
|
||||
PluginCodec_RTPTypeExplicit, // specified RTP type
|
||||
|
||||
g722, // text decription
|
||||
L16Desc, // source format
|
||||
g722, // destination format
|
||||
|
||||
0, // user data
|
||||
|
||||
CLOCK_RATE, // samples per second
|
||||
BITS_PER_SECOND, // raw bits per second
|
||||
FRAME_TIME, // microseconds per frame
|
||||
SAMPLES_PER_FRAME, // samples per frame
|
||||
BYTES_PER_FRAME, // bytes per frame
|
||||
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
|
||||
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
|
||||
PAYLOAD_CODE, // IANA RTP payload code
|
||||
sdpG722, // RTP payload name
|
||||
|
||||
create_encoder, // create codec function
|
||||
destroy_encoder, // destroy codec
|
||||
encode, // encode/decode
|
||||
NULL, // codec controls
|
||||
|
||||
PluginCodec_H323AudioCodec_g722_64k, // h323CapabilityType
|
||||
NULL // h323CapabilityData
|
||||
},
|
||||
|
||||
{
|
||||
// decoder
|
||||
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
|
||||
&licenseInfo, // license information
|
||||
|
||||
PluginCodec_MediaTypeAudio | // audio codec
|
||||
PluginCodec_InputTypeRaw | // raw input data
|
||||
PluginCodec_OutputTypeRaw | // raw output data
|
||||
PluginCodec_RTPTypeExplicit, // specified RTP type
|
||||
|
||||
g722, // text decription
|
||||
g722, // source format
|
||||
L16Desc, // destination format
|
||||
|
||||
0, // user data
|
||||
|
||||
CLOCK_RATE, // samples per second
|
||||
BITS_PER_SECOND, // raw bits per second
|
||||
FRAME_TIME, // microseconds per frame
|
||||
SAMPLES_PER_FRAME, // samples per frame
|
||||
BYTES_PER_FRAME, // bytes per frame
|
||||
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
|
||||
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
|
||||
PAYLOAD_CODE, // IANA RTP payload code
|
||||
sdpG722, // RTP payload name
|
||||
|
||||
create_decoder, // create codec function
|
||||
destroy_decoder, // destroy codec
|
||||
decode, // encode/decode
|
||||
NULL, // codec controls
|
||||
|
||||
PluginCodec_H323AudioCodec_g722_64k, // h323CapabilityType
|
||||
NULL // h323CapabilityData
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PLUGIN_CODEC_IMPLEMENT_ALL(G722, g722CodecDefn, PLUGIN_CODEC_VERSION_WIDEBAND)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
12
src/libs/gsmhr/CMakeLists.txt
Normal file
12
src/libs/gsmhr/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
project (gsmhr_codec)
|
||||
|
||||
# Rely on C++ 11
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set (GSMHR_SOURCES
|
||||
gsmhr.cpp
|
||||
gsmhr_sp_rom.c
|
||||
)
|
||||
|
||||
add_library(gsmhr_codec ${GSMHR_SOURCES})
|
||||
15726
src/libs/gsmhr/gsmhr.cpp
Normal file
15726
src/libs/gsmhr/gsmhr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
804
src/libs/gsmhr/gsmhr.h
Normal file
804
src/libs/gsmhr/gsmhr.h
Normal file
@@ -0,0 +1,804 @@
|
||||
#ifndef __GSM_HR_CODEC_H
|
||||
#define __GSM_HR_CODEC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "gsmhr_sp_rom.h"
|
||||
|
||||
namespace GsmHr
|
||||
{
|
||||
#define DATE "August 8, 1996 "
|
||||
#define VERSION "Version 4.2 "
|
||||
|
||||
#define LW_SIGN (long)0x80000000 /* sign bit */
|
||||
#define LW_MIN (long)0x80000000
|
||||
#define LW_MAX (long)0x7fffffff
|
||||
|
||||
#define SW_SIGN (short)0x8000 /* sign bit for int16_t type */
|
||||
#define SW_MIN (short)0x8000 /* smallest Ram */
|
||||
#define SW_MAX (short)0x7fff /* largest Ram */
|
||||
#define SPEECH 1
|
||||
#define CNIFIRSTSID 2
|
||||
#define PN_INIT_SEED (int32_t)0x1091988L /* initial seed for Comfort
|
||||
* noise pn-generator */
|
||||
|
||||
#define CNICONT 3
|
||||
#define CNIBFI 4
|
||||
#define VALIDSID 11
|
||||
#define INVALIDSID 22
|
||||
#define GOODSPEECH 33
|
||||
#define UNUSABLE 44
|
||||
|
||||
typedef short int int16_tRom; /* 16 bit ROM data (sr*) */
|
||||
typedef long int int32_tRom; /* 32 bit ROM data (L_r*) */
|
||||
|
||||
struct NormSw
|
||||
{ /* normalized int16_t fractional
|
||||
* number snr.man precedes snr.sh (the
|
||||
* shift count)i */
|
||||
int16_t man; /* "mantissa" stored in 16 bit
|
||||
* location */
|
||||
int16_t sh; /* the shift count, stored in 16 bit
|
||||
* location */
|
||||
};
|
||||
|
||||
|
||||
struct QuantList
|
||||
{
|
||||
/* structure which points to the beginning of a block of candidate vq
|
||||
* vectors. It also stores the residual error for each vector. */
|
||||
int iNum; /* total number in list */
|
||||
int iRCIndex; /* an index to the first vector of the
|
||||
* block */
|
||||
int16_t pswPredErr[PREQ1_NUM_OF_ROWS]; /* PREQ1 is the biggest block */
|
||||
};
|
||||
|
||||
/* Global constants *
|
||||
********************/
|
||||
|
||||
#define NP 10 /* order of the lpc filter */
|
||||
#define N_SUB 4 /* number of subframes */
|
||||
#define F_LEN 160 /* number of samples in a frame */
|
||||
#define S_LEN 40 /* number of samples in a subframe */
|
||||
#define A_LEN 170 /* LPC analysis length */
|
||||
#define OS_FCTR 6 /* maximum LTP lag oversampling
|
||||
* factor */
|
||||
|
||||
#define OVERHANG 8 /* vad parameter */
|
||||
#define strStr strStr16
|
||||
|
||||
#define LTP_LEN 147 /* 147==0x93 length of LTP history */
|
||||
#define CNINTPER 12
|
||||
|
||||
class Codec
|
||||
{
|
||||
protected:
|
||||
|
||||
// From typedefs.h
|
||||
int giFrmCnt; /* 0,1,2,3,4..... */
|
||||
int giSfrmCnt = 0; /* 0,1,2,3 */
|
||||
|
||||
int giDTXon = 1; /* DTX Mode on/off */
|
||||
|
||||
|
||||
// From err_conc.c
|
||||
int32_t plSubfrEnergyMem[4];
|
||||
int16_t swLevelMem[4],
|
||||
lastR0,
|
||||
pswLastGood[18],
|
||||
swState,
|
||||
swLastFlag;
|
||||
|
||||
|
||||
// From sp_dec.c
|
||||
|
||||
int16_t gswPostFiltAgcGain,
|
||||
gpswPostFiltStateNum[NP],
|
||||
gpswPostFiltStateDenom[NP],
|
||||
swPostEmphasisState,
|
||||
pswSynthFiltState[NP],
|
||||
pswOldFrmKsDec[NP],
|
||||
pswOldFrmAsDec[NP],
|
||||
pswOldFrmPFNum[NP],
|
||||
pswOldFrmPFDenom[NP],
|
||||
swOldR0Dec,
|
||||
pswLtpStateBaseDec[LTP_LEN + S_LEN],
|
||||
pswPPreState[LTP_LEN + S_LEN];
|
||||
|
||||
|
||||
int16_t swMuteFlagOld; /* error concealment */
|
||||
|
||||
|
||||
|
||||
int16_t swRxDTXState = CNINTPER - 1; /* DTX State at the rx.
|
||||
* Modulo */
|
||||
|
||||
int16_t swDecoMode = SPEECH;
|
||||
int16_t swDtxMuting = 0;
|
||||
int16_t swDtxBfiCnt = 0;
|
||||
|
||||
int16_t swOldR0IndexDec = 0;
|
||||
|
||||
int16_t swRxGsHistPtr = 0;
|
||||
int32_t pL_RxGsHist[(OVERHANG - 1) * N_SUB];
|
||||
|
||||
int16_t swR0Dec;
|
||||
|
||||
int16_t swVoicingMode, /* MODE */
|
||||
pswVq[3], /* LPC1, LPC2, LPC3 */
|
||||
swSi, /* INT_LPC */
|
||||
swEngyRShift; /* for use by spectral postfilter */
|
||||
|
||||
|
||||
int16_t swR0NewCN; /* DTX mode */
|
||||
|
||||
int32_tRom ppLr_gsTable[4][32]; /* DTX mode */
|
||||
|
||||
int16_t
|
||||
*pswLtpStateOut = &pswLtpStateBaseDec[LTP_LEN],
|
||||
pswSythAsSpace[NP * N_SUB],
|
||||
pswPFNumAsSpace[NP * N_SUB],
|
||||
pswPFDenomAsSpace[NP * N_SUB],
|
||||
*ppswSynthAs[N_SUB] = {
|
||||
&pswSythAsSpace[0],
|
||||
&pswSythAsSpace[10],
|
||||
&pswSythAsSpace[20],
|
||||
&pswSythAsSpace[30],
|
||||
},
|
||||
|
||||
*ppswPFNumAs[N_SUB] = {
|
||||
&pswPFNumAsSpace[0],
|
||||
&pswPFNumAsSpace[10],
|
||||
&pswPFNumAsSpace[20],
|
||||
&pswPFNumAsSpace[30],
|
||||
},
|
||||
*ppswPFDenomAs[N_SUB] = {
|
||||
&pswPFDenomAsSpace[0],
|
||||
&pswPFDenomAsSpace[10],
|
||||
&pswPFDenomAsSpace[20],
|
||||
&pswPFDenomAsSpace[30],
|
||||
};
|
||||
|
||||
int16_tRom
|
||||
psrSPFDenomWidenCf[NP] = {
|
||||
0x6000, 0x4800, 0x3600, 0x2880, 0x1E60,
|
||||
0x16C8, 0x1116, 0x0CD0, 0x099C, 0x0735,
|
||||
};
|
||||
|
||||
|
||||
int32_t L_RxPNSeed; /* DTX mode */
|
||||
int16_t swRxDtxGsIndex; /* DTX mode */
|
||||
|
||||
// From dtx.c
|
||||
int16_t swVadFrmCnt = 0; /* Indicates the number of sequential
|
||||
* frames where VAD == 0 */
|
||||
|
||||
short int siUpdPointer = 0;
|
||||
int16_t swNElapsed = 50;
|
||||
|
||||
int32_t pL_GsHist[N_SUB * (OVERHANG - 1)];
|
||||
|
||||
/* history of unquantized parameters */
|
||||
int32_t pL_R0Hist[OVERHANG];
|
||||
int32_t ppL_CorrHist[OVERHANG][NP + 1];
|
||||
|
||||
/* quantized reference parameters */
|
||||
int16_t swQntRefR0,
|
||||
swRefGsIndex;
|
||||
int piRefVqCodewds[3];
|
||||
|
||||
/* handling of short speech bursts */
|
||||
int16_t swShortBurst;
|
||||
|
||||
/* state value of random generator */
|
||||
int32_t L_TxPNSeed;
|
||||
|
||||
int16_t swR0OldCN;
|
||||
int32_t pL_OldCorrSeq[NP + 1],
|
||||
pL_NewCorrSeq[NP + 1],
|
||||
pL_CorrSeq[NP + 1];
|
||||
|
||||
// From sp_enc.c
|
||||
int16_t swTxGsHistPtr = 0;
|
||||
|
||||
int16_t pswCNVSCode1[N_SUB],
|
||||
pswCNVSCode2[N_SUB],
|
||||
pswCNGsp0Code[N_SUB],
|
||||
pswCNLpc[3],
|
||||
swCNR0;
|
||||
|
||||
int16_t pswAnalysisState[NP];
|
||||
|
||||
int16_t pswWStateNum[NP],
|
||||
pswWStateDenom[NP];
|
||||
|
||||
int16_t swLastLag;
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Other External Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int16_tRom *psrTable; /* points to correct table of
|
||||
* vectors */
|
||||
int iLimit; /* accessible to all in this file
|
||||
* and to lpcCorrQntz() in dtx.c */
|
||||
int iLow; /* the low element in this segment */
|
||||
int iThree; /* boolean, is this a three element
|
||||
* vector */
|
||||
int iWordHalfPtr; /* points to the next byte */
|
||||
int iWordPtr; /* points to the next word to be */
|
||||
|
||||
// from vad.c
|
||||
|
||||
int16_t
|
||||
pswRvad[9],
|
||||
swNormRvad,
|
||||
swPt_sacf,
|
||||
swPt_sav0,
|
||||
swE_thvad,
|
||||
swM_thvad,
|
||||
swAdaptCount,
|
||||
swBurstCount,
|
||||
swHangCount,
|
||||
swOldLagCount,
|
||||
swVeryOldLagCount,
|
||||
swOldLag;
|
||||
|
||||
int32_t
|
||||
pL_sacf[27],
|
||||
pL_sav0[36],
|
||||
L_lastdm;
|
||||
|
||||
public:
|
||||
|
||||
// From VAD
|
||||
void vad_reset(void);
|
||||
|
||||
void vad_algorithm
|
||||
(
|
||||
int32_t pL_acf[9],
|
||||
int16_t swScaleAcf,
|
||||
int16_t pswRc[4],
|
||||
int16_t swPtch,
|
||||
int16_t *pswVadFlag
|
||||
);
|
||||
|
||||
void energy_computation
|
||||
(
|
||||
int32_t pL_acf[],
|
||||
int16_t swScaleAcf,
|
||||
int16_t pswRvad[],
|
||||
int16_t swNormRvad,
|
||||
int16_t *pswM_pvad,
|
||||
int16_t *pswE_pvad,
|
||||
int16_t *pswM_acf0,
|
||||
int16_t *pswE_acf0
|
||||
);
|
||||
|
||||
|
||||
void average_acf
|
||||
(
|
||||
int32_t pL_acf[],
|
||||
int16_t swScaleAcf,
|
||||
int32_t pL_av0[],
|
||||
int32_t pL_av1[]
|
||||
);
|
||||
|
||||
void predictor_values
|
||||
(
|
||||
int32_t pL_av1[],
|
||||
int16_t pswRav1[],
|
||||
int16_t *pswNormRav1
|
||||
);
|
||||
|
||||
void schur_recursion
|
||||
(
|
||||
int32_t pL_av1[],
|
||||
int16_t pswVpar[]
|
||||
);
|
||||
|
||||
void step_up
|
||||
(
|
||||
int16_t swNp,
|
||||
int16_t pswVpar[],
|
||||
int16_t pswAav1[]
|
||||
);
|
||||
|
||||
void compute_rav1
|
||||
(
|
||||
int16_t pswAav1[],
|
||||
int16_t pswRav1[],
|
||||
int16_t *pswNormRav1
|
||||
);
|
||||
|
||||
void spectral_comparison
|
||||
(
|
||||
int16_t pswRav1[],
|
||||
int16_t swNormRav1,
|
||||
int32_t pL_av0[],
|
||||
int16_t *pswStat
|
||||
);
|
||||
|
||||
void tone_detection
|
||||
(
|
||||
int16_t pswRc[4],
|
||||
int16_t *pswTone
|
||||
);
|
||||
|
||||
|
||||
void threshold_adaptation
|
||||
(
|
||||
int16_t swStat,
|
||||
int16_t swPtch,
|
||||
int16_t swTone,
|
||||
int16_t pswRav1[],
|
||||
int16_t swNormRav1,
|
||||
int16_t swM_pvad,
|
||||
int16_t swE_pvad,
|
||||
int16_t swM_acf0,
|
||||
int16_t swE_acf0,
|
||||
int16_t pswRvad[],
|
||||
int16_t *pswNormRvad,
|
||||
int16_t *pswM_thvad,
|
||||
int16_t *pswE_thvad
|
||||
);
|
||||
|
||||
void vad_decision
|
||||
(
|
||||
int16_t swM_pvad,
|
||||
int16_t swE_pvad,
|
||||
int16_t swM_thvad,
|
||||
int16_t swE_thvad,
|
||||
int16_t *pswVvad
|
||||
);
|
||||
|
||||
void vad_hangover
|
||||
(
|
||||
int16_t swVvad,
|
||||
int16_t *pswVadFlag
|
||||
);
|
||||
|
||||
void periodicity_update
|
||||
(
|
||||
int16_t pswLags[4],
|
||||
int16_t *pswPtch
|
||||
);
|
||||
|
||||
|
||||
// From err_conc.h
|
||||
|
||||
void para_conceal_speech_decoder(int16_t pswErrorFlag[],
|
||||
int16_t pswSpeechPara[], int16_t *pswMutePermit);
|
||||
|
||||
int16_t level_calc(int16_t swInd, int32_t *pl_en);
|
||||
|
||||
void level_estimator(int16_t update, int16_t *pswLevelMean,
|
||||
int16_t *pswLevelMax,
|
||||
int16_t pswDecodedSpeechFrame[]);
|
||||
|
||||
void signal_conceal_sub(int16_t pswPPFExcit[],
|
||||
int16_t ppswSynthAs[], int16_t pswSynthFiltState[],
|
||||
int16_t pswLtpStateOut[], int16_t pswPPreState[],
|
||||
int16_t swLevelMean, int16_t swLevelMax,
|
||||
int16_t swErrorFlag1, int16_t swMuteFlagOld,
|
||||
int16_t *pswMuteFlag, int16_t swMutePermit);
|
||||
|
||||
|
||||
|
||||
void speechDecoder(int16_t pswParameters[],
|
||||
int16_t pswDecodedSpeechFrame[]);
|
||||
|
||||
void aFlatRcDp(int32_t *pL_R, int16_t *pswRc);
|
||||
|
||||
void b_con(int16_t swCodeWord, short siNumBits,
|
||||
int16_t pswVectOut[]);
|
||||
|
||||
void fp_ex(int16_t swOrigLagIn, int16_t pswLTPState[]);
|
||||
|
||||
int16_t g_corr1(int16_t *pswIn, int32_t *pL_out);
|
||||
|
||||
int16_t g_corr1s(int16_t pswIn[], int16_t swEngyRShft,
|
||||
int32_t *pL_out);
|
||||
|
||||
void getSfrmLpc(short int siSoftInterpolation,
|
||||
int16_t swPrevR0, int16_t swNewR0,
|
||||
int16_t pswPrevFrmKs[],
|
||||
int16_t pswPrevFrmAs[],
|
||||
int16_t pswPrevFrmPFNum[],
|
||||
int16_t pswPrevFrmPFDenom[],
|
||||
int16_t pswNewFrmKs[],
|
||||
int16_t pswNewFrmAs[],
|
||||
int16_t pswNewFrmPFNum[],
|
||||
int16_t pswNewFrmPFDenom[],
|
||||
struct NormSw *psnsSqrtRs,
|
||||
int16_t *ppswSynthAs[],
|
||||
int16_t *ppswPFNumAs[],
|
||||
int16_t *ppswPFDenomAs[]);
|
||||
|
||||
void get_ipjj(int16_t swLagIn,
|
||||
int16_t *pswIp, int16_t *pswJj);
|
||||
|
||||
short int interpolateCheck(int16_t pswRefKs[],
|
||||
int16_t pswRefCoefsA[],
|
||||
int16_t pswOldCoefsA[],
|
||||
int16_t pswNewCoefsA[],
|
||||
int16_t swOldPer,
|
||||
int16_t swNewPer,
|
||||
int16_t swRq,
|
||||
struct NormSw *psnsSqrtRsOut,
|
||||
int16_t pswCoefOutA[]);
|
||||
|
||||
void lpcFir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswState[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcIir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswState[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcIrZsIir(int16_t pswCoef[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZiIir(int16_t pswCoef[], int16_t pswState[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsFir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsIir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsIirP(int16_t pswCommonIO[], int16_t pswCoef[]);
|
||||
|
||||
int16_t r0BasedEnergyShft(int16_t swR0Index);
|
||||
|
||||
short rcToADp(int16_t swAscale, int16_t pswRc[],
|
||||
int16_t pswA[]);
|
||||
|
||||
void rcToCorrDpL(int16_t swAshift, int16_t swAscale,
|
||||
int16_t pswRc[], int32_t pL_R[]);
|
||||
|
||||
void res_eng(int16_t pswReflecCoefIn[], int16_t swRq,
|
||||
struct NormSw *psnsSqrtRsOut);
|
||||
|
||||
void rs_rr(int16_t pswExcitation[], struct NormSw snsSqrtRs,
|
||||
struct NormSw *snsSqrtRsRr);
|
||||
|
||||
void rs_rrNs(int16_t pswExcitation[], struct NormSw snsSqrtRs,
|
||||
struct NormSw *snsSqrtRsRr);
|
||||
|
||||
int16_t scaleExcite(int16_t pswVect[],
|
||||
int16_t swErrTerm, struct NormSw snsRS,
|
||||
int16_t pswScldVect[]);
|
||||
|
||||
int16_t sqroot(int32_t L_SqrtIn);
|
||||
|
||||
void v_con(int16_t pswBVects[], int16_t pswOutVect[],
|
||||
int16_t pswBitArray[], short int siNumBVctrs);
|
||||
|
||||
void a_sst(int16_t swAshift, int16_t swAscale,
|
||||
int16_t pswDirectFormCoefIn[],
|
||||
int16_t pswDirectFormCoefOut[]);
|
||||
|
||||
int16_t agcGain(int16_t pswStateCurr[],
|
||||
struct NormSw snsInSigEnergy, int16_t swEngyRShft);
|
||||
|
||||
void pitchPreFilt(int16_t pswExcite[],
|
||||
int16_t swRxGsp0,
|
||||
int16_t swRxLag, int16_t swUvCode,
|
||||
int16_t swSemiBeta, struct NormSw snsSqrtRs,
|
||||
int16_t pswExciteOut[],
|
||||
int16_t pswPPreState[]);
|
||||
|
||||
void spectralPostFilter(int16_t pswSPFIn[],
|
||||
int16_t pswNumCoef[],
|
||||
int16_t pswDenomCoef[], int16_t pswSPFOut[]);
|
||||
// From dtx.c
|
||||
void avgCNHist(int32_t pL_R0History[],
|
||||
int32_t ppL_CorrHistory[OVERHANG][NP + 1],
|
||||
int32_t *pL_AvgdR0,
|
||||
int32_t pL_AvgdCorrSeq[]);
|
||||
|
||||
void avgGsHistQntz(int32_t pL_GsHistory[], int32_t *pL_GsAvgd);
|
||||
|
||||
int16_t swComfortNoise(int16_t swVadFlag,
|
||||
int32_t L_UnqntzdR0, int32_t *pL_UnqntzdCorr);
|
||||
|
||||
int16_t getPnBits(int iBits, int32_t *L_PnSeed);
|
||||
|
||||
int16_t gsQuant(int32_t L_GsIn, int16_t swVoicingMode);
|
||||
|
||||
void updateCNHist(int32_t L_UnqntzdR0,
|
||||
int32_t *pL_UnqntzdCorr,
|
||||
int32_t pL_R0Hist[],
|
||||
int32_t ppL_CorrHist[OVERHANG][NP + 1]);
|
||||
|
||||
void lpcCorrQntz(int32_t pL_CorrelSeq[],
|
||||
int16_t pswFinalRc[],
|
||||
int piVQCodewds[]);
|
||||
|
||||
int32_t linInterpSid(int32_t L_New, int32_t L_Old, int16_t swDtxState);
|
||||
|
||||
int16_t linInterpSidShort(int16_t swNew,
|
||||
int16_t swOld,
|
||||
int16_t swDtxState);
|
||||
|
||||
void rxInterpR0Lpc(int16_t *pswOldKs, int16_t *pswNewKs,
|
||||
int16_t swRxDTXState,
|
||||
int16_t swDecoMode, int16_t swFrameType);
|
||||
|
||||
// From sp_frm.c
|
||||
void iir_d(int16_t pswCoeff[], int16_t pswIn[],
|
||||
int16_t pswXstate[],
|
||||
int16_t pswYstate[],
|
||||
int npts, int shifts,
|
||||
int16_t swPreFirDownSh,
|
||||
int16_t swFinalUpShift);
|
||||
|
||||
|
||||
void filt4_2nd(int16_t pswCoeff[],
|
||||
int16_t pswIn[],
|
||||
int16_t pswXstate[],
|
||||
int16_t pswYstate[],
|
||||
int npts,
|
||||
int shifts);
|
||||
|
||||
void initPBarVBarL(int32_t pL_PBarFull[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[]);
|
||||
|
||||
void initPBarFullVBarFullL(int32_t pL_CorrelSeq[],
|
||||
int32_t pL_PBarFull[],
|
||||
int32_t pL_VBarFull[]);
|
||||
|
||||
int16_t aflatRecursion(int16_t pswQntRc[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[],
|
||||
int16_t *ppswPAddrs[],
|
||||
int16_t *ppswVAddrs[],
|
||||
int16_t swSegmentOrder);
|
||||
|
||||
void aflatNewBarRecursionL(int16_t pswQntRc[],
|
||||
int iSegment,
|
||||
int32_t pL_PBar[],
|
||||
int32_t pL_VBar[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[]);
|
||||
|
||||
|
||||
void setupPreQ(int iSeg, int iVector);
|
||||
|
||||
void setupQuant(int iSeg, int iVector);
|
||||
|
||||
void getNextVec(int16_t pswRc[]);
|
||||
|
||||
void aflat(int16_t pswSpeechToLPC[],
|
||||
int piR0Index[],
|
||||
int16_t pswFinalRc[],
|
||||
int piVQCodewds[],
|
||||
int16_t swPtch,
|
||||
int16_t *pswVadFlag,
|
||||
int16_t *pswSP);
|
||||
|
||||
|
||||
int16_t fnExp2(int32_t L_Input);
|
||||
|
||||
int16_t fnLog2(int32_t L_Input);
|
||||
|
||||
void weightSpeechFrame(int16_t pswSpeechFrm[],
|
||||
int16_t pswWNumSpace[],
|
||||
int16_t pswWDenomSpace[],
|
||||
int16_t pswWSpeechBuffBase[]);
|
||||
|
||||
void getSfrmLpcTx(int16_t swPrevR0, int16_t swNewR0,
|
||||
int16_t pswPrevFrmKs[],
|
||||
int16_t pswPrevFrmAs[],
|
||||
int16_t pswPrevFrmSNWCoef[],
|
||||
int16_t pswNewFrmKs[],
|
||||
int16_t pswNewFrmAs[],
|
||||
int16_t pswNewFrmSNWCoef[],
|
||||
int16_t pswHPFSpeech[],
|
||||
short *pswSoftInterp,
|
||||
struct NormSw *psnsSqrtRs,
|
||||
int16_t ppswSynthAs[][NP],
|
||||
int16_t ppswSNWCoefAs[][NP]);
|
||||
|
||||
short int fnBest_CG(int16_t pswCframe[],
|
||||
int16_t pswGframe[],
|
||||
int16_t *pswCmaxSqr,
|
||||
int16_t *pswGmax,
|
||||
short int siNumPairs);
|
||||
|
||||
short compResidEnergy(int16_t pswSpeech[],
|
||||
int16_t ppswInterpCoef[][NP],
|
||||
int16_t pswPreviousCoef[],
|
||||
int16_t pswCurrentCoef[],
|
||||
struct NormSw psnsSqrtRs[]);
|
||||
|
||||
int16_t r0Quant(int32_t L_UnqntzdR0);
|
||||
|
||||
int16_t cov32(int16_t pswIn[],
|
||||
int32_t pppL_B[NP][NP][2],
|
||||
int32_t pppL_F[NP][NP][2],
|
||||
int32_t pppL_C[NP][NP][2],
|
||||
int32_t *pL_R0,
|
||||
int32_t pL_VadAcf[],
|
||||
int16_t *pswVadScalAuto);
|
||||
|
||||
int32_t flat(int16_t pswSpeechIn[],
|
||||
int16_t pswRc[],
|
||||
int *piR0Inx,
|
||||
int32_t pL_VadAcf[],
|
||||
int16_t *pswVadScalAuto);
|
||||
|
||||
|
||||
|
||||
void openLoopLagSearch(int16_t pswWSpeech[],
|
||||
int16_t swPrevR0Index,
|
||||
int16_t swCurrR0Index,
|
||||
int16_t *psiUVCode,
|
||||
int16_t pswLagList[],
|
||||
int16_t pswNumLagList[],
|
||||
int16_t pswPitchBuf[],
|
||||
int16_t pswHNWCoefBuf[],
|
||||
struct NormSw psnsWSfrmEng[],
|
||||
int16_t pswVadLags[],
|
||||
int16_t swSP);
|
||||
|
||||
int16_t getCCThreshold(int16_t swRp0,
|
||||
int16_t swCC,
|
||||
int16_t swG);
|
||||
|
||||
void pitchLags(int16_t swBestIntLag,
|
||||
int16_t pswIntCs[],
|
||||
int16_t pswIntGs[],
|
||||
int16_t swCCThreshold,
|
||||
int16_t pswLPeaksSorted[],
|
||||
int16_t pswCPeaksSorted[],
|
||||
int16_t pswGPeaksSorted[],
|
||||
int16_t *psiNumSorted,
|
||||
int16_t *pswPitch,
|
||||
int16_t *pswHNWCoef);
|
||||
|
||||
short CGInterpValid(int16_t swFullResLag,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
int16_t pswLOut[],
|
||||
int16_t pswCOut[],
|
||||
int16_t pswGOut[]);
|
||||
|
||||
void CGInterp(int16_t pswLIn[],
|
||||
short siNum,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
short siLoIntLag,
|
||||
int16_t pswCOut[],
|
||||
int16_t pswGOut[]);
|
||||
|
||||
int16_t quantLag(int16_t swRawLag,
|
||||
int16_t *psiCode);
|
||||
|
||||
void findBestInQuantList(struct QuantList psqlInList,
|
||||
int iNumVectOut,
|
||||
struct QuantList psqlBestOutList[]);
|
||||
|
||||
int16_t findPeak(int16_t swSingleResLag,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[]);
|
||||
|
||||
void bestDelta(int16_t pswLagList[],
|
||||
int16_t pswCSfrm[],
|
||||
int16_t pswGSfrm[],
|
||||
short int siNumLags,
|
||||
short int siSfrmIndex,
|
||||
int16_t pswLTraj[],
|
||||
int16_t pswCCTraj[],
|
||||
int16_t pswGTraj[]);
|
||||
|
||||
int16_t
|
||||
maxCCOverGWithSign(int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
int16_t *pswCCMax,
|
||||
int16_t *pswGMax,
|
||||
int16_t swNum);
|
||||
|
||||
void getNWCoefs(int16_t pswACoefs[],
|
||||
int16_t pswHCoefs[]);
|
||||
|
||||
int16_t lagDecode(int16_t swDeltaLag);
|
||||
|
||||
};
|
||||
|
||||
// From mathdp31
|
||||
extern int32_t L_mpy_ls(int32_t L_var2, int16_t var1);
|
||||
extern int32_t L_mpy_ll(int32_t L_var1, int32_t L_var2);
|
||||
extern short isSwLimit(int16_t swIn);
|
||||
extern short isLwLimit(int32_t L_In);
|
||||
|
||||
// From mathhalf
|
||||
/* addition */
|
||||
/************/
|
||||
|
||||
extern int16_t add(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int16_t sub(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int32_t L_add(int32_t L_var1, int32_t L_var2); /* 2 ops */
|
||||
extern int32_t L_sub(int32_t L_var1, int32_t L_var2); /* 2 ops */
|
||||
|
||||
/* multiplication */
|
||||
/******************/
|
||||
|
||||
extern int16_t mult(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int32_t L_mult(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int16_t mult_r(int16_t var1, int16_t var2); /* 2 ops */
|
||||
|
||||
|
||||
/* arithmetic shifts */
|
||||
/*********************/
|
||||
|
||||
extern int16_t shr(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int16_t shl(int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int32_t L_shr(int32_t L_var1, int16_t var2); /* 2 ops */
|
||||
extern int32_t L_shl(int32_t L_var1, int16_t var2); /* 2 ops */
|
||||
extern int16_t shift_r(int16_t var, int16_t var2); /* 2 ops */
|
||||
extern int32_t L_shift_r(int32_t L_var, int16_t var2); /* 3 ops */
|
||||
|
||||
/* absolute value */
|
||||
/*******************/
|
||||
|
||||
extern int16_t abs_s(int16_t var1); /* 1 ops */
|
||||
extern int32_t L_abs(int32_t var1); /* 3 ops */
|
||||
|
||||
|
||||
/* multiply accumulate */
|
||||
/************************/
|
||||
|
||||
extern int32_t L_mac(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 1 op */
|
||||
extern int16_t mac_r(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 2 op */
|
||||
extern int32_t L_msu(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 1 op */
|
||||
extern int16_t msu_r(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 2 op */
|
||||
|
||||
/* negation */
|
||||
/*************/
|
||||
|
||||
extern int16_t negate(int16_t var1); /* 1 ops */
|
||||
extern int32_t L_negate(int32_t L_var1); /* 2 ops */
|
||||
|
||||
|
||||
/* Accumulator manipulation */
|
||||
/****************************/
|
||||
|
||||
extern int32_t L_deposit_l(int16_t var1); /* 1 ops */
|
||||
extern int32_t L_deposit_h(int16_t var1); /* 1 ops */
|
||||
extern int16_t extract_l(int32_t L_var1); /* 1 ops */
|
||||
extern int16_t extract_h(int32_t L_var1); /* 1 ops */
|
||||
|
||||
/* Round */
|
||||
/*********/
|
||||
|
||||
extern int16_t round(int32_t L_var1); /* 1 ops */
|
||||
|
||||
/* Normalization */
|
||||
/*****************/
|
||||
|
||||
extern int16_t norm_l(int32_t L_var1); /* 30 ops */
|
||||
extern int16_t norm_s(int16_t var1); /* 15 ops */
|
||||
|
||||
/* Division */
|
||||
/************/
|
||||
extern int16_t divide_s(int16_t var1, int16_t var2); /* 18 ops */
|
||||
|
||||
/* Non-saturating instructions */
|
||||
/*******************************/
|
||||
extern int32_t L_add_c(int32_t L_Var1, int32_t L_Var2); /* 2 ops */
|
||||
extern int32_t L_sub_c(int32_t L_Var1, int32_t L_Var2); /* 2 ops */
|
||||
extern int32_t L_sat(int32_t L_var1); /* 4 ops */
|
||||
extern int32_t L_macNs(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 1 ops */
|
||||
extern int32_t L_msuNs(int32_t L_var3,
|
||||
int16_t var1, int16_t var2); /* 1 ops */
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1341
src/libs/gsmhr/gsmhr_dtx.c
Normal file
1341
src/libs/gsmhr/gsmhr_dtx.c
Normal file
File diff suppressed because it is too large
Load Diff
1334
src/libs/gsmhr/gsmhr_dtx.cpp
Normal file
1334
src/libs/gsmhr/gsmhr_dtx.cpp
Normal file
File diff suppressed because it is too large
Load Diff
62
src/libs/gsmhr/gsmhr_dtx.h
Normal file
62
src/libs/gsmhr/gsmhr_dtx.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef __DTX
|
||||
#define __DTX
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
|
||||
#define PN_INIT_SEED (int32_t)0x1091988L /* initial seed for Comfort
|
||||
* noise pn-generator */
|
||||
|
||||
#define CNINTPER 12 /* inperpolation period of CN
|
||||
* parameters */
|
||||
|
||||
#define SPEECH 1
|
||||
#define CNIFIRSTSID 2
|
||||
#define CNICONT 3
|
||||
#define CNIBFI 4
|
||||
|
||||
#define VALIDSID 11
|
||||
#define INVALIDSID 22
|
||||
#define GOODSPEECH 33
|
||||
#define UNUSABLE 44
|
||||
|
||||
/*________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void avgCNHist(int32_t pL_R0History[],
|
||||
int32_t ppL_CorrHistory[OVERHANG][NP + 1],
|
||||
int32_t *pL_AvgdR0,
|
||||
int32_t pL_AvgdCorrSeq[]);
|
||||
|
||||
void avgGsHistQntz(int32_t pL_GsHistory[], int32_t *pL_GsAvgd);
|
||||
|
||||
int16_t swComfortNoise(int16_t swVadFlag,
|
||||
int32_t L_UnqntzdR0, int32_t *pL_UnqntzdCorr);
|
||||
|
||||
int16_t getPnBits(int iBits, int32_t *L_PnSeed);
|
||||
|
||||
int16_t gsQuant(int32_t L_GsIn, int16_t swVoicingMode);
|
||||
|
||||
void updateCNHist(int32_t L_UnqntzdR0,
|
||||
int32_t *pL_UnqntzdCorr,
|
||||
int32_t pL_R0Hist[],
|
||||
int32_t ppL_CorrHist[OVERHANG][NP + 1]);
|
||||
|
||||
void lpcCorrQntz(int32_t pL_CorrelSeq[],
|
||||
int16_t pswFinalRc[],
|
||||
int piVQCodewds[]);
|
||||
|
||||
int32_t linInterpSid(int32_t L_New, int32_t L_Old, int16_t swDtxState);
|
||||
|
||||
int16_t linInterpSidShort(int16_t swNew,
|
||||
int16_t swOld,
|
||||
int16_t swDtxState);
|
||||
|
||||
void rxInterpR0Lpc(int16_t *pswOldKs, int16_t *pswNewKs,
|
||||
int16_t swRxDTXState,
|
||||
int16_t swDecoMode, int16_t swFrameType);
|
||||
|
||||
#endif
|
||||
480
src/libs/gsmhr/gsmhr_gsm_hr.c
Normal file
480
src/libs/gsmhr/gsmhr_gsm_hr.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* File Name: gsm_hr.c
|
||||
*
|
||||
* Purpose:
|
||||
*
|
||||
* This file contains the main routine for the GSM Half Rate speech
|
||||
* codec. The code for the speech coder, including the VAD, DTX,
|
||||
* Comfort Noise, bad frame handling (error concealment), and codec
|
||||
* homing functions is in the files listed below:
|
||||
*
|
||||
* gsm_hr.c globdefs.c homing.c host.c
|
||||
* mathdp31.c mathhalf.c sp_dec.c sp_enc.c
|
||||
* sp_frm.c sp_rom.c sp_sfrm.c vad.c
|
||||
* dtx.c err_conc.c
|
||||
*
|
||||
* This particular file only has the level 0, main(), and all level
|
||||
* 1, main()'s daughter functions, in it.
|
||||
*
|
||||
* Details on how to run gsm_hr are in the readme.txt file.
|
||||
*
|
||||
* Below is a listing of all the functions appearing in the file.
|
||||
* The ordering is hierarchical.
|
||||
*
|
||||
* main() "gsm_hr", main program.
|
||||
* encode() - encodes a speech file, outputs an encoded parameter file
|
||||
* decode() - decodes a parameter file, outputs a decoded speech file
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Include Files |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "gsmhr_gsm_hr.h"
|
||||
#include "gsmhr_homing.h"
|
||||
#include "gsmhr_host.h"
|
||||
#include "gsmhr_sp_dec.h"
|
||||
#include "gsmhr_sp_enc.h"
|
||||
#include "gsmhr_typedefs.h"
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* PROGRAM NAME: gsm_hr
|
||||
*
|
||||
* PURPOSE:
|
||||
* gsm_hr - main program for the GSM Half-Rate speech coder.
|
||||
* Allows running one of the following operational modes:
|
||||
* 0. Encoder only with speech input / encoded parameter data output.
|
||||
* 1. Decoder only with speech parameter data input / speech output.
|
||||
*
|
||||
* INPUT:
|
||||
* inputFileName 0. speech file in 8 kHz, pcm format.
|
||||
* 1. speech parameter file in decoder input format.
|
||||
* <number of frames> - number of frames to be processed (optional).
|
||||
* <dtx|nodtx> - switch to enable/disable the DTX functions.
|
||||
*
|
||||
* OUTPUT:
|
||||
* outputFileName 0. encoded paramter output file.
|
||||
* 1. synthesized speech file in 8 kHz, pcm format.
|
||||
*
|
||||
* RETURN:
|
||||
* none
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.0 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: main, gsm_hr, speech codec, top level
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Constants |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#define DEFAULT_NUMFRAMES 32766
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int iDoneFrm,
|
||||
iMaxNumFrms,
|
||||
option,
|
||||
i;
|
||||
|
||||
FILE *pfileInFile,
|
||||
*pfileOutFile;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* check command line arguments */
|
||||
/* ---------------------------- */
|
||||
|
||||
iMaxNumFrms = DEFAULT_NUMFRAMES;
|
||||
giDTXon = 1;
|
||||
|
||||
/* check command line arguments */
|
||||
/* ---------------------------- */
|
||||
|
||||
switch (argc)
|
||||
{
|
||||
case 4:
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 6:
|
||||
|
||||
for (i = 4; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "dtx"))
|
||||
giDTXon = 1;
|
||||
else if (!strcmp(argv[i], "nodtx"))
|
||||
giDTXon = 0;
|
||||
else if ((iMaxNumFrms = atoi(argv[i])) <= 0)
|
||||
{
|
||||
printf("invalid number of frames or wrong DTX switch, %s", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
printf("\n\nUsage:\n\n");
|
||||
printf("gsm_hr option inputFileName outputFileName ");
|
||||
printf("<number of frames> <dtx|nodtx>\n");
|
||||
printf(" or\n");
|
||||
printf("gsm_hr option inputFileName outputFileName ");
|
||||
printf("<dtx|nodtx> <number of frames>\n");
|
||||
printf("\nOptions: ");
|
||||
printf("enc ");
|
||||
puts("inputFileName: speech --> outputFileName: encoder output");
|
||||
printf(" ");
|
||||
printf("dec ");
|
||||
puts("inputFileName: decoder input --> outputFileName: speech");
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* check encoding and decoding options */
|
||||
/* ----------------------------------- */
|
||||
|
||||
if (!strcmp(argv[1], "enc"))
|
||||
option = 0;
|
||||
else if (!strcmp(argv[1], "dec"))
|
||||
option = 1;
|
||||
else
|
||||
{
|
||||
printf("error in option selection\n");
|
||||
printf(" Your entry : %s \n", argv[1]);
|
||||
printf("\n\nUsage:\n\n");
|
||||
printf("gsm_hr option inputFileName outputFileName ");
|
||||
printf("<number of frames> <dtx|nodtx>\n");
|
||||
printf(" or\n");
|
||||
printf("gsm_hr option inputFileName outputFileName ");
|
||||
printf("<dtx|nodtx> <number of frames>\n");
|
||||
printf("\nOptions: ");
|
||||
printf("enc ");
|
||||
puts("inputFileName: speech --> outputFileName: encoder output");
|
||||
printf(" ");
|
||||
printf("dec ");
|
||||
puts("inputFileName: decoder input --> outputFileName: speech");
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* open the input and output files */
|
||||
/* ------------------------------- */
|
||||
|
||||
#ifdef VAX
|
||||
pfileInFile = fopen(argv[2], "rb", "mrs=2", "rfm=fix", "ctx=stm");
|
||||
pfileOutFile = fopen(argv[3], "wb", "mrs=2", "rfm=fix", "ctx=stm");
|
||||
#else
|
||||
pfileInFile = fopen(argv[2], "rb");
|
||||
pfileOutFile = fopen(argv[3], "wb");
|
||||
#endif
|
||||
|
||||
if (pfileInFile == NULL)
|
||||
{
|
||||
printf("error: can not open file %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
if (pfileOutFile == NULL)
|
||||
{
|
||||
printf("error: can not open file %s\n", argv[3]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
puts("\n\n");
|
||||
puts(" ****************************************");
|
||||
puts(" * *");
|
||||
puts(" * GSM Half-Rate Speech Coder *");
|
||||
puts(" * *");
|
||||
puts(" * *");
|
||||
printf(" * %s *\n", VERSION);
|
||||
printf(" * %s *\n", DATE);
|
||||
puts(" * *");
|
||||
puts(" ****************************************");
|
||||
puts("\n");
|
||||
|
||||
|
||||
printf("option: ");
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case 0:
|
||||
puts("enc (speech encoder)");
|
||||
break;
|
||||
case 1:
|
||||
puts("dec (speech decoder)");
|
||||
break;
|
||||
default:
|
||||
puts("invalid option");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (giDTXon)
|
||||
printf("DTX mode: enabled\n");
|
||||
else
|
||||
printf("DTX mode: disabled\n");
|
||||
|
||||
printf("input file: %s\n", argv[2]);
|
||||
printf("output file: %s\n\n", argv[3]);
|
||||
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case 0: /* encode */
|
||||
|
||||
/* start the encoder, VAD, and transmit DTX in the home state */
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
resetEnc();
|
||||
|
||||
/* encode: analyze 8 kHz speech and output encoded parameter file */
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
for (giFrmCnt = 1, iDoneFrm = 0;
|
||||
!iDoneFrm && giFrmCnt <= iMaxNumFrms;
|
||||
giFrmCnt++)
|
||||
{
|
||||
|
||||
#ifndef SILENT
|
||||
printf("encoding frame %d \r", giFrmCnt);
|
||||
#endif
|
||||
|
||||
if (encode(pfileInFile, pfileOutFile))
|
||||
iDoneFrm = 1;
|
||||
}
|
||||
|
||||
if (iDoneFrm)
|
||||
giFrmCnt--;
|
||||
|
||||
printf(" %d speech frames encoded\n", giFrmCnt - 1);
|
||||
break;
|
||||
|
||||
case 1: /* decode */
|
||||
|
||||
/* start the decoder and receive DTX in the home state */
|
||||
/* --------------------------------------------------- */
|
||||
|
||||
resetDec();
|
||||
|
||||
/* decode: synthesize speech */
|
||||
/* -------------------------- */
|
||||
|
||||
for (giFrmCnt = 1, iDoneFrm = 0;
|
||||
!iDoneFrm && giFrmCnt <= iMaxNumFrms;
|
||||
giFrmCnt++)
|
||||
{
|
||||
|
||||
#ifndef SILENT
|
||||
printf("decoding frame %d \r", giFrmCnt);
|
||||
#endif
|
||||
|
||||
if (decode(pfileInFile, pfileOutFile))
|
||||
iDoneFrm = 1;
|
||||
}
|
||||
|
||||
if (iDoneFrm)
|
||||
giFrmCnt--;
|
||||
|
||||
printf(" %d speech frames decoded\n", giFrmCnt - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(pfileInFile);
|
||||
fclose(pfileOutFile);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: decode
|
||||
*
|
||||
* PURPOSE:
|
||||
* Reads in one frame of speech parameters and outputs one frame of
|
||||
* synthesized speech. Resets the decoder to the home state if the
|
||||
* Decoder Homing Frame pattern is detected.
|
||||
*
|
||||
* INPUT:
|
||||
* pfileDec speech parameter input file.
|
||||
*
|
||||
* OUTPUT:
|
||||
* pfileSpeechOut synthesized speech file
|
||||
*
|
||||
* RETURN:
|
||||
* 0 successfully synthesized a complete frame of speech
|
||||
* 1 failed to synthesize a complete frame of speech
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.2 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pfileDec, pfileSpeechOut
|
||||
**************************************************************************/
|
||||
|
||||
int decode(FILE *pfileDec, FILE *pfileSpeechOut)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Constants |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* These constants define the number of consecutive */
|
||||
/* parameters that decoderHomingFrameTest checks. */
|
||||
/* -------------------------------------------------*/
|
||||
|
||||
#define WHOLE_FRAME 18
|
||||
#define TO_FIRST_SUBFRAME 9
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Static Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
static int16_t pswSpeechPara[22],
|
||||
pswDecodedSpeechFrame[F_LEN];
|
||||
|
||||
static int reset_flag_decoder_old = 1;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
int i,
|
||||
reset_flag_decoder;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
if (readDecfile(pfileDec, pswSpeechPara))
|
||||
return (1);
|
||||
|
||||
if(reset_flag_decoder_old)
|
||||
reset_flag_decoder=decoderHomingFrameTest(pswSpeechPara,
|
||||
TO_FIRST_SUBFRAME);
|
||||
else
|
||||
reset_flag_decoder=0;
|
||||
|
||||
if (reset_flag_decoder && reset_flag_decoder_old)
|
||||
{
|
||||
/* force the output to be the encoder homing frame pattern */
|
||||
|
||||
for (i = 0; i < F_LEN; i++)
|
||||
pswDecodedSpeechFrame[i] = EHF_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
speechDecoder(pswSpeechPara, pswDecodedSpeechFrame);
|
||||
}
|
||||
|
||||
speechDecoderHostInterface(pswDecodedSpeechFrame, pfileSpeechOut);
|
||||
|
||||
if(!reset_flag_decoder_old)
|
||||
reset_flag_decoder=decoderHomingFrameTest(pswSpeechPara, WHOLE_FRAME);
|
||||
|
||||
if (reset_flag_decoder)
|
||||
resetDec(); /* bring the decoder and receive DTX
|
||||
* to the home state */
|
||||
|
||||
reset_flag_decoder_old = reset_flag_decoder;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: encode
|
||||
*
|
||||
* PURPOSE:
|
||||
* Reads in one frame of speech samples and outputs one frame of
|
||||
* speech parameters. Resets the encoder to the home state if the
|
||||
* Encoder Homing Frame pattern is detected.
|
||||
*
|
||||
* INPUT:
|
||||
* pfileSpeechIn speech file
|
||||
*
|
||||
* OUTPUT:
|
||||
* pfileEnc speech, encoded paramater data
|
||||
*
|
||||
* RETURN:
|
||||
* 0 successfully wrote a complete frame of data
|
||||
* 1 failed to write a complete frame of data
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.1 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pfileSpeechIn, pfileEnc
|
||||
**************************************************************************/
|
||||
|
||||
int encode(FILE *pfileSpeechIn, FILE *pfileEnc)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Static Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
static int16_t pswSpeechPara[20];
|
||||
static int16_t pswSpeechBuff[F_LEN];
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
int iNumRead,
|
||||
reset_flag;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
iNumRead = hostEncoderInterface(pfileSpeechIn, F_LEN, &pswSpeechBuff[0]);
|
||||
|
||||
if (iNumRead < F_LEN)
|
||||
return (1);
|
||||
|
||||
reset_flag = encoderHomingFrameTest(&pswSpeechBuff[0]);
|
||||
|
||||
speechEncoder(&pswSpeechBuff[0], pswSpeechPara);
|
||||
|
||||
if (writeEncfile(pswSpeechPara, pfileEnc) != 20)
|
||||
return (1);
|
||||
|
||||
if (reset_flag)
|
||||
resetEnc(); /* Bring the encoder, VAD, and DTX to
|
||||
* the home state */
|
||||
|
||||
return (0);
|
||||
}
|
||||
15
src/libs/gsmhr/gsmhr_gsm_hr.h
Normal file
15
src/libs/gsmhr/gsmhr_gsm_hr.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __GSM_HR
|
||||
#define __GSM_HR
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int encode(FILE *pfileSpeechIn, FILE *pfileEnc);
|
||||
int decode(FILE *pfileDec, FILE *pfileSpeechOut);
|
||||
|
||||
#endif
|
||||
648
src/libs/gsmhr/gsmhr_homing.c
Normal file
648
src/libs/gsmhr/gsmhr_homing.c
Normal file
@@ -0,0 +1,648 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* File Name: homing.c
|
||||
*
|
||||
* Purpose:
|
||||
* This file contains the following functions:
|
||||
*
|
||||
* decoderHomingFrameTest() - checks if a frame of input speech
|
||||
* parameters matches the Decoder Homing
|
||||
* Frame pattern.
|
||||
*
|
||||
* decoderReset() - called by resetDec() to reset all of the state
|
||||
* variables for the decoder
|
||||
*
|
||||
* encoderHomingFrameTest() - checks if a frame of input samples
|
||||
* matches the Encoder Homing Frame pattern.
|
||||
*
|
||||
* encoderReset() - called by resetEnc() to reset all the state
|
||||
* variables for the encoder.
|
||||
*
|
||||
* resetDec() - calls functions to reset the state variables for the
|
||||
* decoder, and for the receive DTX and Comfort Noise.
|
||||
*
|
||||
* resetEnc() - calls functions to reset the state variables for the
|
||||
* encoder and VAD, and for the transmit DTX and
|
||||
* Comfort Noise.
|
||||
*
|
||||
* dtxResetTx() - called by resetEnc() to reset all of the transmit
|
||||
* DTX and Comfort Noise state variables
|
||||
*
|
||||
* dtxResetRx() - called by resetDec() to reset all of the receive
|
||||
* DTX and Comfort Noise state variables
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Include Files |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "vad.h"
|
||||
#include "dtx.h"
|
||||
#include "homing.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Defines |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#define EHF_MASK 0x0008 /* Encoder Homing Frame pattern */
|
||||
#define LMAX 142 /* largest lag (integer sense) */
|
||||
#define CG_INT_MACS 6 /* Number of multiply-accumulates in
|
||||
* one interpolation */
|
||||
#define NUM_CLOSED 3 /* maximum number of lags searched */
|
||||
#define LPCSTARTINDEX 25 /* where the LPC analysis window
|
||||
* starts */
|
||||
#define INBUFFSZ LPCSTARTINDEX + A_LEN /* input buffer size */
|
||||
|
||||
|
||||
#define LTP_LEN 147 /* maximum ltp lag */
|
||||
#define LSMAX (LMAX + CG_INT_MACS/2)
|
||||
#define HNW_BUFF_LEN LSMAX
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: decoderHomingFrameTest
|
||||
*
|
||||
* PURPOSE:
|
||||
* Checks if a frame of input speech parameters matches the Decoder
|
||||
* Homing Frame pattern, which is:
|
||||
*
|
||||
* parameter decimal value hexidecimal value
|
||||
* --------- ------------- -----------------
|
||||
* R0 0 0x0000
|
||||
* LPC1 881 0x0371
|
||||
* LPC2 350 0x015E
|
||||
* LPC3 195 0x00c3
|
||||
* INT_LPC 1 0x0001
|
||||
* MODE 0 0x0000
|
||||
* CODE1_1 71 0x0047
|
||||
* CODE2_1 74 0x004a
|
||||
* GSP0_1 0 0x0000
|
||||
* CODE1_2 9 0x0009
|
||||
* CODE2_2 38 0x0026
|
||||
* GSP0_2 7 0x0007
|
||||
* CODE1_3 0 0x0000
|
||||
* CODE2_3 0 0x0000
|
||||
* GSP0_3 0 0x0000
|
||||
* CODE1_4 0 0x0000
|
||||
* CODE2_4 0 0x0000
|
||||
* GSP0_4 0 0x0000
|
||||
*
|
||||
* INPUT:
|
||||
* pswSpeechPara[] - one frame of speech parameters
|
||||
* in decoder input format
|
||||
*
|
||||
* iLastPara - the number of consecutive parameters in
|
||||
* pswSpeechPara[] to match.
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* 0 input frame does not match the Decoder Homing Frame pattern.
|
||||
* 1 input frame matches the Decoder Homing Frame pattern.
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pswSpeechPara
|
||||
**************************************************************************/
|
||||
|
||||
int decoderHomingFrameTest(Shortword pswSpeechPara[], int iLastPara)
|
||||
{
|
||||
/* the n[] array contains the number of bits in each speech parameter */
|
||||
static int n[] = {5, 11, 9, 8, 1, 2, 7, 7, 5, 7, 7, 5, 7, 7, 5, 7, 7, 5};
|
||||
|
||||
static Shortword dhf_mask[] =
|
||||
{
|
||||
0x0000, /* R0 */
|
||||
0x0371, /* LPC1 */
|
||||
0x015E, /* LPC2 */
|
||||
0x00c3, /* LPC3 */
|
||||
0x0001, /* INT_LPC */
|
||||
0x0000, /* MODE */
|
||||
0x0047, /* CODE1_1 */
|
||||
0x004a, /* CODE2_1 */
|
||||
0x0000, /* GSP0_1 */
|
||||
0x0009, /* CODE1_2 */
|
||||
0x0026, /* CODE2_2 */
|
||||
0x0007, /* GSP0_2 */
|
||||
0x0000, /* CODE1_3 */
|
||||
0x0000, /* CODE2_3 */
|
||||
0x0000, /* GSP0_3 */
|
||||
0x0000, /* CODE1_4 */
|
||||
0x0000, /* CODE2_4 */
|
||||
0x0000 /* GSP0_4 */
|
||||
};
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < iLastPara; i++)
|
||||
{
|
||||
j = ((pswSpeechPara[i] & ~(~0 << n[i])) ^ dhf_mask[i]);
|
||||
if (j)
|
||||
break;
|
||||
}
|
||||
|
||||
return !j;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: decoderReset
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the decoder
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void decoderReset(void)
|
||||
{
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for decoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_dec.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern Shortword gswPostFiltAgcGain,
|
||||
gpswPostFiltStateNum[NP],
|
||||
gpswPostFiltStateDenom[NP],
|
||||
swPostEmphasisState,
|
||||
pswSynthFiltState[NP],
|
||||
pswOldFrmKsDec[NP],
|
||||
pswOldFrmAsDec[NP],
|
||||
pswOldFrmPFNum[NP],
|
||||
pswOldFrmPFDenom[NP],
|
||||
swOldR0Dec,
|
||||
pswLtpStateBaseDec[LTP_LEN + S_LEN],
|
||||
pswPPreState[LTP_LEN + S_LEN];
|
||||
|
||||
extern Shortword swMuteFlagOld; /* error concealment */
|
||||
|
||||
|
||||
/* variables defined in err_conc.c *//* error concealment */
|
||||
/* ------------------------------- *//* error concealment */
|
||||
|
||||
extern Longword plSubfrEnergyMem[4]; /* error concealment */
|
||||
extern Shortword swLevelMem[4],
|
||||
lastR0, /* error concealment */
|
||||
pswLastGood[18], /* error concealment */
|
||||
swState,
|
||||
swLastFlag; /* error concealment */
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the decoder state variables */
|
||||
/* ------------------------------------- */
|
||||
|
||||
swOldR0Dec = 0;
|
||||
|
||||
gswPostFiltAgcGain = 0;
|
||||
|
||||
swPostEmphasisState = 0;
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
gpswPostFiltStateNum[i] = 0;
|
||||
gpswPostFiltStateDenom[i] = 0;
|
||||
pswSynthFiltState[i] = 0;
|
||||
pswOldFrmKsDec[i] = 0;
|
||||
pswOldFrmAsDec[i] = 0;
|
||||
pswOldFrmPFNum[i] = 0;
|
||||
pswOldFrmPFDenom[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (LTP_LEN + S_LEN); i++)
|
||||
{
|
||||
pswLtpStateBaseDec[i] = 0;
|
||||
pswPPreState[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* reset all the error concealment state variables */
|
||||
/* ----------------------------------------------- */
|
||||
|
||||
swMuteFlagOld = 0;
|
||||
|
||||
lastR0 = 0;
|
||||
swState = 7;
|
||||
swLastFlag = 0;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
plSubfrEnergyMem[i] = 80;
|
||||
swLevelMem[i] = -72;
|
||||
}
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
pswLastGood[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: encoderHomingFrameTest
|
||||
*
|
||||
* PURPOSE:
|
||||
* Checks if a frame of input samples matches the Encoder Homing Frame
|
||||
* pattern, which is 0x0008 for all 160 samples in the frame.
|
||||
*
|
||||
* INPUT:
|
||||
* pswSpeech[] one frame of speech samples
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* 0 input frame does not match the Encoder Homing Frame pattern.
|
||||
* 1 input frame matches the Encoder Homing Frame pattern.
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pswSpeech
|
||||
**************************************************************************/
|
||||
|
||||
int encoderHomingFrameTest(Shortword pswSpeech[])
|
||||
{
|
||||
int i;
|
||||
Shortword j;
|
||||
|
||||
for (i = 0; i < F_LEN; i++)
|
||||
{
|
||||
j = pswSpeech[i] ^ EHF_MASK;
|
||||
if (j)
|
||||
break;
|
||||
}
|
||||
|
||||
return !j;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: encoderReset
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the encoder
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void encoderReset(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_enc.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern Shortword swOldR0;
|
||||
extern Shortword swOldR0Index;
|
||||
|
||||
extern struct NormSw psnsWSfrmEngSpace[];
|
||||
|
||||
extern Shortword pswHPFXState[];
|
||||
extern Shortword pswHPFYState[];
|
||||
extern Shortword pswOldFrmKs[];
|
||||
extern Shortword pswOldFrmAs[];
|
||||
extern Shortword pswOldFrmSNWCoefs[];
|
||||
extern Shortword pswWgtSpeechSpace[];
|
||||
|
||||
extern Shortword pswSpeech[]; /* input speech */
|
||||
|
||||
extern Shortword swPtch;
|
||||
|
||||
|
||||
/* variables defined in sp_frm.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern Shortword pswAnalysisState[NP];
|
||||
|
||||
extern Shortword pswWStateNum[NP],
|
||||
pswWStateDenom[NP];
|
||||
|
||||
|
||||
/* variables defined in sp_sfrm.c */
|
||||
/* ------------------------------ */
|
||||
|
||||
extern Shortword pswLtpStateBase[LTP_LEN + S_LEN];
|
||||
extern Shortword pswHState[NP];
|
||||
extern Shortword pswHNWState[HNW_BUFF_LEN];
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the encoder state variables */
|
||||
/* ------------------------------------- */
|
||||
|
||||
swOldR0Index = 0;
|
||||
swOldR0 = 0;
|
||||
|
||||
for (i = 0; i < 2 * N_SUB; i++)
|
||||
{
|
||||
psnsWSfrmEngSpace[i].man = 0;
|
||||
psnsWSfrmEngSpace[i].sh = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
pswHPFXState[i] = 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
pswHPFYState[i] = 0;
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
pswOldFrmKs[i] = 0;
|
||||
pswOldFrmAs[i] = 0;
|
||||
pswOldFrmSNWCoefs[i] = 0;
|
||||
pswAnalysisState[i] = 0;
|
||||
pswWStateNum[i] = 0;
|
||||
pswWStateDenom[i] = 0;
|
||||
pswHState[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (F_LEN + LMAX + CG_INT_MACS / 2); i++)
|
||||
pswWgtSpeechSpace[i] = 0;
|
||||
|
||||
for (i = 0; i < INBUFFSZ; i++)
|
||||
pswSpeech[i] = 0;
|
||||
|
||||
for (i = 0; i < (LTP_LEN + S_LEN); i++)
|
||||
pswLtpStateBase[i] = 0;
|
||||
|
||||
for (i = 0; i < HNW_BUFF_LEN; i++)
|
||||
pswHNWState[i] = 0;
|
||||
|
||||
swPtch = 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: resetDec
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the decoder, and for the
|
||||
* receive DTX and Comfort Noise.
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void resetDec(void)
|
||||
{
|
||||
decoderReset(); /* reset all the state variables in
|
||||
* the speech decoder */
|
||||
dtxResetRx(); /* reset all the receive DTX and CN
|
||||
* state variables */
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: resetEnc
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the encoder and VAD, and for
|
||||
* the transmit DTX and Comfort Noise.
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void resetEnc(void)
|
||||
{
|
||||
|
||||
encoderReset(); /* reset all the state variables in
|
||||
* the speech encoder */
|
||||
vad_reset(); /* reset all the VAD state variables */
|
||||
|
||||
dtxResetTx(); /* reset all the transmit DTX and CN
|
||||
* state variables */
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: dtxResetTx
|
||||
*
|
||||
* PURPOSE:
|
||||
* reset all the transmit DTX and CN state variables
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void dtxResetTx(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_enc.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern Shortword swTxGsHistPtr;
|
||||
|
||||
|
||||
/* variables defined in dtx.c */
|
||||
/* -------------------------- */
|
||||
|
||||
extern Shortword swVadFrmCnt; /* Indicates the number of sequential
|
||||
* frames where VAD == 0 */
|
||||
extern short int siUpdPointer;
|
||||
extern Shortword swNElapsed;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the transmit DTX and CN state variables */
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
swTxGsHistPtr = 0;
|
||||
|
||||
swVadFrmCnt = 0;
|
||||
|
||||
siUpdPointer = 0;
|
||||
|
||||
swNElapsed = 50;
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: dtxResetRx
|
||||
*
|
||||
* PURPOSE:
|
||||
* reset all the receive DTX and CN state variables
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void dtxResetRx(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_dec.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern Shortword swRxDTXState;
|
||||
extern Shortword swDecoMode;
|
||||
extern Shortword swDtxMuting;
|
||||
extern Shortword swDtxBfiCnt;
|
||||
|
||||
extern Shortword swOldR0IndexDec;
|
||||
|
||||
extern Shortword swRxGsHistPtr;
|
||||
extern Longword pL_RxGsHist[(OVERHANG - 1) * N_SUB];
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the receive DTX and CN state variables */
|
||||
/* ------------------------------------------------ */
|
||||
|
||||
swRxDTXState = CNINTPER - 1;
|
||||
swDecoMode = SPEECH;
|
||||
swDtxMuting = 0;
|
||||
swDtxBfiCnt = 0;
|
||||
|
||||
swOldR0IndexDec = 0;
|
||||
|
||||
swRxGsHistPtr = 0;
|
||||
|
||||
for (i = 0; i < (OVERHANG - 1) * N_SUB; i++)
|
||||
pL_RxGsHist[i] = 0;
|
||||
|
||||
}
|
||||
648
src/libs/gsmhr/gsmhr_homing.cpp
Normal file
648
src/libs/gsmhr/gsmhr_homing.cpp
Normal file
@@ -0,0 +1,648 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* File Name: homing.c
|
||||
*
|
||||
* Purpose:
|
||||
* This file contains the following functions:
|
||||
*
|
||||
* decoderHomingFrameTest() - checks if a frame of input speech
|
||||
* parameters matches the Decoder Homing
|
||||
* Frame pattern.
|
||||
*
|
||||
* decoderReset() - called by resetDec() to reset all of the state
|
||||
* variables for the decoder
|
||||
*
|
||||
* encoderHomingFrameTest() - checks if a frame of input samples
|
||||
* matches the Encoder Homing Frame pattern.
|
||||
*
|
||||
* encoderReset() - called by resetEnc() to reset all the state
|
||||
* variables for the encoder.
|
||||
*
|
||||
* resetDec() - calls functions to reset the state variables for the
|
||||
* decoder, and for the receive DTX and Comfort Noise.
|
||||
*
|
||||
* resetEnc() - calls functions to reset the state variables for the
|
||||
* encoder and VAD, and for the transmit DTX and
|
||||
* Comfort Noise.
|
||||
*
|
||||
* dtxResetTx() - called by resetEnc() to reset all of the transmit
|
||||
* DTX and Comfort Noise state variables
|
||||
*
|
||||
* dtxResetRx() - called by resetDec() to reset all of the receive
|
||||
* DTX and Comfort Noise state variables
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Include Files |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#include "gsmhr_typedefs.h"
|
||||
#include "gsmhr_vad.h"
|
||||
#include "gsmhr_dtx.h"
|
||||
#include "gsmhr_homing.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Defines |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#define EHF_MASK 0x0008 /* Encoder Homing Frame pattern */
|
||||
#define LMAX 142 /* largest lag (integer sense) */
|
||||
#define CG_INT_MACS 6 /* Number of multiply-accumulates in
|
||||
* one interpolation */
|
||||
#define NUM_CLOSED 3 /* maximum number of lags searched */
|
||||
#define LPCSTARTINDEX 25 /* where the LPC analysis window
|
||||
* starts */
|
||||
#define INBUFFSZ LPCSTARTINDEX + A_LEN /* input buffer size */
|
||||
|
||||
|
||||
#define LTP_LEN 147 /* maximum ltp lag */
|
||||
#define LSMAX (LMAX + CG_INT_MACS/2)
|
||||
#define HNW_BUFF_LEN LSMAX
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: decoderHomingFrameTest
|
||||
*
|
||||
* PURPOSE:
|
||||
* Checks if a frame of input speech parameters matches the Decoder
|
||||
* Homing Frame pattern, which is:
|
||||
*
|
||||
* parameter decimal value hexidecimal value
|
||||
* --------- ------------- -----------------
|
||||
* R0 0 0x0000
|
||||
* LPC1 881 0x0371
|
||||
* LPC2 350 0x015E
|
||||
* LPC3 195 0x00c3
|
||||
* INT_LPC 1 0x0001
|
||||
* MODE 0 0x0000
|
||||
* CODE1_1 71 0x0047
|
||||
* CODE2_1 74 0x004a
|
||||
* GSP0_1 0 0x0000
|
||||
* CODE1_2 9 0x0009
|
||||
* CODE2_2 38 0x0026
|
||||
* GSP0_2 7 0x0007
|
||||
* CODE1_3 0 0x0000
|
||||
* CODE2_3 0 0x0000
|
||||
* GSP0_3 0 0x0000
|
||||
* CODE1_4 0 0x0000
|
||||
* CODE2_4 0 0x0000
|
||||
* GSP0_4 0 0x0000
|
||||
*
|
||||
* INPUT:
|
||||
* pswSpeechPara[] - one frame of speech parameters
|
||||
* in decoder input format
|
||||
*
|
||||
* iLastPara - the number of consecutive parameters in
|
||||
* pswSpeechPara[] to match.
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* 0 input frame does not match the Decoder Homing Frame pattern.
|
||||
* 1 input frame matches the Decoder Homing Frame pattern.
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pswSpeechPara
|
||||
**************************************************************************/
|
||||
|
||||
int GsmHrCodec::decoderHomingFrameTest(int16_t pswSpeechPara[], int iLastPara)
|
||||
{
|
||||
/* the n[] array contains the number of bits in each speech parameter */
|
||||
static int n[] = {5, 11, 9, 8, 1, 2, 7, 7, 5, 7, 7, 5, 7, 7, 5, 7, 7, 5};
|
||||
|
||||
static int16_t dhf_mask[] =
|
||||
{
|
||||
0x0000, /* R0 */
|
||||
0x0371, /* LPC1 */
|
||||
0x015E, /* LPC2 */
|
||||
0x00c3, /* LPC3 */
|
||||
0x0001, /* INT_LPC */
|
||||
0x0000, /* MODE */
|
||||
0x0047, /* CODE1_1 */
|
||||
0x004a, /* CODE2_1 */
|
||||
0x0000, /* GSP0_1 */
|
||||
0x0009, /* CODE1_2 */
|
||||
0x0026, /* CODE2_2 */
|
||||
0x0007, /* GSP0_2 */
|
||||
0x0000, /* CODE1_3 */
|
||||
0x0000, /* CODE2_3 */
|
||||
0x0000, /* GSP0_3 */
|
||||
0x0000, /* CODE1_4 */
|
||||
0x0000, /* CODE2_4 */
|
||||
0x0000 /* GSP0_4 */
|
||||
};
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < iLastPara; i++)
|
||||
{
|
||||
j = ((pswSpeechPara[i] & ~(~0 << n[i])) ^ dhf_mask[i]);
|
||||
if (j)
|
||||
break;
|
||||
}
|
||||
|
||||
return !j;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: decoderReset
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the decoder
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void GsmHrCodec::decoderReset(void)
|
||||
{
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for decoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_dec.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern int16_t gswPostFiltAgcGain,
|
||||
gpswPostFiltStateNum[NP],
|
||||
gpswPostFiltStateDenom[NP],
|
||||
swPostEmphasisState,
|
||||
pswSynthFiltState[NP],
|
||||
pswOldFrmKsDec[NP],
|
||||
pswOldFrmAsDec[NP],
|
||||
pswOldFrmPFNum[NP],
|
||||
pswOldFrmPFDenom[NP],
|
||||
swOldR0Dec,
|
||||
pswLtpStateBaseDec[LTP_LEN + S_LEN],
|
||||
pswPPreState[LTP_LEN + S_LEN];
|
||||
|
||||
extern int16_t swMuteFlagOld; /* error concealment */
|
||||
|
||||
|
||||
/* variables defined in err_conc.c *//* error concealment */
|
||||
/* ------------------------------- *//* error concealment */
|
||||
|
||||
extern int32_t plSubfrEnergyMem[4]; /* error concealment */
|
||||
extern int16_t swLevelMem[4],
|
||||
lastR0, /* error concealment */
|
||||
pswLastGood[18], /* error concealment */
|
||||
swState,
|
||||
swLastFlag; /* error concealment */
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the decoder state variables */
|
||||
/* ------------------------------------- */
|
||||
|
||||
swOldR0Dec = 0;
|
||||
|
||||
gswPostFiltAgcGain = 0;
|
||||
|
||||
swPostEmphasisState = 0;
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
gpswPostFiltStateNum[i] = 0;
|
||||
gpswPostFiltStateDenom[i] = 0;
|
||||
pswSynthFiltState[i] = 0;
|
||||
pswOldFrmKsDec[i] = 0;
|
||||
pswOldFrmAsDec[i] = 0;
|
||||
pswOldFrmPFNum[i] = 0;
|
||||
pswOldFrmPFDenom[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (LTP_LEN + S_LEN); i++)
|
||||
{
|
||||
pswLtpStateBaseDec[i] = 0;
|
||||
pswPPreState[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* reset all the error concealment state variables */
|
||||
/* ----------------------------------------------- */
|
||||
|
||||
swMuteFlagOld = 0;
|
||||
|
||||
lastR0 = 0;
|
||||
swState = 7;
|
||||
swLastFlag = 0;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
plSubfrEnergyMem[i] = 80;
|
||||
swLevelMem[i] = -72;
|
||||
}
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
pswLastGood[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: encoderHomingFrameTest
|
||||
*
|
||||
* PURPOSE:
|
||||
* Checks if a frame of input samples matches the Encoder Homing Frame
|
||||
* pattern, which is 0x0008 for all 160 samples in the frame.
|
||||
*
|
||||
* INPUT:
|
||||
* pswSpeech[] one frame of speech samples
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* 0 input frame does not match the Encoder Homing Frame pattern.
|
||||
* 1 input frame matches the Encoder Homing Frame pattern.
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
* pswSpeech
|
||||
**************************************************************************/
|
||||
|
||||
int encoderHomingFrameTest(int16_t pswSpeech[])
|
||||
{
|
||||
int i;
|
||||
int16_t j;
|
||||
|
||||
for (i = 0; i < F_LEN; i++)
|
||||
{
|
||||
j = pswSpeech[i] ^ EHF_MASK;
|
||||
if (j)
|
||||
break;
|
||||
}
|
||||
|
||||
return !j;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: encoderReset
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the encoder
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void encoderReset(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_enc.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern int16_t swOldR0;
|
||||
extern int16_t swOldR0Index;
|
||||
|
||||
extern struct NormSw psnsWSfrmEngSpace[];
|
||||
|
||||
extern int16_t pswHPFXState[];
|
||||
extern int16_t pswHPFYState[];
|
||||
extern int16_t pswOldFrmKs[];
|
||||
extern int16_t pswOldFrmAs[];
|
||||
extern int16_t pswOldFrmSNWCoefs[];
|
||||
extern int16_t pswWgtSpeechSpace[];
|
||||
|
||||
extern int16_t pswSpeech[]; /* input speech */
|
||||
|
||||
extern int16_t swPtch;
|
||||
|
||||
|
||||
/* variables defined in sp_frm.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern int16_t pswAnalysisState[NP];
|
||||
|
||||
extern int16_t pswWStateNum[NP],
|
||||
pswWStateDenom[NP];
|
||||
|
||||
|
||||
/* variables defined in sp_sfrm.c */
|
||||
/* ------------------------------ */
|
||||
|
||||
extern int16_t pswLtpStateBase[LTP_LEN + S_LEN];
|
||||
extern int16_t pswHState[NP];
|
||||
extern int16_t pswHNWState[HNW_BUFF_LEN];
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the encoder state variables */
|
||||
/* ------------------------------------- */
|
||||
|
||||
swOldR0Index = 0;
|
||||
swOldR0 = 0;
|
||||
|
||||
for (i = 0; i < 2 * N_SUB; i++)
|
||||
{
|
||||
psnsWSfrmEngSpace[i].man = 0;
|
||||
psnsWSfrmEngSpace[i].sh = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
pswHPFXState[i] = 0;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
pswHPFYState[i] = 0;
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
pswOldFrmKs[i] = 0;
|
||||
pswOldFrmAs[i] = 0;
|
||||
pswOldFrmSNWCoefs[i] = 0;
|
||||
pswAnalysisState[i] = 0;
|
||||
pswWStateNum[i] = 0;
|
||||
pswWStateDenom[i] = 0;
|
||||
pswHState[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (F_LEN + LMAX + CG_INT_MACS / 2); i++)
|
||||
pswWgtSpeechSpace[i] = 0;
|
||||
|
||||
for (i = 0; i < INBUFFSZ; i++)
|
||||
pswSpeech[i] = 0;
|
||||
|
||||
for (i = 0; i < (LTP_LEN + S_LEN); i++)
|
||||
pswLtpStateBase[i] = 0;
|
||||
|
||||
for (i = 0; i < HNW_BUFF_LEN; i++)
|
||||
pswHNWState[i] = 0;
|
||||
|
||||
swPtch = 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: resetDec
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the decoder, and for the
|
||||
* receive DTX and Comfort Noise.
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void resetDec(void)
|
||||
{
|
||||
decoderReset(); /* reset all the state variables in
|
||||
* the speech decoder */
|
||||
dtxResetRx(); /* reset all the receive DTX and CN
|
||||
* state variables */
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: resetEnc
|
||||
*
|
||||
* PURPOSE:
|
||||
* resets all of the state variables for the encoder and VAD, and for
|
||||
* the transmit DTX and Comfort Noise.
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void resetEnc(void)
|
||||
{
|
||||
|
||||
encoderReset(); /* reset all the state variables in
|
||||
* the speech encoder */
|
||||
vad_reset(); /* reset all the VAD state variables */
|
||||
|
||||
dtxResetTx(); /* reset all the transmit DTX and CN
|
||||
* state variables */
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: dtxResetTx
|
||||
*
|
||||
* PURPOSE:
|
||||
* reset all the transmit DTX and CN state variables
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void dtxResetTx(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_enc.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern int16_t swTxGsHistPtr;
|
||||
|
||||
|
||||
/* variables defined in dtx.c */
|
||||
/* -------------------------- */
|
||||
|
||||
extern int16_t swVadFrmCnt; /* Indicates the number of sequential
|
||||
* frames where VAD == 0 */
|
||||
extern short int siUpdPointer;
|
||||
extern int16_t swNElapsed;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the transmit DTX and CN state variables */
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
swTxGsHistPtr = 0;
|
||||
|
||||
swVadFrmCnt = 0;
|
||||
|
||||
siUpdPointer = 0;
|
||||
|
||||
swNElapsed = 50;
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: dtxResetRx
|
||||
*
|
||||
* PURPOSE:
|
||||
* reset all the receive DTX and CN state variables
|
||||
*
|
||||
* INPUT:
|
||||
* None
|
||||
*
|
||||
* OUTPUT:
|
||||
* None
|
||||
*
|
||||
* RETURN:
|
||||
* None
|
||||
*
|
||||
* REFERENCES: Sub-clause 10 of GSM Recomendation 06.02
|
||||
*
|
||||
* KEYWORDS:
|
||||
**************************************************************************/
|
||||
|
||||
void dtxResetRx(void)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| External declarations for encoder variables which need to be reset |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* variables defined in sp_dec.c */
|
||||
/* ----------------------------- */
|
||||
|
||||
extern int16_t swRxDTXState;
|
||||
extern int16_t swDecoMode;
|
||||
extern int16_t swDtxMuting;
|
||||
extern int16_t swDtxBfiCnt;
|
||||
|
||||
extern int16_t swOldR0IndexDec;
|
||||
|
||||
extern int16_t swRxGsHistPtr;
|
||||
extern int32_t pL_RxGsHist[(OVERHANG - 1) * N_SUB];
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* reset all the receive DTX and CN state variables */
|
||||
/* ------------------------------------------------ */
|
||||
|
||||
swRxDTXState = CNINTPER - 1;
|
||||
swDecoMode = SPEECH;
|
||||
swDtxMuting = 0;
|
||||
swDtxBfiCnt = 0;
|
||||
|
||||
swOldR0IndexDec = 0;
|
||||
|
||||
swRxGsHistPtr = 0;
|
||||
|
||||
for (i = 0; i < (OVERHANG - 1) * N_SUB; i++)
|
||||
pL_RxGsHist[i] = 0;
|
||||
|
||||
}
|
||||
30
src/libs/gsmhr/gsmhr_homing.h
Normal file
30
src/libs/gsmhr/gsmhr_homing.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef __HOMING
|
||||
#define __HOMING
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#define EHF_MASK 0x0008 /* Encoder Homing Frame pattern */
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int decoderHomingFrameTest(Shortword pswSpeechPara[], int iLastPara);
|
||||
|
||||
void decoderReset(void);
|
||||
|
||||
int encoderHomingFrameTest(Shortword pswSpeech[]);
|
||||
|
||||
void encoderReset(void);
|
||||
|
||||
void resetDec(void);
|
||||
|
||||
void resetEnc(void);
|
||||
|
||||
void dtxResetTx(void);
|
||||
|
||||
void dtxResetRx(void);
|
||||
|
||||
#endif
|
||||
347
src/libs/gsmhr/gsmhr_host.c
Normal file
347
src/libs/gsmhr/gsmhr_host.c
Normal file
@@ -0,0 +1,347 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* File Name: host.c
|
||||
*
|
||||
* Purpose: Contains functions for file I/O and formatting, no signal
|
||||
* processing.
|
||||
*
|
||||
* The functions in this file are listed below. All are level 2
|
||||
* fuctions, where level 0 is main(), except for fillBitAlloc() which
|
||||
* is level 3. The two "Interface" routines perform truncation of the
|
||||
* three least significant bits of the 16 bit linear input. The others
|
||||
* are simply file I/O functions and data reformatters.
|
||||
*
|
||||
* fillBitAlloc()
|
||||
* hostEncoderInterface()
|
||||
* readDecfile()
|
||||
* speechDecoderHostInterface()
|
||||
* writeEncfile()
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Include Files |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "gsmhr_typedefs.h"
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: fillBitAlloc
|
||||
*
|
||||
* PURPOSE:
|
||||
*
|
||||
* Arrange speech parameters for encoder output
|
||||
*
|
||||
* INPUTS:
|
||||
*
|
||||
* The speechcoders codewords:
|
||||
* iR0 - Frame energy
|
||||
* piVqIndeces[0:2] - LPC vector quantizer codewords
|
||||
* iSoftInterp - Soft interpolation bit 1 or 0
|
||||
* iVoicing - voicing mode 0,1,2,3
|
||||
* piLags[0:3] - Frame and delta lag codewords
|
||||
* piCodeWrdsA[0:3] - VSELP codevector 1
|
||||
* piCodeWrdsB[0:3] - VSELP codevector 2 (n/a for voiced modes)
|
||||
* piGsp0s[0:3] - GSP0 codewords
|
||||
* swVadFlag - voice activity detection flag
|
||||
* swSP - Speech flag
|
||||
*
|
||||
* OUTPUTS:
|
||||
*
|
||||
* pswBAlloc[0:20] - an array into which the coded data is moved
|
||||
*
|
||||
* RETURN VALUE:
|
||||
*
|
||||
* none
|
||||
*
|
||||
* REFERENCES: Sub-clause 2.1 and 4.1.12 of GSM Recomendation 06.20
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
void fillBitAlloc(int iVoicing, int iR0, int *piVqIndeces,
|
||||
int iSoftInterp, int *piLags,
|
||||
int *piCodeWrdsA, int *piCodeWrdsB,
|
||||
int *piGsp0s, int16_t swVadFlag,
|
||||
int16_t swSP, int16_t *pswBAlloc)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int i;
|
||||
int16_t *pswNxt;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
pswNxt = pswBAlloc;
|
||||
*pswNxt++ = iR0;
|
||||
for (i = 0; i < 3; i++)
|
||||
*pswNxt++ = *piVqIndeces++;
|
||||
*pswNxt++ = iSoftInterp;
|
||||
*pswNxt++ = iVoicing;
|
||||
|
||||
/* check voicing mode */
|
||||
if (iVoicing)
|
||||
{
|
||||
/* voiced mode */
|
||||
for (i = 0; i < N_SUB; i++)
|
||||
{
|
||||
*pswNxt++ = *piLags++;
|
||||
*pswNxt++ = *piCodeWrdsA++;
|
||||
*pswNxt++ = *piGsp0s++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* unvoiced frame */
|
||||
for (i = 0; i < N_SUB; i++)
|
||||
{
|
||||
*pswNxt++ = *piCodeWrdsA++;
|
||||
*pswNxt++ = *piCodeWrdsB++;
|
||||
*pswNxt++ = *piGsp0s++;
|
||||
}
|
||||
}
|
||||
*pswNxt++ = swVadFlag;
|
||||
*pswNxt++ = swSP;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: hostEncoderInterface
|
||||
*
|
||||
* PURPOSE:
|
||||
*
|
||||
* Read in speech data from a file. Zero the least significant 3 bits.
|
||||
*
|
||||
*
|
||||
* INPUTS:
|
||||
*
|
||||
* pfileInSpeech
|
||||
* FILE pointer to the binary input file
|
||||
*
|
||||
* iNumToRead
|
||||
* Number of samples to read from the file, typically
|
||||
* 160 (20 ms of speech).
|
||||
*
|
||||
*
|
||||
* OUTPUTS:
|
||||
*
|
||||
* pswSamplesRead[]
|
||||
* The speech samples read in from the file.
|
||||
*
|
||||
*
|
||||
* RETURN VALUE:
|
||||
*
|
||||
* iNumRead
|
||||
* The number of samples actually read.
|
||||
*
|
||||
* IMPLEMENTATION:
|
||||
*
|
||||
* The input speech file should be in "native" format. This means that
|
||||
* the file is to be read (by this program) and written (by another
|
||||
* program) as short ints (not chars).
|
||||
*
|
||||
* If not enough samples are available in the file, the number actually
|
||||
* read is returned. If the read fails to fill the requested iNumToRead
|
||||
* samples, then the rest are zeroed.
|
||||
*
|
||||
* In all cases the least significant 3 bits of all speech samples are
|
||||
* zeroed.
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.1 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: read, read speech, get speech data
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
int hostEncoderInterface(FILE *pfileInSpeech, int iNumToRead,
|
||||
int16_t pswSamplesRead[])
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
int iNumRead,
|
||||
i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
iNumRead = fread((char *) pswSamplesRead, sizeof (int16_t),
|
||||
iNumToRead, pfileInSpeech);
|
||||
|
||||
/* Delete the 3 LSB's - 13 bit speech input */
|
||||
/*------------------------------------------*/
|
||||
|
||||
for (i = 0; i < iNumRead; i++)
|
||||
{
|
||||
pswSamplesRead[i] &= 0xfff8;
|
||||
}
|
||||
|
||||
|
||||
/* Fill out the iNumToRead buffer with zeroes */
|
||||
/*--------------------------------------------*/
|
||||
|
||||
if (iNumRead != iNumToRead)
|
||||
{
|
||||
for (i = iNumRead; i < iNumToRead; i++)
|
||||
{
|
||||
pswSamplesRead[i] = 0;
|
||||
}
|
||||
}
|
||||
return (iNumRead);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: readDecfile
|
||||
*
|
||||
* PURPOSE:
|
||||
* Reads decoder parameter input file
|
||||
*
|
||||
* INPUT:
|
||||
* infile decoder parameter input file.
|
||||
*
|
||||
* OUTPUT:
|
||||
* pswSpeechPara array of received 16-bit values
|
||||
*
|
||||
* RETURN:
|
||||
* 0 successfully read a complete frame of data
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.2 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: pswSpeechPara
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
int readDecfile(FILE *infile, int16_t pswSpeechPara[])
|
||||
{
|
||||
if (fread((char *) pswSpeechPara, sizeof (int16_t), 22, infile) == 0)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: speechDecoderHostInterface
|
||||
*
|
||||
* PURPOSE:
|
||||
* The purpose of this function is to truncate the linear pcm and write
|
||||
* it into the output file
|
||||
*
|
||||
* INPUTS:
|
||||
*
|
||||
* F_LEN
|
||||
*
|
||||
* 160 = linear pcm output frame size
|
||||
*
|
||||
* pswDecodedSpeechFrame[0:F_LEN-1]
|
||||
*
|
||||
* 16 bit linear pcm
|
||||
*
|
||||
* OUTPUTS:
|
||||
*
|
||||
* fpfileSpeechOut
|
||||
*
|
||||
* 13 bit linear pcm stored to file given by this pointer
|
||||
*
|
||||
* RETURN VALUE:
|
||||
*
|
||||
* none
|
||||
*
|
||||
* IMPLEMENTATION:
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.2 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: synthesis, speechdecoder, decoding, truncation
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
void speechDecoderHostInterface(int16_t pswDecodedSpeechFrame[],
|
||||
FILE *fpfileSpeechOut)
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Constants |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#define PCM_MASK 0xfff8 /* 16 to 13 bit linear PCM mask */
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
short int i;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* truncate the 16 bit linear pcm to 13 bits */
|
||||
/* ----------------------------------------- */
|
||||
|
||||
for (i = 0; i < F_LEN; i++)
|
||||
{
|
||||
pswDecodedSpeechFrame[i] = pswDecodedSpeechFrame[i] & PCM_MASK;
|
||||
}
|
||||
|
||||
/* F_LEN samples of linear pcm to output file */
|
||||
/* ------------------------------------------ */
|
||||
|
||||
fwrite((char *) pswDecodedSpeechFrame, sizeof (int16_t),
|
||||
F_LEN, fpfileSpeechOut);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: writeEncfile
|
||||
*
|
||||
* PURPOSE:
|
||||
* Writes encoded parameters to ouput file
|
||||
*
|
||||
* INPUT:
|
||||
* pswSpeechPara array of encoded parameter words.
|
||||
*
|
||||
* OUTPUT:
|
||||
* fpfileEnc 16-bit encoded values.
|
||||
*
|
||||
* RETURN:
|
||||
* i number of bytes written
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.1 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: pswSpeechPara, fpfileEnc
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
int writeEncfile(int16_t pswSpeechPara[], FILE *fpfileEnc)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = fwrite((char *) pswSpeechPara, sizeof (int16_t), 20, fpfileEnc);
|
||||
|
||||
return (i);
|
||||
}
|
||||
29
src/libs/gsmhr/gsmhr_host.h
Normal file
29
src/libs/gsmhr/gsmhr_host.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef __HOSTGSM
|
||||
#define __HOSTGSM
|
||||
|
||||
#include <stdio.h>
|
||||
#include "typedefs.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void fillBitAlloc(int iVoicing, int iR0, int *piVqIndeces,
|
||||
int iSoftInterp, int *piLags,
|
||||
int *piCodeWrdsA, int *piCodeWrdsB,
|
||||
int *piGsp0s, int16_t swVadFlag,
|
||||
int16_t swSP, int16_t *pswBAlloc);
|
||||
|
||||
int hostEncoderInterface(FILE *pfileInSpeech, int iNumToRead,
|
||||
int16_t pswSamplesRead[]);
|
||||
|
||||
int readDecfile(FILE *infile, int16_t pswSpeechPara[]);
|
||||
|
||||
void speechDecoderHostInterface(int16_t pswDecodedSpeechFrame[],
|
||||
FILE *fpfileSpeechOut);
|
||||
|
||||
int writeEncfile(int16_t pswOutBit[], FILE *fpfileEnc);
|
||||
|
||||
#endif
|
||||
5471
src/libs/gsmhr/gsmhr_sp_dec.c
Normal file
5471
src/libs/gsmhr/gsmhr_sp_dec.c
Normal file
File diff suppressed because it is too large
Load Diff
100
src/libs/gsmhr/gsmhr_sp_dec.h
Normal file
100
src/libs/gsmhr/gsmhr_sp_dec.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef __SP_DEC
|
||||
#define __SP_DEC
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void speechDecoder(int16_t pswParameters[],
|
||||
int16_t pswDecodedSpeechFrame[]);
|
||||
|
||||
void aFlatRcDp(int32_t *pL_R, int16_t *pswRc);
|
||||
|
||||
void b_con(int16_t swCodeWord, short siNumBits,
|
||||
int16_t pswVectOut[]);
|
||||
|
||||
void fp_ex(int16_t swOrigLagIn, int16_t pswLTPState[]);
|
||||
|
||||
int16_t g_corr1(int16_t *pswIn, int32_t *pL_out);
|
||||
|
||||
int16_t g_corr1s(int16_t pswIn[], int16_t swEngyRShft,
|
||||
int32_t *pL_out);
|
||||
|
||||
void getSfrmLpc(short int siSoftInterpolation,
|
||||
int16_t swPrevR0, int16_t swNewR0,
|
||||
int16_t pswPrevFrmKs[],
|
||||
int16_t pswPrevFrmAs[],
|
||||
int16_t pswPrevFrmPFNum[],
|
||||
int16_t pswPrevFrmPFDenom[],
|
||||
int16_t pswNewFrmKs[],
|
||||
int16_t pswNewFrmAs[],
|
||||
int16_t pswNewFrmPFNum[],
|
||||
int16_t pswNewFrmPFDenom[],
|
||||
struct NormSw *psnsSqrtRs,
|
||||
int16_t *ppswSynthAs[],
|
||||
int16_t *ppswPFNumAs[],
|
||||
int16_t *ppswPFDenomAs[]);
|
||||
|
||||
void get_ipjj(int16_t swLagIn,
|
||||
int16_t *pswIp, int16_t *pswJj);
|
||||
|
||||
short int interpolateCheck(int16_t pswRefKs[],
|
||||
int16_t pswRefCoefsA[],
|
||||
int16_t pswOldCoefsA[],
|
||||
int16_t pswNewCoefsA[],
|
||||
int16_t swOldPer,
|
||||
int16_t swNewPer,
|
||||
int16_t swRq,
|
||||
struct NormSw *psnsSqrtRsOut,
|
||||
int16_t pswCoefOutA[]);
|
||||
|
||||
void lpcFir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswState[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcIir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswState[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcIrZsIir(int16_t pswCoef[], int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZiIir(int16_t pswCoef[], int16_t pswState[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsFir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsIir(int16_t pswInput[], int16_t pswCoef[],
|
||||
int16_t pswFiltOut[]);
|
||||
|
||||
void lpcZsIirP(int16_t pswCommonIO[], int16_t pswCoef[]);
|
||||
|
||||
int16_t r0BasedEnergyShft(int16_t swR0Index);
|
||||
|
||||
short rcToADp(int16_t swAscale, int16_t pswRc[],
|
||||
int16_t pswA[]);
|
||||
|
||||
void rcToCorrDpL(int16_t swAshift, int16_t swAscale,
|
||||
int16_t pswRc[], int32_t pL_R[]);
|
||||
|
||||
void res_eng(int16_t pswReflecCoefIn[], int16_t swRq,
|
||||
struct NormSw *psnsSqrtRsOut);
|
||||
|
||||
void rs_rr(int16_t pswExcitation[], struct NormSw snsSqrtRs,
|
||||
struct NormSw *snsSqrtRsRr);
|
||||
|
||||
void rs_rrNs(int16_t pswExcitation[], struct NormSw snsSqrtRs,
|
||||
struct NormSw *snsSqrtRsRr);
|
||||
|
||||
int16_t scaleExcite(int16_t pswVect[],
|
||||
int16_t swErrTerm, struct NormSw snsRS,
|
||||
int16_t pswScldVect[]);
|
||||
|
||||
int16_t sqroot(int32_t L_SqrtIn);
|
||||
|
||||
void v_con(int16_t pswBVects[], int16_t pswOutVect[],
|
||||
int16_t pswBitArray[], short int siNumBVctrs);
|
||||
|
||||
#endif
|
||||
406
src/libs/gsmhr/gsmhr_sp_enc.c
Normal file
406
src/libs/gsmhr/gsmhr_sp_enc.c
Normal file
@@ -0,0 +1,406 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* File Name: sp_enc.c
|
||||
*
|
||||
* Purpose: Contains speech encoder function. Calls are made to the
|
||||
* frame-based encoding functions (see sp_frm.c), and the subframe-
|
||||
* based encoding function (see sp_sfrm.c)
|
||||
*
|
||||
* Functions in this file (only 1)
|
||||
* speechEncoder()
|
||||
*
|
||||
**************************************************************************/
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Include Files |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#include "gsmhr_mathhalf.h"
|
||||
#include "gsmhr_mathdp31.h"
|
||||
#include "gsmhr_sp_rom.h"
|
||||
#include "gsmhr_sp_dec.h"
|
||||
#include "gsmhr_sp_frm.h"
|
||||
#include "gsmhr_sp_sfrm.h"
|
||||
#include "gsmhr_sp_enc.h"
|
||||
#include "gsmhr_host.h"
|
||||
#include "gsmhr_vad.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Local Defines |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
#define CG_INT_MACS 6 /* Number of Multiply-Accumulates in */
|
||||
/* one interpolation */
|
||||
#define ASCALE 0x0800
|
||||
#define LMAX 142 /* largest lag (integer sense) */
|
||||
#define LSMAX (LMAX+ CG_INT_MACS/2) /* Lag Search Array Length */
|
||||
#define NUM_CLOSED 3 /* Maximum number of lags searched */
|
||||
/* in closed loop. */
|
||||
|
||||
#define LPCSTARTINDEX 25 /* Where the LPC analysis window
|
||||
* starts */
|
||||
#define INBUFFSZ LPCSTARTINDEX + A_LEN /* Input buffer size */
|
||||
#define NUMSTARTUPSMP INBUFFSZ - F_LEN /* Number of samples needed */
|
||||
/* at start up */
|
||||
#define NUMSTARTUPSMP_P1 INBUFFSZ - F_LEN + 1
|
||||
#define HPFSHIFT 1 /* no right shifts high pass shifts
|
||||
* speech */
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| State variables (globals) |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int16_t swOldR0;
|
||||
int16_t swOldR0Index;
|
||||
|
||||
struct NormSw psnsWSfrmEngSpace[2 * N_SUB];
|
||||
|
||||
int16_t pswHPFXState[4];
|
||||
int16_t pswHPFYState[8];
|
||||
int16_t pswOldFrmKs[NP];
|
||||
int16_t pswOldFrmAs[NP];
|
||||
int16_t pswOldFrmSNWCoefs[NP];
|
||||
int16_t pswWgtSpeechSpace[F_LEN + LMAX + CG_INT_MACS / 2];
|
||||
|
||||
int16_t pswSpeech[INBUFFSZ]; /* input speech */
|
||||
|
||||
int16_t swPtch = 1;
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Global DTX variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int16_t swTxGsHistPtr = 0;
|
||||
|
||||
int16_t pswCNVSCode1[N_SUB],
|
||||
pswCNVSCode2[N_SUB],
|
||||
pswCNGsp0Code[N_SUB],
|
||||
pswCNLpc[3],
|
||||
swCNR0;
|
||||
|
||||
|
||||
extern int32_t pL_GsHist[];
|
||||
extern int32_tRom ppLr_gsTable[4][32];
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* FUNCTION NAME: speechEncoder
|
||||
*
|
||||
* PURPOSE:
|
||||
*
|
||||
* Performs GSM half-rate speech encoding on frame basis (160 samples).
|
||||
*
|
||||
* INPUTS:
|
||||
*
|
||||
* pswSpeechIn[0:159] - input speech samples, 160 new samples per frame
|
||||
*
|
||||
* OUTPUTS:
|
||||
*
|
||||
* pswFrmCodes[0:19] - output parameters, 18 speech parameters plus
|
||||
* VAD and SP flags
|
||||
*
|
||||
* RETURN VALUE:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* IMPLEMENTATION:
|
||||
*
|
||||
* n/a
|
||||
*
|
||||
* REFERENCES: Sub-clause 4.1 of GSM Recomendation 06.20
|
||||
*
|
||||
* KEYWORDS: speechcoder, analysis
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
void speechEncoder(int16_t pswSpeechIn[], int16_t pswFrmCodes[])
|
||||
{
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Static Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* 1st point in analysis window */
|
||||
static int16_t *pswLpcStart = &pswSpeech[LPCSTARTINDEX];
|
||||
|
||||
/* 1st point of new frame other than 1st */
|
||||
static int16_t *pswNewSpeech = &pswSpeech[NUMSTARTUPSMP];
|
||||
|
||||
/* sample 0 of weighted speech */
|
||||
static int16_t *pswWgtSpeech = &pswWgtSpeechSpace[LSMAX];
|
||||
|
||||
static struct NormSw *psnsWSfrmEng = &psnsWSfrmEngSpace[N_SUB];
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Automatic Variables |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int iVoicing, /* bitAlloc */
|
||||
iR0, /* bitAlloc and aflat */
|
||||
piVq[3], /* bitAlloc */
|
||||
iSi, /* bitAlloc */
|
||||
piLagCode[N_SUB], /* bitAlloc */
|
||||
piVSCode1[N_SUB], /* bitAlloc */
|
||||
piVSCode2[N_SUB], /* bitAlloc */
|
||||
piGsp0Code[N_SUB]; /* bitAlloc */
|
||||
|
||||
short int siUVCode,
|
||||
siSi,
|
||||
i,
|
||||
j;
|
||||
|
||||
int16_t swR0,
|
||||
pswLagCode[N_SUB],
|
||||
pswVSCode1[N_SUB],
|
||||
pswVSCode2[N_SUB],
|
||||
pswGsp0Code[N_SUB],
|
||||
*pswLagListPtr,
|
||||
pswFrmKs[NP],
|
||||
pswFrmAs[NP],
|
||||
pswFrmSNWCoefs[NP],
|
||||
pswLagList[N_SUB * NUM_CLOSED],
|
||||
pswNumLagList[N_SUB],
|
||||
pswPitchBuf[N_SUB],
|
||||
pswHNWCoefBuf[N_SUB],
|
||||
ppswSNWCoefAs[N_SUB][NP],
|
||||
ppswSynthAs[N_SUB][NP];
|
||||
|
||||
int16_t swSP,
|
||||
pswVadLags[4], /* VAD Parameters */
|
||||
swVadFlag; /* flag indicating voice activity
|
||||
* detector state. 1 = speech or
|
||||
* speech/signal present */
|
||||
struct NormSw
|
||||
psnsSqrtRs[N_SUB];
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Executable Code |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* Speech frame processing */
|
||||
/* High pass filter the speech */
|
||||
/* ---------------------------- */
|
||||
|
||||
filt4_2nd(psrHPFCoefs, pswSpeechIn,
|
||||
pswHPFXState, pswHPFYState, F_LEN, HPFSHIFT);
|
||||
|
||||
/* copy high passed filtered speech into encoder's speech buff */
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
for (i = 0; i < F_LEN; i++)
|
||||
pswNewSpeech[i] = pswSpeechIn[i];
|
||||
|
||||
|
||||
|
||||
|
||||
/* Calculate and quantize LPC coefficients */
|
||||
/* --------------------------------------- */
|
||||
|
||||
aflat(pswLpcStart, &iR0, pswFrmKs, piVq,
|
||||
swPtch, &swVadFlag, &swSP);
|
||||
|
||||
|
||||
/* Lookup frame energy r0 */
|
||||
/* ---------------------- */
|
||||
|
||||
swR0 = psrR0DecTbl[iR0 * 2]; /* lookupR0 */
|
||||
|
||||
/* Generate the direct form coefs */
|
||||
/* ------------------------------ */
|
||||
|
||||
if (!rcToADp(ASCALE, pswFrmKs, pswFrmAs))
|
||||
{
|
||||
|
||||
getNWCoefs(pswFrmAs, pswFrmSNWCoefs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
pswFrmKs[i] = pswOldFrmKs[i];
|
||||
pswFrmAs[i] = pswOldFrmAs[i];
|
||||
pswFrmSNWCoefs[i] = pswOldFrmSNWCoefs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Interpolate, or otherwise get sfrm reflection coefs */
|
||||
/* --------------------------------------------------- */
|
||||
|
||||
getSfrmLpcTx(swOldR0, swR0,
|
||||
pswOldFrmKs, pswOldFrmAs,
|
||||
pswOldFrmSNWCoefs,
|
||||
pswFrmKs, pswFrmAs,
|
||||
pswFrmSNWCoefs,
|
||||
pswSpeech,
|
||||
&siSi,
|
||||
psnsSqrtRs,
|
||||
ppswSynthAs, ppswSNWCoefAs);
|
||||
|
||||
/* loose once bitAlloc done */
|
||||
iSi = siSi;
|
||||
|
||||
/* Weight the entire speech frame */
|
||||
/* ------------------------------ */
|
||||
|
||||
weightSpeechFrame(pswSpeech, ppswSynthAs[0], ppswSNWCoefAs[0],
|
||||
pswWgtSpeechSpace);
|
||||
|
||||
/* Perform open-loop lag search, get harmonic-noise-weighting parameters */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
openLoopLagSearch(&pswWgtSpeechSpace[LSMAX],
|
||||
swOldR0Index,
|
||||
(int16_t) iR0,
|
||||
&siUVCode,
|
||||
pswLagList,
|
||||
pswNumLagList,
|
||||
pswPitchBuf,
|
||||
pswHNWCoefBuf,
|
||||
&psnsWSfrmEng[0],
|
||||
pswVadLags,
|
||||
swSP);
|
||||
|
||||
iVoicing = siUVCode;
|
||||
|
||||
|
||||
/* Using open loop LTP data to calculate swPtch */ /* DTX mode */
|
||||
/* parameter */ /* DTX mode */
|
||||
/* -------------------------------------------- */ /* DTX mode */
|
||||
|
||||
periodicity_update(pswVadLags, &swPtch); /* DTX mode */
|
||||
|
||||
|
||||
/* Subframe processing loop */
|
||||
/* ------------------------ */
|
||||
|
||||
pswLagListPtr = pswLagList;
|
||||
|
||||
for (giSfrmCnt = 0; giSfrmCnt < N_SUB; giSfrmCnt++)
|
||||
{
|
||||
|
||||
if (swSP == 0) /* DTX mode */
|
||||
{ /* DTX mode */
|
||||
pswVSCode1[giSfrmCnt] = pswCNVSCode1[giSfrmCnt]; /* DTX mode */
|
||||
pswVSCode2[giSfrmCnt] = pswCNVSCode2[giSfrmCnt]; /* DTX mode */
|
||||
pswGsp0Code[giSfrmCnt] = pswCNGsp0Code[giSfrmCnt]; /* DTX mode */
|
||||
} /* DTX mode */
|
||||
|
||||
sfrmAnalysis(&pswWgtSpeech[giSfrmCnt * S_LEN],
|
||||
siUVCode,
|
||||
psnsSqrtRs[giSfrmCnt],
|
||||
ppswSNWCoefAs[giSfrmCnt],
|
||||
pswLagListPtr,
|
||||
pswNumLagList[giSfrmCnt],
|
||||
pswPitchBuf[giSfrmCnt],
|
||||
pswHNWCoefBuf[giSfrmCnt],
|
||||
&pswLagCode[giSfrmCnt], &pswVSCode1[giSfrmCnt],
|
||||
&pswVSCode2[giSfrmCnt], &pswGsp0Code[giSfrmCnt],
|
||||
swSP);
|
||||
|
||||
pswLagListPtr = &pswLagListPtr[pswNumLagList[giSfrmCnt]];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* copy comfort noise parameters, */ /* DTX mode */
|
||||
/* update GS history */ /* DTX mode */
|
||||
/* ------------------------------ */ /* DTX mode */
|
||||
|
||||
if (swSP == 0) /* DTX mode */
|
||||
{ /* DTX mode */
|
||||
|
||||
/* copy comfort noise frame parameter */ /* DTX mode */
|
||||
/* ---------------------------------- */ /* DTX mode */
|
||||
|
||||
iR0 = swCNR0; /* quantized R0 index */ /* DTX mode */
|
||||
for (i=0; i < 3; i++) /* DTX mode */
|
||||
piVq[i] = pswCNLpc[i]; /* DTX mode */
|
||||
|
||||
} /* DTX mode */
|
||||
else /* DTX mode */
|
||||
{ /* DTX mode */
|
||||
|
||||
/* if swSP != 0, then update the GS history */ /* DTX mode */
|
||||
/* -----------------------------------------*/ /* DTX mode */
|
||||
|
||||
for (i=0; i < N_SUB; i++){ /* DTX mode */
|
||||
pL_GsHist[swTxGsHistPtr] = /* DTX mode */
|
||||
ppLr_gsTable[siUVCode][pswGsp0Code[i]]; /* DTX mode */
|
||||
swTxGsHistPtr++; /* DTX mode */
|
||||
if (swTxGsHistPtr > ((OVERHANG-1)*N_SUB)-1) /* DTX mode */
|
||||
swTxGsHistPtr=0; /* DTX mode */
|
||||
} /* DTX mode */
|
||||
|
||||
} /* DTX mode */
|
||||
|
||||
|
||||
/* End of frame processing, update frame based parameters */
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
for (i = 0; i < N_SUB; i++)
|
||||
{
|
||||
piLagCode[i] = pswLagCode[i];
|
||||
piVSCode1[i] = pswVSCode1[i];
|
||||
piVSCode2[i] = pswVSCode2[i];
|
||||
piGsp0Code[i] = pswGsp0Code[i];
|
||||
}
|
||||
|
||||
swOldR0Index = (int16_t) iR0;
|
||||
swOldR0 = swR0;
|
||||
|
||||
for (i = 0; i < NP; i++)
|
||||
{
|
||||
pswOldFrmKs[i] = pswFrmKs[i];
|
||||
pswOldFrmAs[i] = pswFrmAs[i];
|
||||
pswOldFrmSNWCoefs[i] = pswFrmSNWCoefs[i];
|
||||
}
|
||||
|
||||
/* Insert SID Codeword */ /* DTX mode */
|
||||
/* ------------------- */ /* DTX mode */
|
||||
|
||||
if (swSP == 0) /* DTX mode */
|
||||
{ /* DTX mode */
|
||||
iVoicing = 0x0003; /* 2 bits */ /* DTX mode */
|
||||
iSi = 0x0001; /* 1 bit */ /* DTX mode */
|
||||
for (i=0; i < N_SUB; i++) /* DTX mode */
|
||||
{ /* DTX mode */
|
||||
piVSCode1[i] = 0x01ff; /* 9 bits */ /* DTX mode */
|
||||
piGsp0Code[i] = 0x001f; /* 5 bits */ /* DTX mode */
|
||||
}
|
||||
piLagCode[0] = 0x00ff; /* 8 bits */ /* DTX mode */
|
||||
piLagCode[1] = 0x000f; /* 4 bits */ /* DTX mode */
|
||||
piLagCode[2] = 0x000f; /* 4 bits */ /* DTX mode */
|
||||
piLagCode[3] = 0x000f; /* 4 bits */ /* DTX mode */
|
||||
} /* DTX mode */
|
||||
|
||||
|
||||
/* Generate encoded parameter array */
|
||||
/* -------------------------------- */
|
||||
|
||||
fillBitAlloc(iVoicing, iR0, piVq, iSi, piLagCode,
|
||||
piVSCode1, piVSCode2,
|
||||
piGsp0Code, swVadFlag, swSP, pswFrmCodes);
|
||||
|
||||
|
||||
/* delay the input speech by 1 frame */
|
||||
/*-----------------------------------*/
|
||||
|
||||
for (i = 0, j = F_LEN; j < INBUFFSZ; i++, j++)
|
||||
{
|
||||
pswSpeech[i] = pswSpeech[j];
|
||||
}
|
||||
}
|
||||
14
src/libs/gsmhr/gsmhr_sp_enc.h
Normal file
14
src/libs/gsmhr/gsmhr_sp_enc.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __SP_ENC
|
||||
#define __SP_ENC
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void speechEncoder(int16_t pswSpeechIn[], int16_t pswFrmCodes[]);
|
||||
|
||||
#endif
|
||||
5908
src/libs/gsmhr/gsmhr_sp_frm.c
Normal file
5908
src/libs/gsmhr/gsmhr_sp_frm.c
Normal file
File diff suppressed because it is too large
Load Diff
201
src/libs/gsmhr/gsmhr_sp_frm.h
Normal file
201
src/libs/gsmhr/gsmhr_sp_frm.h
Normal file
@@ -0,0 +1,201 @@
|
||||
#ifndef __SP_FRM
|
||||
#define __SP_FRM
|
||||
|
||||
#include "gsmhr_typedefs.h"
|
||||
#include "gsmhr_sp_rom.h"
|
||||
|
||||
|
||||
struct QuantList
|
||||
{
|
||||
/* structure which points to the beginning of a block of candidate vq
|
||||
* vectors. It also stores the residual error for each vector. */
|
||||
int iNum; /* total number in list */
|
||||
int iRCIndex; /* an index to the first vector of the
|
||||
* block */
|
||||
int16_t pswPredErr[PREQ1_NUM_OF_ROWS]; /* PREQ1 is the biggest block */
|
||||
};
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void iir_d(int16_t pswCoeff[], int16_t pswIn[],
|
||||
int16_t pswXstate[],
|
||||
int16_t pswYstate[],
|
||||
int npts, int shifts,
|
||||
int16_t swPreFirDownSh,
|
||||
int16_t swFinalUpShift);
|
||||
|
||||
|
||||
void filt4_2nd(int16_t pswCoeff[],
|
||||
int16_t pswIn[],
|
||||
int16_t pswXstate[],
|
||||
int16_t pswYstate[],
|
||||
int npts,
|
||||
int shifts);
|
||||
|
||||
void initPBarVBarL(int32_t pL_PBarFull[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[]);
|
||||
|
||||
void initPBarFullVBarFullL(int32_t pL_CorrelSeq[],
|
||||
int32_t pL_PBarFull[],
|
||||
int32_t pL_VBarFull[]);
|
||||
|
||||
int16_t aflatRecursion(int16_t pswQntRc[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[],
|
||||
int16_t *ppswPAddrs[],
|
||||
int16_t *ppswVAddrs[],
|
||||
int16_t swSegmentOrder);
|
||||
|
||||
void aflatNewBarRecursionL(int16_t pswQntRc[],
|
||||
int iSegment,
|
||||
int32_t pL_PBar[],
|
||||
int32_t pL_VBar[],
|
||||
int16_t pswPBar[],
|
||||
int16_t pswVBar[]);
|
||||
|
||||
|
||||
void setupPreQ(int iSeg, int iVector);
|
||||
|
||||
void setupQuant(int iSeg, int iVector);
|
||||
|
||||
void getNextVec(int16_t pswRc[]);
|
||||
|
||||
void aflat(int16_t pswSpeechToLPC[],
|
||||
int piR0Index[],
|
||||
int16_t pswFinalRc[],
|
||||
int piVQCodewds[],
|
||||
int16_t swPtch,
|
||||
int16_t *pswVadFlag,
|
||||
int16_t *pswSP);
|
||||
|
||||
|
||||
int16_t fnExp2(int32_t L_Input);
|
||||
|
||||
int16_t fnLog2(int32_t L_Input);
|
||||
|
||||
void weightSpeechFrame(int16_t pswSpeechFrm[],
|
||||
int16_t pswWNumSpace[],
|
||||
int16_t pswWDenomSpace[],
|
||||
int16_t pswWSpeechBuffBase[]);
|
||||
|
||||
void getSfrmLpcTx(int16_t swPrevR0, int16_t swNewR0,
|
||||
int16_t pswPrevFrmKs[],
|
||||
int16_t pswPrevFrmAs[],
|
||||
int16_t pswPrevFrmSNWCoef[],
|
||||
int16_t pswNewFrmKs[],
|
||||
int16_t pswNewFrmAs[],
|
||||
int16_t pswNewFrmSNWCoef[],
|
||||
int16_t pswHPFSpeech[],
|
||||
short *pswSoftInterp,
|
||||
struct NormSw *psnsSqrtRs,
|
||||
int16_t ppswSynthAs[][NP],
|
||||
int16_t ppswSNWCoefAs[][NP]);
|
||||
|
||||
short int fnBest_CG(int16_t pswCframe[],
|
||||
int16_t pswGframe[],
|
||||
int16_t *pswCmaxSqr,
|
||||
int16_t *pswGmax,
|
||||
short int siNumPairs);
|
||||
|
||||
short compResidEnergy(int16_t pswSpeech[],
|
||||
int16_t ppswInterpCoef[][NP],
|
||||
int16_t pswPreviousCoef[],
|
||||
int16_t pswCurrentCoef[],
|
||||
struct NormSw psnsSqrtRs[]);
|
||||
|
||||
int16_t r0Quant(int32_t L_UnqntzdR0);
|
||||
|
||||
int16_t cov32(int16_t pswIn[],
|
||||
int32_t pppL_B[NP][NP][2],
|
||||
int32_t pppL_F[NP][NP][2],
|
||||
int32_t pppL_C[NP][NP][2],
|
||||
int32_t *pL_R0,
|
||||
int32_t pL_VadAcf[],
|
||||
int16_t *pswVadScalAuto);
|
||||
|
||||
int32_t flat(int16_t pswSpeechIn[],
|
||||
int16_t pswRc[],
|
||||
int *piR0Inx,
|
||||
int32_t pL_VadAcf[],
|
||||
int16_t *pswVadScalAuto);
|
||||
|
||||
|
||||
|
||||
void openLoopLagSearch(int16_t pswWSpeech[],
|
||||
int16_t swPrevR0Index,
|
||||
int16_t swCurrR0Index,
|
||||
int16_t *psiUVCode,
|
||||
int16_t pswLagList[],
|
||||
int16_t pswNumLagList[],
|
||||
int16_t pswPitchBuf[],
|
||||
int16_t pswHNWCoefBuf[],
|
||||
struct NormSw psnsWSfrmEng[],
|
||||
int16_t pswVadLags[],
|
||||
int16_t swSP);
|
||||
|
||||
int16_t getCCThreshold(int16_t swRp0,
|
||||
int16_t swCC,
|
||||
int16_t swG);
|
||||
|
||||
void pitchLags(int16_t swBestIntLag,
|
||||
int16_t pswIntCs[],
|
||||
int16_t pswIntGs[],
|
||||
int16_t swCCThreshold,
|
||||
int16_t pswLPeaksSorted[],
|
||||
int16_t pswCPeaksSorted[],
|
||||
int16_t pswGPeaksSorted[],
|
||||
int16_t *psiNumSorted,
|
||||
int16_t *pswPitch,
|
||||
int16_t *pswHNWCoef);
|
||||
|
||||
short CGInterpValid(int16_t swFullResLag,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
int16_t pswLOut[],
|
||||
int16_t pswCOut[],
|
||||
int16_t pswGOut[]);
|
||||
|
||||
void CGInterp(int16_t pswLIn[],
|
||||
short siNum,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
short siLoIntLag,
|
||||
int16_t pswCOut[],
|
||||
int16_t pswGOut[]);
|
||||
|
||||
int16_t quantLag(int16_t swRawLag,
|
||||
int16_t *psiCode);
|
||||
|
||||
void findBestInQuantList(struct QuantList psqlInList,
|
||||
int iNumVectOut,
|
||||
struct QuantList psqlBestOutList[]);
|
||||
|
||||
int16_t findPeak(int16_t swSingleResLag,
|
||||
int16_t pswCIn[],
|
||||
int16_t pswGIn[]);
|
||||
|
||||
void bestDelta(int16_t pswLagList[],
|
||||
int16_t pswCSfrm[],
|
||||
int16_t pswGSfrm[],
|
||||
short int siNumLags,
|
||||
short int siSfrmIndex,
|
||||
int16_t pswLTraj[],
|
||||
int16_t pswCCTraj[],
|
||||
int16_t pswGTraj[]);
|
||||
|
||||
int16_t
|
||||
maxCCOverGWithSign(int16_t pswCIn[],
|
||||
int16_t pswGIn[],
|
||||
int16_t *pswCCMax,
|
||||
int16_t *pswGMax,
|
||||
int16_t swNum);
|
||||
|
||||
void getNWCoefs(int16_t pswACoefs[],
|
||||
int16_t pswHCoefs[]);
|
||||
|
||||
#endif
|
||||
6592
src/libs/gsmhr/gsmhr_sp_rom.c
Normal file
6592
src/libs/gsmhr/gsmhr_sp_rom.c
Normal file
File diff suppressed because it is too large
Load Diff
193
src/libs/gsmhr/gsmhr_sp_rom.h
Normal file
193
src/libs/gsmhr/gsmhr_sp_rom.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Purpose: Define the structure of the Global Constants
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef ___ROM
|
||||
#define ___ROM
|
||||
|
||||
#include "gsmhr_typedefs.h"
|
||||
//#include "gsmhr_mathhalf.h"
|
||||
//#include "gsmhr_mathdp31.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Data Types |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
/* gsp0 vector quantizer */
|
||||
/*-----------------------*/
|
||||
#define GSP0_NUM_OF_TABLES 4
|
||||
#define GSP0_NUM 32
|
||||
#define GSP0_VECTOR_SIZE 5
|
||||
|
||||
extern int16_tRom pppsrGsp0
|
||||
[GSP0_NUM_OF_TABLES][GSP0_NUM][GSP0_VECTOR_SIZE];
|
||||
|
||||
|
||||
/* unvoiced code vectors */
|
||||
/*-----------------------*/
|
||||
#define UVCODEVEC_NUM_OF_CODE_BOOKS 2
|
||||
#define UVCODEVEC_NUM_OF_CODE_BITS 7
|
||||
|
||||
extern int16_tRom pppsrUvCodeVec
|
||||
[UVCODEVEC_NUM_OF_CODE_BOOKS][UVCODEVEC_NUM_OF_CODE_BITS][S_LEN];
|
||||
|
||||
|
||||
/* voiced code vectors */
|
||||
/*---------------------*/
|
||||
#define VCDCODEVEC_NUM_OF_CODE_BOOKS 1
|
||||
#define VCDCODEVEC_NUM_OF_CODE_BITS 9
|
||||
|
||||
extern int16_tRom pppsrVcdCodeVec
|
||||
[VCDCODEVEC_NUM_OF_CODE_BOOKS][VCDCODEVEC_NUM_OF_CODE_BITS][S_LEN];
|
||||
|
||||
|
||||
/* vector quantizer tables */
|
||||
/*-------------------------*/
|
||||
#define QUANT_NUM_OF_TABLES 3
|
||||
|
||||
#define QUANT1_NUM_OF_BITS 11
|
||||
#define QUANT1_NUM_OF_ROWS (1 << QUANT1_NUM_OF_BITS)
|
||||
#define QUANT1_NUM_OF_STAGES 3
|
||||
#define QUANT1_NUM_OF_WORDS (QUANT1_NUM_OF_ROWS*QUANT1_NUM_OF_STAGES/2)
|
||||
|
||||
#define QUANT2_NUM_OF_BITS 9
|
||||
#define QUANT2_NUM_OF_ROWS (1 << QUANT2_NUM_OF_BITS)
|
||||
#define QUANT2_NUM_OF_STAGES 3
|
||||
#define QUANT2_NUM_OF_WORDS (QUANT2_NUM_OF_ROWS*QUANT2_NUM_OF_STAGES/2)
|
||||
|
||||
#define QUANT3_NUM_OF_BITS 8
|
||||
#define QUANT3_NUM_OF_ROWS (1 << QUANT3_NUM_OF_BITS)
|
||||
#define QUANT3_NUM_OF_STAGES 4
|
||||
#define QUANT3_NUM_OF_WORDS (QUANT3_NUM_OF_ROWS*QUANT3_NUM_OF_STAGES/2)
|
||||
|
||||
extern int16_tRom psrQuant1[QUANT1_NUM_OF_WORDS];
|
||||
|
||||
extern int16_tRom psrQuant2[QUANT2_NUM_OF_WORDS];
|
||||
|
||||
extern int16_tRom psrQuant3[QUANT3_NUM_OF_WORDS];
|
||||
|
||||
|
||||
/* lpc pre-quantizer */
|
||||
/*-------------------*/
|
||||
#define PREQ1_NUM_OF_BITS 6
|
||||
#define PREQ1_NUM_OF_ROWS (1 << PREQ1_NUM_OF_BITS)
|
||||
#define PREQ1_NUM_OF_STAGES 3
|
||||
#define PREQ1_NUM_OF_WORDS (PREQ1_NUM_OF_ROWS*PREQ1_NUM_OF_STAGES/2)
|
||||
|
||||
#define PREQ2_NUM_OF_BITS 5
|
||||
#define PREQ2_NUM_OF_ROWS (1 << PREQ2_NUM_OF_BITS)
|
||||
#define PREQ2_NUM_OF_STAGES 3
|
||||
#define PREQ2_NUM_OF_WORDS (PREQ2_NUM_OF_ROWS*PREQ2_NUM_OF_STAGES/2)
|
||||
|
||||
#define PREQ3_NUM_OF_BITS 4
|
||||
#define PREQ3_NUM_OF_ROWS (1 << PREQ3_NUM_OF_BITS)
|
||||
#define PREQ3_NUM_OF_STAGES 4
|
||||
#define PREQ3_NUM_OF_WORDS (PREQ3_NUM_OF_ROWS*PREQ3_NUM_OF_STAGES/2)
|
||||
|
||||
extern int16_tRom psrPreQ1[PREQ1_NUM_OF_WORDS];
|
||||
|
||||
extern int16_tRom psrPreQ2[PREQ2_NUM_OF_WORDS];
|
||||
|
||||
extern int16_tRom psrPreQ3[PREQ3_NUM_OF_WORDS];
|
||||
|
||||
|
||||
/* size of the vq subset in the kth segment */
|
||||
/*------------------------------------------*/
|
||||
extern int16_tRom psrQuantSz[QUANT_NUM_OF_TABLES];
|
||||
|
||||
|
||||
/* pre-quantizer size */
|
||||
/*--------------------*/
|
||||
extern int16_tRom psrPreQSz[QUANT_NUM_OF_TABLES];
|
||||
|
||||
|
||||
/* reflection coeff scalar quantizer */
|
||||
/*-----------------------------------*/
|
||||
#define SQUANT_NUM_OF_BITS 8
|
||||
#define SQUANT_NUM_OF_ROWS (1 << SQUANT_NUM_OF_BITS)
|
||||
|
||||
extern int16_tRom psrSQuant[SQUANT_NUM_OF_ROWS];
|
||||
|
||||
|
||||
/* index structure for LPC Vector Quantizer */
|
||||
/*------------------------------------------*/
|
||||
struct IsubLHn
|
||||
{ /* index structure for LPC Vector
|
||||
* Quantizer */
|
||||
int16_tRom l; /* lowest index index range
|
||||
* from 1..NP */
|
||||
int16_tRom h; /* highest index */
|
||||
int16_tRom len; /* h-l+1 */
|
||||
};
|
||||
|
||||
|
||||
extern struct IsubLHn psvqIndex[QUANT_NUM_OF_TABLES];
|
||||
|
||||
|
||||
/* square root of p0 table */
|
||||
/*-------------------------*/
|
||||
#define SQRTP0_NUM_OF_BITS 5
|
||||
#define SQRTP0_NUM_OF_ROWS (1 << SQRTP0_NUM_OF_BITS)
|
||||
#define SQRTP0_NUM_OF_MODES 3
|
||||
|
||||
extern int16_tRom ppsrSqrtP0[SQRTP0_NUM_OF_MODES][SQRTP0_NUM_OF_ROWS];
|
||||
|
||||
|
||||
/* interpolation filter used for C and G */
|
||||
/*---------------------------------------*/
|
||||
#define CGINTFILT_MACS 6
|
||||
|
||||
extern int16_tRom ppsrCGIntFilt[CGINTFILT_MACS][OS_FCTR];
|
||||
|
||||
|
||||
/* interpolation filter used pitch */
|
||||
/*---------------------------------*/
|
||||
#define PVECINTFILT_MACS 10
|
||||
|
||||
extern int16_tRom ppsrPVecIntFilt[PVECINTFILT_MACS][OS_FCTR];
|
||||
|
||||
|
||||
/* fractional pitch lag table lag*OS_FCTR */
|
||||
/*----------------------------------------*/
|
||||
#define LAGTBL_NUM_OF_ROWS 256
|
||||
|
||||
extern int16_tRom psrLagTbl[LAGTBL_NUM_OF_ROWS];
|
||||
|
||||
|
||||
/* R0 decision value table defines range (not the levels themselves */
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
#define R0DECTBL_NUM_OF_R0BITS 5
|
||||
#define R0DECTBL_NUM_OF_ROWS ((1 << R0DECTBL_NUM_OF_R0BITS)*2 - 1)
|
||||
|
||||
extern int16_tRom psrR0DecTbl[R0DECTBL_NUM_OF_ROWS];
|
||||
|
||||
|
||||
/* high pass filter coefficients */
|
||||
/*-------------------------------*/
|
||||
#define HPFCOEFS_NUM_OF_CODES 10
|
||||
|
||||
extern int16_tRom psrHPFCoefs[HPFCOEFS_NUM_OF_CODES];
|
||||
|
||||
|
||||
/* spectral smoothing coefficients */
|
||||
/*---------------------------------*/
|
||||
#define NWCOEFS_NUM_OF_CODES 20
|
||||
|
||||
extern int16_tRom psrNWCoefs[NWCOEFS_NUM_OF_CODES];
|
||||
|
||||
|
||||
/* spectral smoothing coefficients for FLAT */
|
||||
/*------------------------------------------*/
|
||||
#define FLATSSTCOEFS_NUM_OF_CODES 10
|
||||
|
||||
extern int32_tRom pL_rFlatSstCoefs[FLATSSTCOEFS_NUM_OF_CODES];
|
||||
|
||||
extern int16_tRom psrOldCont[4];
|
||||
extern int16_tRom psrNewCont[4];
|
||||
|
||||
#endif
|
||||
2360
src/libs/gsmhr/gsmhr_sp_sfrm.c
Normal file
2360
src/libs/gsmhr/gsmhr_sp_sfrm.c
Normal file
File diff suppressed because it is too large
Load Diff
65
src/libs/gsmhr/gsmhr_sp_sfrm.h
Normal file
65
src/libs/gsmhr/gsmhr_sp_sfrm.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef __SP_SFRM
|
||||
#define __SP_SFRM
|
||||
|
||||
#include "gsmfr_typedefs.h"
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
int16_t g_corr2(int16_t *pswIn, int16_t *pswIn2,
|
||||
int32_t *pL_out);
|
||||
|
||||
int closedLoopLagSearch(int16_t pswLagList[],
|
||||
int iNumLags,
|
||||
int16_t pswLtpState[],
|
||||
int16_t pswHCoefs[],
|
||||
int16_t pswPVect[],
|
||||
int16_t *pswLag,
|
||||
int16_t *pswLtpShift);
|
||||
|
||||
void decorr(int iNumVects,
|
||||
int16_t pswGivenVect[],
|
||||
int16_t pswVects[]);
|
||||
|
||||
int16_t g_quant_vl(int16_t swUVCode,
|
||||
int16_t pswWInput[],
|
||||
int16_t swWIShift,
|
||||
int16_t pswWLTPVec[],
|
||||
int16_t pswWVSVec1[],
|
||||
int16_t pswWVSVec2[],
|
||||
struct NormSw snsRs00,
|
||||
struct NormSw snsRs11,
|
||||
struct NormSw snsRs22);
|
||||
|
||||
void gainTweak(struct NormSw *psErrorTerm);
|
||||
|
||||
void hnwFilt(int16_t pswInSample[],
|
||||
int16_t pswOutSample[],
|
||||
int16_t pswState[],
|
||||
int16_t pswInCoef[],
|
||||
int iStateOffset,
|
||||
int16_t swZeroState,
|
||||
int iNumSamples);
|
||||
|
||||
void sfrmAnalysis(int16_t *pswWSpeech,
|
||||
int16_t swVoicingMode,
|
||||
struct NormSw snsSqrtRs,
|
||||
int16_t *pswHCoefs,
|
||||
int16_t *pswLagList,
|
||||
short siNumLags,
|
||||
int16_t swPitch,
|
||||
int16_t swHNWCoef,
|
||||
short *psiLagCode,
|
||||
short *psiVSCode1,
|
||||
short *psiVSCode2,
|
||||
short *psiGsp0Code,
|
||||
int16_t swSP);
|
||||
|
||||
int16_t v_srch(int16_t pswWInput[],
|
||||
int16_t pswWBasisVecs[],
|
||||
short int siNumBasis);
|
||||
|
||||
#endif
|
||||
63
src/libs/gsmhr/gsmhr_typedefs.h
Normal file
63
src/libs/gsmhr/gsmhr_typedefs.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*******************************************************************
|
||||
*
|
||||
* typedef statements of types used in all half-rate GSM routines
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#ifndef __GSM_HR_TYPEDEFS
|
||||
#define __GSM_HR_TYPEDEFS
|
||||
|
||||
#define DATE "August 8, 1996 "
|
||||
#define VERSION "Version 4.2 "
|
||||
|
||||
#define LW_SIGN (long)0x80000000 /* sign bit */
|
||||
#define LW_MIN (long)0x80000000
|
||||
#define LW_MAX (long)0x7fffffff
|
||||
|
||||
#define SW_SIGN (short)0x8000 /* sign bit for int16_t type */
|
||||
#define SW_MIN (short)0x8000 /* smallest Ram */
|
||||
#define SW_MAX (short)0x7fff /* largest Ram */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Definition of Types *
|
||||
***********************/
|
||||
|
||||
/* 32 bit "accumulator" (L_*) */
|
||||
/* 16 bit "register" (sw*) */
|
||||
typedef short int int16_tRom; /* 16 bit ROM data (sr*) */
|
||||
typedef long int int32_tRom; /* 32 bit ROM data (L_r*) */
|
||||
|
||||
struct NormSw
|
||||
{ /* normalized int16_t fractional
|
||||
* number snr.man precedes snr.sh (the
|
||||
* shift count)i */
|
||||
int16_t man; /* "mantissa" stored in 16 bit
|
||||
* location */
|
||||
int16_t sh; /* the shift count, stored in 16 bit
|
||||
* location */
|
||||
};
|
||||
|
||||
/* Global constants *
|
||||
********************/
|
||||
|
||||
#define NP 10 /* order of the lpc filter */
|
||||
#define N_SUB 4 /* number of subframes */
|
||||
#define F_LEN 160 /* number of samples in a frame */
|
||||
#define S_LEN 40 /* number of samples in a subframe */
|
||||
#define A_LEN 170 /* LPC analysis length */
|
||||
#define OS_FCTR 6 /* maximum LTP lag oversampling
|
||||
* factor */
|
||||
|
||||
#define OVERHANG 8 /* vad parameter */
|
||||
#define strStr strStr16
|
||||
|
||||
/* global variables */
|
||||
/********************/
|
||||
|
||||
extern int giFrmCnt; /* 0,1,2,3,4..... */
|
||||
extern int giSfrmCnt; /* 0,1,2,3 */
|
||||
|
||||
extern int giDTXon; /* DTX Mode on/off */
|
||||
|
||||
#endif
|
||||
1106
src/libs/gsmhr/gsmhr_utils.c
Normal file
1106
src/libs/gsmhr/gsmhr_utils.c
Normal file
File diff suppressed because it is too large
Load Diff
1363
src/libs/gsmhr/gsmhr_vad.c
Normal file
1363
src/libs/gsmhr/gsmhr_vad.c
Normal file
File diff suppressed because it is too large
Load Diff
1331
src/libs/gsmhr/gsmhr_vad.cpp
Normal file
1331
src/libs/gsmhr/gsmhr_vad.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
src/libs/gsmhr/gsmhr_vad.h
Normal file
125
src/libs/gsmhr/gsmhr_vad.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#ifndef __VAD
|
||||
#define __VAD
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
|
||||
/*_________________________________________________________________________
|
||||
| |
|
||||
| Function Prototypes |
|
||||
|_________________________________________________________________________|
|
||||
*/
|
||||
|
||||
void vad_reset(void);
|
||||
|
||||
void vad_algorithm
|
||||
(
|
||||
int32_t pL_acf[9],
|
||||
int16_t swScaleAcf,
|
||||
int16_t pswRc[4],
|
||||
int16_t swPtch,
|
||||
int16_t *pswVadFlag
|
||||
);
|
||||
|
||||
void energy_computation
|
||||
(
|
||||
int32_t pL_acf[],
|
||||
int16_t swScaleAcf,
|
||||
int16_t pswRvad[],
|
||||
int16_t swNormRvad,
|
||||
int16_t *pswM_pvad,
|
||||
int16_t *pswE_pvad,
|
||||
int16_t *pswM_acf0,
|
||||
int16_t *pswE_acf0
|
||||
);
|
||||
|
||||
|
||||
void average_acf
|
||||
(
|
||||
int32_t pL_acf[],
|
||||
int16_t swScaleAcf,
|
||||
int32_t pL_av0[],
|
||||
int32_t pL_av1[]
|
||||
);
|
||||
|
||||
void predictor_values
|
||||
(
|
||||
int32_t pL_av1[],
|
||||
int16_t pswRav1[],
|
||||
int16_t *pswNormRav1
|
||||
);
|
||||
|
||||
void schur_recursion
|
||||
(
|
||||
int32_t pL_av1[],
|
||||
int16_t pswVpar[]
|
||||
);
|
||||
|
||||
void step_up
|
||||
(
|
||||
int16_t swNp,
|
||||
int16_t pswVpar[],
|
||||
int16_t pswAav1[]
|
||||
);
|
||||
|
||||
void compute_rav1
|
||||
(
|
||||
int16_t pswAav1[],
|
||||
int16_t pswRav1[],
|
||||
int16_t *pswNormRav1
|
||||
);
|
||||
|
||||
void spectral_comparison
|
||||
(
|
||||
int16_t pswRav1[],
|
||||
int16_t swNormRav1,
|
||||
int32_t pL_av0[],
|
||||
int16_t *pswStat
|
||||
);
|
||||
|
||||
void tone_detection
|
||||
(
|
||||
int16_t pswRc[4],
|
||||
int16_t *pswTone
|
||||
);
|
||||
|
||||
|
||||
void threshold_adaptation
|
||||
(
|
||||
int16_t swStat,
|
||||
int16_t swPtch,
|
||||
int16_t swTone,
|
||||
int16_t pswRav1[],
|
||||
int16_t swNormRav1,
|
||||
int16_t swM_pvad,
|
||||
int16_t swE_pvad,
|
||||
int16_t swM_acf0,
|
||||
int16_t swE_acf0,
|
||||
int16_t pswRvad[],
|
||||
int16_t *pswNormRvad,
|
||||
int16_t *pswM_thvad,
|
||||
int16_t *pswE_thvad
|
||||
);
|
||||
|
||||
void vad_decision
|
||||
(
|
||||
int16_t swM_pvad,
|
||||
int16_t swE_pvad,
|
||||
int16_t swM_thvad,
|
||||
int16_t swE_thvad,
|
||||
int16_t *pswVvad
|
||||
);
|
||||
|
||||
void vad_hangover
|
||||
(
|
||||
int16_t swVvad,
|
||||
int16_t *pswVadFlag
|
||||
);
|
||||
|
||||
void periodicity_update
|
||||
(
|
||||
int16_t pswLags[4],
|
||||
int16_t *pswPtch
|
||||
);
|
||||
|
||||
#endif
|
||||
35
src/libs/ice/CMakeLists.txt
Normal file
35
src/libs/ice/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
project (ice_stack)
|
||||
|
||||
# Rely on C++ 11
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set (ICE_STACK_SOURCES ICEAddress.cpp
|
||||
ICEAuthTransaction.cpp
|
||||
ICEBinding.cpp
|
||||
ICEBox.cpp
|
||||
ICEBoxImpl.cpp
|
||||
ICEByteBuffer.cpp
|
||||
ICECandidate.cpp
|
||||
ICECandidatePair.cpp
|
||||
ICECheckList.cpp
|
||||
ICECRC32.cpp
|
||||
ICEError.cpp
|
||||
ICELog.cpp
|
||||
ICEMD5.cpp
|
||||
ICENetworkHelper.cpp
|
||||
ICEPacketTimer.cpp
|
||||
ICEPlatform.cpp
|
||||
ICERelaying.cpp
|
||||
ICESession.cpp
|
||||
ICESHA1.cpp
|
||||
ICEStream.cpp
|
||||
ICEStunAttributes.cpp
|
||||
ICEStunConfig.cpp
|
||||
ICEStunMessage.cpp
|
||||
ICEStunTransaction.cpp
|
||||
ICESync.cpp
|
||||
ICETime.cpp
|
||||
ICETransactionList.cpp)
|
||||
|
||||
add_library(ice_stack ${ICE_STACK_SOURCES})
|
||||
42
src/libs/ice/ICEAction.h
Normal file
42
src/libs/ice/ICEAction.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_ACTION__H
|
||||
#define __ICE_ACTION__H
|
||||
|
||||
#include "ICESmartPtr.h"
|
||||
#include "ICECandidatePair.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class Transaction;
|
||||
struct Stream;
|
||||
class Logger;
|
||||
struct StackConfig;
|
||||
|
||||
class Action
|
||||
{
|
||||
protected:
|
||||
Stream& mStream;
|
||||
StackConfig& mConfig;
|
||||
|
||||
public:
|
||||
Action(Stream& stream, StackConfig& config)
|
||||
:mStream(stream), mConfig(config)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Action()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void finished(Transaction& transaction) = 0;
|
||||
};
|
||||
|
||||
typedef SmartPtr<Action> PAction;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
782
src/libs/ice/ICEAddress.cpp
Normal file
782
src/libs/ice/ICEAddress.cpp
Normal file
@@ -0,0 +1,782 @@
|
||||
/* Copyright(C) 2007-2018 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
# include <w32api.h>
|
||||
|
||||
# define WINVER WindowsVista
|
||||
# define _WIN32_WINDOWS WindowsVista
|
||||
# define _WIN32_WINNT WindowsVista
|
||||
#endif
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEAddress.h"
|
||||
#include "ICEError.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(TARGET_WIN)
|
||||
# include <WinSock2.h>
|
||||
# include <Windows.h>
|
||||
# include <ws2tcpip.h>
|
||||
#else
|
||||
# include <netinet/in.h>
|
||||
# if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
|
||||
# include <linux/in6.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
std::ostream& operator << (std::ostream& s, const ice::NetworkAddress& addr)
|
||||
{
|
||||
s << addr.toStdString().c_str();
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef TARGET_WIN
|
||||
std::wostream& operator << (std::wostream& s, const ice::NetworkAddress& addr)
|
||||
{
|
||||
s << addr.toStdWString();
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace ice;
|
||||
|
||||
NetworkAddress NetworkAddress::LoopbackAddress4("127.0.0.1", 1000);
|
||||
#ifdef TARGET_WIN
|
||||
static in_addr6 la6 = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 };
|
||||
#else
|
||||
static in6_addr la6 = { { { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 } } };
|
||||
#endif
|
||||
NetworkAddress NetworkAddress::LoopbackAddress6(la6, 1000);
|
||||
|
||||
|
||||
NetworkAddress NetworkAddress::parse(const std::string& s)
|
||||
{
|
||||
NetworkAddress result;
|
||||
result.mInitialized = !s.empty();
|
||||
if (result.mInitialized)
|
||||
{
|
||||
// Relayed or not
|
||||
result.mRelayed = s.find("relayed ") != std::string::npos;
|
||||
std::string::size_type ip4Pos = s.find("IPv4"), ip6Pos = s.find("IPv6");
|
||||
|
||||
if (ip4Pos == std::string::npos && ip6Pos == std::string::npos)
|
||||
{
|
||||
// Parse usual IP[:port] pair
|
||||
std::string::size_type cp = s.find(":");
|
||||
if (cp == std::string::npos)
|
||||
result.setIp(cp);
|
||||
else
|
||||
{
|
||||
result.setIp(s.substr(0, cp));
|
||||
result.setPort(atoi(s.substr(cp + 1).c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Family
|
||||
result.mAddr4.sin_family = ip4Pos != std::string::npos ? AF_INET : AF_INET6;
|
||||
|
||||
// IP:port
|
||||
std::string::size_type familyPos = ip4Pos != std::string::npos ? ip4Pos : ip6Pos;
|
||||
std::string addr = s.substr(familyPos + 5);
|
||||
|
||||
// Find IP substring and port
|
||||
std::string::size_type colonPos = addr.find_last_of(":");
|
||||
if (colonPos != std::string::npos)
|
||||
{
|
||||
int port = atoi(addr.substr(colonPos+1).c_str());
|
||||
result.setPort(port);
|
||||
result.setIp(addr.substr(0, colonPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NetworkAddress NetworkAddress::LoopbackAddress6("0:0:0:0:0:0:0:1", 1000);
|
||||
|
||||
NetworkAddress::NetworkAddress()
|
||||
:mInitialized(false), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
mAddr4.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(int stunType)
|
||||
:mInitialized(false), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
setStunType(stunType);
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const in6_addr& addr6, unsigned short port)
|
||||
:mInitialized(true), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
mAddr4.sin_family = AF_INET6;
|
||||
mAddr6.sin6_addr = addr6;
|
||||
mAddr6.sin6_port = htons(port);
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const in_addr& addr4, unsigned short port)
|
||||
:mInitialized(true), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
mAddr4.sin_family = AF_INET;
|
||||
mAddr4.sin_addr = addr4;
|
||||
mAddr4.sin_port = htons(port);
|
||||
}
|
||||
|
||||
unsigned char NetworkAddress::stunType() const
|
||||
{
|
||||
assert(mInitialized);
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return 1;
|
||||
|
||||
case AF_INET6:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void NetworkAddress::setStunType(unsigned char st)
|
||||
{
|
||||
switch (st)
|
||||
{
|
||||
case 1:
|
||||
mAddr4.sin_family = AF_INET;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
mAddr6.sin6_family = AF_INET6;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const std::string& ip, unsigned short port)
|
||||
:mInitialized(true), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
setIp(ip);
|
||||
if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6)
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const char *ip, unsigned short port)
|
||||
:mInitialized(true), mRelayed(false)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
setIp(ip);
|
||||
if (mAddr4.sin_family == AF_INET || mAddr4.sin_family == AF_INET6)
|
||||
setPort(port);
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const sockaddr& addr, unsigned addrLen)
|
||||
:mInitialized(true), mRelayed(false)
|
||||
{
|
||||
switch (addr.sa_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
memcpy(&mAddr6, &addr, addrLen);
|
||||
break;
|
||||
|
||||
case AF_INET:
|
||||
memset(&mAddr4, 0, sizeof(mAddr4));
|
||||
memcpy(&mAddr4, &addr, addrLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(const NetworkAddress& src)
|
||||
:mInitialized(src.mInitialized), mRelayed(src.mRelayed)
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
if (src.mAddr4.sin_family == AF_INET)
|
||||
memcpy(&mAddr4, &src.mAddr4, sizeof mAddr4);
|
||||
else
|
||||
memcpy(&mAddr6, &src.mAddr6, sizeof mAddr6);
|
||||
}
|
||||
|
||||
NetworkAddress::~NetworkAddress()
|
||||
{
|
||||
}
|
||||
|
||||
int NetworkAddress::family() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
|
||||
return this->mAddr4.sin_family;
|
||||
}
|
||||
|
||||
sockaddr* NetworkAddress::genericsockaddr() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return (sockaddr*)&mAddr4;
|
||||
|
||||
case AF_INET6:
|
||||
return (sockaddr*)&mAddr6;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned NetworkAddress::sockaddrLen() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(mAddr4);
|
||||
|
||||
case AF_INET6:
|
||||
return sizeof(mAddr6);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sockaddr_in* NetworkAddress::sockaddr4() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return (sockaddr_in*)&mAddr4;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sockaddr_in6* NetworkAddress::sockaddr6() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
return (sockaddr_in6*)&mAddr6;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NetworkAddress::setIp(NetworkAddress ipOnly)
|
||||
{
|
||||
// Save port
|
||||
mAddr4.sin_family = ipOnly.genericsockaddr()->sa_family;
|
||||
|
||||
switch (ipOnly.family())
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&mAddr4.sin_addr, &ipOnly.sockaddr4()->sin_addr, 4);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
memcpy(&mAddr4.sin_addr, &ipOnly.sockaddr6()->sin6_addr, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkAddress::setIp(const std::string& ip)
|
||||
{
|
||||
#ifdef TARGET_WIN
|
||||
int addrSize = sizeof(mAddr6);
|
||||
#endif
|
||||
|
||||
if (inet_addr(ip.c_str()) != INADDR_NONE)
|
||||
{
|
||||
mAddr4.sin_family = AF_INET;
|
||||
mAddr4.sin_addr.s_addr = inet_addr(ip.c_str());
|
||||
if (mAddr4.sin_port)
|
||||
mInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mAddr6.sin6_family = AF_INET6;
|
||||
#ifdef TARGET_WIN
|
||||
if (WSAStringToAddressA((char*)ip.c_str(), AF_INET6, NULL, (sockaddr*)&mAddr6, &addrSize) != 0)
|
||||
#else
|
||||
std::string ip2;
|
||||
if (ip.find('[') == 0 && ip.find(']') == ip.length()-1)
|
||||
ip2 = ip.substr(1, ip.length()-2);
|
||||
else
|
||||
ip2 = ip;
|
||||
|
||||
if (!inet_pton(AF_INET6, ip2.c_str(), &mAddr6.sin6_addr))
|
||||
#endif
|
||||
{
|
||||
mInitialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mAddr6.sin6_family = AF_INET6;
|
||||
if (mAddr6.sin6_port)
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NetworkAddress::setIp(unsigned long ip)
|
||||
{
|
||||
mAddr4.sin_family = AF_INET;
|
||||
mAddr4.sin_addr.s_addr = ip;
|
||||
|
||||
if (mAddr4.sin_port)
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
void NetworkAddress::setIp(const in_addr& ip)
|
||||
{
|
||||
//memset(&mAddr4, 0, sizeof mAddr4);
|
||||
mAddr4.sin_family = AF_INET;
|
||||
mAddr4.sin_addr = ip;
|
||||
}
|
||||
|
||||
void NetworkAddress::setIp(const in6_addr& ip)
|
||||
{
|
||||
mAddr6.sin6_family = AF_INET6;
|
||||
mAddr6.sin6_addr = ip;
|
||||
}
|
||||
// 10.0.0.0 - 10.255.255.255
|
||||
// 172.16.0.0 - 172.31.255.255
|
||||
// 192.168.0.0 - 192.168.255.255
|
||||
|
||||
bool NetworkAddress::isSameLAN(const NetworkAddress& a1, const NetworkAddress& a2)
|
||||
{
|
||||
if (a1.family() != a2.family())
|
||||
return false;
|
||||
if (a1.family() == AF_INET)
|
||||
{
|
||||
sockaddr_in* s1 = a1.sockaddr4();
|
||||
sockaddr_in* s2 = a2.sockaddr4();
|
||||
#ifdef TARGET_WIN
|
||||
unsigned b1_0 = (s1->sin_addr.S_un.S_addr >> 0) & 0xFF;
|
||||
unsigned b1_1 = (s1->sin_addr.S_un.S_addr >> 8) & 0xFF;
|
||||
unsigned b2_0 = (s2->sin_addr.S_un.S_addr >> 0) & 0xFF;
|
||||
unsigned b2_1 = (s2->sin_addr.S_un.S_addr >> 8) & 0xFF;
|
||||
#else
|
||||
unsigned b1_0 = (s1->sin_addr.s_addr >> 0) & 0xFF;
|
||||
unsigned b1_1 = (s1->sin_addr.s_addr >> 8) & 0xFF;
|
||||
unsigned b2_0 = (s2->sin_addr.s_addr >> 0) & 0xFF;
|
||||
unsigned b2_1 = (s2->sin_addr.s_addr >> 8) & 0xFF;
|
||||
|
||||
if (b1_0 == b2_0 && b1_0 == 192 &&
|
||||
b1_1 == b2_1 && b1_1 == 168)
|
||||
return true;
|
||||
|
||||
if (b1_0 == b2_0 && b1_0 == 10)
|
||||
return true;
|
||||
|
||||
if (b1_0 == b2_0 && b1_0 == 172 &&
|
||||
b1_1 == b2_1 && (b1_1 < 32))
|
||||
return true;
|
||||
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkAddress::setPort(unsigned short port)
|
||||
{
|
||||
switch(mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
mAddr4.sin_port = htons(port);
|
||||
mInitialized = true;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
mAddr6.sin6_port = htons(port);
|
||||
mInitialized = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::string NetworkAddress::ip() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
|
||||
char resultbuf[128], ip6[128]; resultbuf[0] = 0;
|
||||
|
||||
#ifdef TARGET_WIN
|
||||
DWORD resultsize = sizeof(resultbuf);
|
||||
#endif
|
||||
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return inet_ntoa(mAddr4.sin_addr);
|
||||
|
||||
case AF_INET6:
|
||||
#if defined(TARGET_WIN)
|
||||
InetNtopA(AF_INET6, (PVOID)&mAddr6.sin6_addr, resultbuf, sizeof(resultbuf));
|
||||
#else
|
||||
inet_ntop(AF_INET6, &mAddr6.sin6_addr, resultbuf, sizeof(resultbuf));
|
||||
#endif
|
||||
sprintf(ip6, "[%s]", resultbuf);
|
||||
return ip6;
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned char* NetworkAddress::ipBytes() const
|
||||
{
|
||||
switch (family())
|
||||
{
|
||||
case AF_INET:
|
||||
#ifdef TARGET_WIN
|
||||
return (unsigned char*)&mAddr4.sin_addr.S_un.S_un_b;
|
||||
#else
|
||||
return (unsigned char*)&mAddr4.sin_addr.s_addr;
|
||||
#endif
|
||||
case AF_INET6:
|
||||
#ifdef TARGET_WIN
|
||||
return (unsigned char*)mAddr6.sin6_addr.u.Byte;
|
||||
#elif defined(TARGET_OSX) || defined(TARGET_IOS)
|
||||
return (unsigned char*)&mAddr6.sin6_addr.__u6_addr.__u6_addr8;
|
||||
#elif defined(TARGET_LINUX)
|
||||
return (unsigned char*)&mAddr6.sin6_addr.__in6_u.__u6_addr8;
|
||||
#elif defined(TARGET_ANDROID)
|
||||
return (unsigned char*)&mAddr6.sin6_addr.in6_u.u6_addr8;
|
||||
#endif
|
||||
}
|
||||
assert(0);
|
||||
return nullptr; // to avoid compiler warning
|
||||
}
|
||||
|
||||
unsigned short NetworkAddress::port() const
|
||||
{
|
||||
assert(mInitialized == true);
|
||||
|
||||
return ntohs(mAddr4.sin_port);
|
||||
}
|
||||
|
||||
std::string NetworkAddress::toStdString() const
|
||||
{
|
||||
if (!mInitialized)
|
||||
return "";
|
||||
|
||||
char temp[128];
|
||||
sprintf(temp, "%s%s %s:%u", mRelayed ? "relayed " : "", this->mAddr4.sin_family == AF_INET ? "IPv4" : "IPv6", ip().c_str(), (unsigned int)port());
|
||||
|
||||
return temp;
|
||||
}
|
||||
#ifdef WIN32
|
||||
std::wstring NetworkAddress::toStdWString() const
|
||||
{
|
||||
if (!mInitialized)
|
||||
return L"";
|
||||
|
||||
wchar_t temp[128];
|
||||
swprintf(temp, L"%s%s %S:%u", mRelayed ? L"relayed " : L"", this->mAddr4.sin_family == AF_INET ? L"IPv4" : L"IPv6", ip().c_str(), (unsigned int)port());
|
||||
|
||||
return temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const unsigned char localhost6[] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
|
||||
bool NetworkAddress::isLoopback() const
|
||||
{
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return (mAddr4.sin_addr.s_addr == htonl(INADDR_LOOPBACK));
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(localhost6, &mAddr6.sin6_addr, sizeof mAddr6.sin6_addr) == 0;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isIp(const std::string& str)
|
||||
{
|
||||
if (inet_addr(str.c_str()) != INADDR_NONE)
|
||||
return true;
|
||||
const char* address = str.c_str();
|
||||
std::string temp;
|
||||
if (str.find('[') == 0 && str.find(']') == str.length()-1)
|
||||
{
|
||||
temp = str.substr(1, str.length()-2);
|
||||
address = temp.c_str();
|
||||
}
|
||||
sockaddr_in6 addr6;
|
||||
addr6.sin6_family = AF_INET6;
|
||||
|
||||
#ifdef _WIN32
|
||||
int addrSize = sizeof(addr6);
|
||||
if (WSAStringToAddressA((char*)address, AF_INET6, NULL, (sockaddr*)&addr6, &addrSize) != 0)
|
||||
#else
|
||||
if (!inet_pton(AF_INET6, address, &addr6))
|
||||
#endif
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isLAN() const
|
||||
{
|
||||
assert(mInitialized);
|
||||
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
unsigned char b1 = mAddr4.sin_addr.s_addr & 0xFF;
|
||||
unsigned char b2 = (mAddr4.sin_addr.s_addr >> 8) & 0xFF;
|
||||
if (b1 == 192 && b2 == 168)
|
||||
return true;
|
||||
if (b1 == 10)
|
||||
return true;
|
||||
if (b1 == 172 && (b2 >= 16 && b2 <= 31))
|
||||
return true;
|
||||
|
||||
// Link local addresses are not routable so report them here
|
||||
if (b1 == 169 && b2 == 254)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
return false;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isLinkLocal() const
|
||||
{
|
||||
assert(mInitialized);
|
||||
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
unsigned char b1 = mAddr4.sin_addr.s_addr & 0xFF;
|
||||
unsigned char b2 = (mAddr4.sin_addr.s_addr >> 8) & 0xFF;
|
||||
|
||||
// Link local addresses are not routable so report them here
|
||||
if (b1 == 169 && b2 == 254)
|
||||
return true;
|
||||
|
||||
//if (b1 == 100 && (b2 >= 64 && b2 <= 127))
|
||||
// return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
#ifdef WIN32
|
||||
return (mAddr6.sin6_addr.u.Byte[0] == 0xFE && mAddr6.sin6_addr.u.Byte[1] == 0x80);
|
||||
#else
|
||||
return IN6_IS_ADDR_LINKLOCAL(&mAddr6.sin6_addr);
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkAddress::clear()
|
||||
{
|
||||
memset(&mAddr6, 0, sizeof(mAddr6));
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isEmpty() const
|
||||
{
|
||||
return !mInitialized;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isZero() const
|
||||
{
|
||||
if (!mInitialized)
|
||||
return false;
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return mAddr4.sin_addr.s_addr == 0;
|
||||
|
||||
case AF_INET6:
|
||||
#ifdef WIN32
|
||||
return !mAddr6.sin6_addr.u.Word[0] && !mAddr6.sin6_addr.u.Word[1] &&
|
||||
!mAddr6.sin6_addr.u.Word[2] && !mAddr6.sin6_addr.u.Word[3] &&
|
||||
!mAddr6.sin6_addr.u.Word[4] && !mAddr6.sin6_addr.u.Word[5] &&
|
||||
!mAddr6.sin6_addr.u.Word[6] && !mAddr6.sin6_addr.u.Word[7];
|
||||
#else
|
||||
return IN6_IS_ADDR_UNSPECIFIED(&mAddr6.sin6_addr);
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isV4() const
|
||||
{
|
||||
return family() == AF_INET;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isV6() const
|
||||
{
|
||||
return family() == AF_INET6;
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator == (const NetworkAddress& rhs) const
|
||||
{
|
||||
return NetworkAddress::isSame(*this, rhs);
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator != (const NetworkAddress& rhs) const
|
||||
{
|
||||
return !NetworkAddress::isSame(*this, rhs);
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator < (const NetworkAddress& rhs) const
|
||||
{
|
||||
if (family() != rhs.family())
|
||||
return family() < rhs.family();
|
||||
|
||||
if (port() != rhs.port())
|
||||
return port() < rhs.port();
|
||||
|
||||
switch (family())
|
||||
{
|
||||
case AF_INET:
|
||||
return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) < 0;
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) < 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator > (const NetworkAddress& rhs) const
|
||||
{
|
||||
if (family() != rhs.family())
|
||||
return family() > rhs.family();
|
||||
|
||||
if (port() != rhs.port())
|
||||
return port() > rhs.port();
|
||||
|
||||
switch (family())
|
||||
{
|
||||
case AF_INET:
|
||||
return memcmp(sockaddr4(), rhs.sockaddr4(), sizeof(sockaddr_in)) > 0;
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(sockaddr6(), rhs.sockaddr6(), sizeof(sockaddr_in6)) > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isPublic() const
|
||||
{
|
||||
return !isLAN() && !isLinkLocal() && !isLoopback() && !isEmpty();
|
||||
}
|
||||
|
||||
void NetworkAddress::setRelayed(bool relayed)
|
||||
{
|
||||
mRelayed = relayed;
|
||||
}
|
||||
bool NetworkAddress::relayed() const
|
||||
{
|
||||
return mRelayed;
|
||||
}
|
||||
|
||||
bool NetworkAddress::hasHost(const std::vector<NetworkAddress>& hosts)
|
||||
{
|
||||
for (unsigned i=0; i<hosts.size(); i++)
|
||||
{
|
||||
const NetworkAddress& a = hosts[i];
|
||||
if (mAddr4.sin_family != a.mAddr4.sin_family)
|
||||
continue;
|
||||
|
||||
switch (mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
if (!memcmp(&mAddr4.sin_addr, &a.mAddr4.sin_addr, sizeof(mAddr4.sin_addr)))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if (!memcmp(&mAddr6.sin6_addr, &a.mAddr6.sin6_addr, sizeof(mAddr6.sin6_addr)))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkAddress::isSameHost(const NetworkAddress& a1, const NetworkAddress& a2)
|
||||
{
|
||||
return (a1.ip() == a2.ip());
|
||||
}
|
||||
|
||||
bool NetworkAddress::isSame(const NetworkAddress& a1, const NetworkAddress& a2)
|
||||
{
|
||||
if (!a1.mInitialized || !a2.mInitialized)
|
||||
return false;
|
||||
|
||||
// Compare address families
|
||||
if (a1.mAddr4.sin_family != a2.mAddr4.sin_family)
|
||||
return false;
|
||||
|
||||
if (a1.mRelayed != a2.mRelayed)
|
||||
return false;
|
||||
|
||||
switch (a1.mAddr4.sin_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return a1.mAddr4.sin_addr.s_addr == a2.mAddr4.sin_addr.s_addr && a1.mAddr4.sin_port == a2.mAddr4.sin_port;
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(&a1.mAddr6.sin6_addr, &a2.mAddr6.sin6_addr, sizeof(a1.mAddr6.sin6_addr)) == 0 &&
|
||||
a1.mAddr6.sin6_port == a2.mAddr6.sin6_port;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
100
src/libs/ice/ICEAddress.h
Normal file
100
src/libs/ice/ICEAddress.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Copyright(C) 2007-2018 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_ADDRESS_H
|
||||
#define __ICE_ADDRESS_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class NetworkAddress
|
||||
{
|
||||
public:
|
||||
static NetworkAddress LoopbackAddress4;
|
||||
static NetworkAddress LoopbackAddress6;
|
||||
static bool isSameLAN(const NetworkAddress& a1, const NetworkAddress& a2);
|
||||
static bool isIp(const std::string& str);
|
||||
static NetworkAddress parse(const std::string& s);
|
||||
|
||||
NetworkAddress();
|
||||
NetworkAddress(int stunType);
|
||||
NetworkAddress(const std::string& ip, unsigned short port);
|
||||
NetworkAddress(const char* ip, unsigned short port);
|
||||
NetworkAddress(const in6_addr& ip, unsigned short port);
|
||||
NetworkAddress(const in_addr& ip, unsigned short port);
|
||||
NetworkAddress(const sockaddr& addr, unsigned addrLen);
|
||||
NetworkAddress(const NetworkAddress& src);
|
||||
~NetworkAddress();
|
||||
|
||||
// Returns AF_INET or AF_INET6
|
||||
int family() const;
|
||||
|
||||
unsigned char stunType() const;
|
||||
void setStunType(unsigned char st);
|
||||
|
||||
sockaddr* genericsockaddr() const;
|
||||
sockaddr_in* sockaddr4() const;
|
||||
sockaddr_in6* sockaddr6() const;
|
||||
unsigned sockaddrLen() const;
|
||||
void setIp(const std::string& ip);
|
||||
void setIp(unsigned long ip);
|
||||
void setIp(const in_addr& ip);
|
||||
void setIp(const in6_addr& ip);
|
||||
void setIp(NetworkAddress ipOnly);
|
||||
|
||||
void setPort(unsigned short port);
|
||||
std::string ip() const;
|
||||
unsigned char* ipBytes() const;
|
||||
|
||||
unsigned short port() const;
|
||||
std::string toStdString() const;
|
||||
#ifdef WIN32
|
||||
std::wstring toStdWString() const;
|
||||
#endif
|
||||
bool isLoopback() const;
|
||||
bool isLAN() const;
|
||||
bool isLinkLocal() const;
|
||||
bool isPublic() const;
|
||||
bool isEmpty() const;
|
||||
bool isZero() const;
|
||||
bool isV4() const;
|
||||
bool isV6() const;
|
||||
|
||||
void clear();
|
||||
|
||||
void setRelayed(bool relayed);
|
||||
bool relayed() const;
|
||||
bool hasHost(const std::vector<NetworkAddress>& hosts);
|
||||
|
||||
static bool isSameHost(const NetworkAddress& a1, const NetworkAddress& a2);
|
||||
|
||||
static bool isSame(const NetworkAddress& a1, const NetworkAddress& a2);
|
||||
|
||||
bool operator == (const NetworkAddress& rhs) const;
|
||||
bool operator != (const NetworkAddress& rhs) const;
|
||||
bool operator < (const NetworkAddress& rhs) const;
|
||||
bool operator > (const NetworkAddress& rhs) const;
|
||||
protected:
|
||||
union
|
||||
{
|
||||
sockaddr_in6 mAddr6;
|
||||
sockaddr_in mAddr4;
|
||||
};
|
||||
bool mRelayed;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& s, const ice::NetworkAddress& addr);
|
||||
#ifdef WIN32
|
||||
std::wostream& operator << (std::wostream& s, const ice::NetworkAddress& addr);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
251
src/libs/ice/ICEAuthTransaction.cpp
Normal file
251
src/libs/ice/ICEAuthTransaction.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEAuthTransaction.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICEMD5.h"
|
||||
#include "ICELog.h"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
AuthTransaction::AuthTransaction()
|
||||
:Transaction(), mActive(false), mComposed(false), mConformsToKeepaliveSchedule(true),
|
||||
mCredentialsEncoded(false)
|
||||
{
|
||||
}
|
||||
|
||||
AuthTransaction::~AuthTransaction()
|
||||
{
|
||||
}
|
||||
|
||||
void AuthTransaction::init()
|
||||
{
|
||||
mConformsToKeepaliveSchedule = false;
|
||||
if (mRealm.size() && mNonce.size())
|
||||
buildAuthenticatedMsg();
|
||||
else
|
||||
{
|
||||
SmartPtr<StunMessage> msg(new StunMessage());
|
||||
msg->setTransactionId(mTransactionID);
|
||||
setInitialRequest(*msg);
|
||||
mComposed = false;
|
||||
mOutgoingMsgQueue.push_back(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void AuthTransaction::buildAuthenticatedMsg()
|
||||
{
|
||||
// Setup key for MessageIntegrity
|
||||
std::string key = mUsername + ":" + mRealm + ":" + mPassword;
|
||||
md5Bin(key.c_str(), key.size(), mKey);
|
||||
|
||||
// Create new authenticated message
|
||||
SmartPtr<StunMessage> newMsg( new StunMessage() );
|
||||
|
||||
// Optional - generate new transaction ID
|
||||
// mTransactionID = StunMessage::TransactionID::GenerateNew();
|
||||
|
||||
newMsg->setTransactionId( mTransactionID );
|
||||
|
||||
// Add USERNAME
|
||||
newMsg->usernameAttr().setValue( mUsername );
|
||||
newMsg->realmAttr().setValue( mRealm );
|
||||
newMsg->nonceAttr().setValue( mNonce );
|
||||
|
||||
// Adjust message
|
||||
setAuthenticatedRequest( *newMsg );
|
||||
|
||||
// Ensure MessageIntegrity exists
|
||||
newMsg->messageIntegrityAttr().setValue( NULL );
|
||||
|
||||
// Enqueue msg
|
||||
mComposed = false;
|
||||
|
||||
mOutgoingMsgQueue.clear();
|
||||
mOutgoingMsgQueue.push_back( newMsg );
|
||||
}
|
||||
|
||||
bool AuthTransaction::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
if (msg.transactionId() != mTransactionID)
|
||||
return false;
|
||||
|
||||
// Check for 401 error code
|
||||
if (msg.hasAttribute(StunAttribute::ErrorCode))
|
||||
{
|
||||
ErrorCode& ec = msg.errorCodeAttr();
|
||||
|
||||
// Get realm value - it must be long term credentials
|
||||
if (ec.errorCode() == 401 && (!mCredentialsEncoded || !mLongTerm))
|
||||
{
|
||||
if (!msg.hasAttribute(StunAttribute::Realm) || !msg.hasAttribute(StunAttribute::Nonce))
|
||||
return false;
|
||||
|
||||
Realm& realm = msg.realmAttr();
|
||||
|
||||
// Extract realm and nonce
|
||||
mRealm = realm.value();
|
||||
mNonce = msg.nonceAttr().value();
|
||||
|
||||
// Change transaction id
|
||||
if (mLongTerm)
|
||||
{
|
||||
mCredentialsEncoded = true;
|
||||
generateId();
|
||||
}
|
||||
ICELogDebug(<< "Server requested long term credentials for realm " << mRealm);
|
||||
buildAuthenticatedMsg();
|
||||
}
|
||||
else
|
||||
if (ec.errorCode() == 438 && (msg.hasAttribute(StunAttribute::Realm) || msg.hasAttribute(StunAttribute::Nonce)))
|
||||
{
|
||||
if (msg.hasAttribute(StunAttribute::Realm))
|
||||
mRealm = msg.realmAttr().value();
|
||||
if (msg.hasAttribute(StunAttribute::Nonce))
|
||||
mNonce = msg.nonceAttr().value();
|
||||
|
||||
ICELogDebug(<< "Returned error 438, using new nonce");
|
||||
if (msg.hasAttribute(StunAttribute::Realm) && msg.hasAttribute(StunAttribute::Nonce))
|
||||
{
|
||||
if (mLongTerm)
|
||||
{
|
||||
mCredentialsEncoded = true;
|
||||
generateId();
|
||||
}
|
||||
}
|
||||
buildAuthenticatedMsg();
|
||||
}
|
||||
else
|
||||
{
|
||||
mErrorCode = ec.errorCode();
|
||||
mErrorResponse = ec.errorPhrase();
|
||||
mState = Transaction::Failed;
|
||||
processError();
|
||||
|
||||
ICELogCritical(<<"Stack ID " << mStackID << ". Got error code " << mErrorCode << " for STUN transaction. Error message: " << ec.errorPhrase());
|
||||
}
|
||||
}
|
||||
else
|
||||
if (msg.messageClass() == StunMessage::ErrorClass)
|
||||
{
|
||||
mErrorCode = 0;
|
||||
mState = Transaction::Failed;
|
||||
processError();
|
||||
ICELogCritical(<<"Stack ID " << mStackID << ". Got ErrorClass response.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ICELogDebug(<< "Process STUN success message");
|
||||
processSuccessMessage(msg, address);
|
||||
mState = Transaction::Success;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteBuffer* AuthTransaction::generateData(bool force)
|
||||
{
|
||||
if (!mActive)
|
||||
{
|
||||
init();
|
||||
mActive = true;
|
||||
}
|
||||
|
||||
if (!mComposed)
|
||||
{
|
||||
// Restart retransmission timer as new message will be built
|
||||
mRTOTimer.stop();
|
||||
mRTOTimer.start();
|
||||
|
||||
// Get message from outgoing queue
|
||||
if (!mOutgoingMsgQueue.empty())
|
||||
{
|
||||
// Clear buffer for raw data
|
||||
mOutgoingData.clear();
|
||||
|
||||
// Encode next message
|
||||
StunMessage& msg = *mOutgoingMsgQueue.front();
|
||||
|
||||
//ICELogDebug(<< "Stack ID " << mStackID << ". Build message " << msg.GetTransactionID().ToString() << " from transaction " << this->GetComment());
|
||||
|
||||
if (mShortTerm)
|
||||
msg.buildPacket(mOutgoingData, mPassword);
|
||||
else
|
||||
msg.buildPacket(mOutgoingData, std::string((char*)mKey, 16));
|
||||
|
||||
// Remove encoded message from msg queue
|
||||
mOutgoingMsgQueue.pop_front();
|
||||
}
|
||||
else
|
||||
ICELogDebug(<< "No outgoing message in queue");
|
||||
|
||||
mComposed = true;
|
||||
}
|
||||
|
||||
return Transaction::generateData(force);
|
||||
}
|
||||
|
||||
int AuthTransaction::errorCode()
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
std::string AuthTransaction::errorResponse()
|
||||
{
|
||||
return mErrorResponse;
|
||||
}
|
||||
|
||||
void AuthTransaction::restart()
|
||||
{
|
||||
// Clear outgoing data
|
||||
mOutgoingData.clear();
|
||||
mOutgoingMsgQueue.clear();
|
||||
|
||||
mState = Transaction::Running;
|
||||
|
||||
// Mark "message is not built yet"
|
||||
mComposed = false;
|
||||
|
||||
// Mark "first request is not sent yet"
|
||||
mActive = false;
|
||||
|
||||
// Reset retransmission timer
|
||||
mRTOTimer.stop();
|
||||
mRTOTimer.start();
|
||||
mCredentialsEncoded = false;
|
||||
mConformsToKeepaliveSchedule = true;
|
||||
}
|
||||
|
||||
bool AuthTransaction::hasToRunNow()
|
||||
{
|
||||
bool result = Transaction::hasToRunNow();
|
||||
if (!result && keepalive())
|
||||
{
|
||||
result |= mState == /*TransactionState::*/Running && !mConformsToKeepaliveSchedule;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string AuthTransaction::realm() const
|
||||
{
|
||||
return mRealm;
|
||||
}
|
||||
|
||||
void AuthTransaction::setRealm(std::string realm)
|
||||
{
|
||||
mRealm = realm;
|
||||
}
|
||||
|
||||
std::string AuthTransaction::nonce() const
|
||||
{
|
||||
return mNonce;
|
||||
}
|
||||
|
||||
void AuthTransaction::setNonce(std::string nonce)
|
||||
{
|
||||
mNonce = nonce;
|
||||
}
|
||||
59
src/libs/ice/ICEAuthTransaction.h
Normal file
59
src/libs/ice/ICEAuthTransaction.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __AUTH_TRANSACTION_H
|
||||
#define __AUTH_TRANSACTION_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEStunTransaction.h"
|
||||
|
||||
namespace ice {
|
||||
|
||||
class AuthTransaction: public Transaction
|
||||
{
|
||||
public:
|
||||
AuthTransaction();
|
||||
virtual ~AuthTransaction();
|
||||
|
||||
// Creates initial request, calls SetInitialRequest. This method is called once from GenerateData.
|
||||
void init();
|
||||
|
||||
virtual void setInitialRequest(StunMessage& msg) = 0;
|
||||
virtual void setAuthenticatedRequest(StunMessage& msg) = 0;
|
||||
virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) = 0;
|
||||
virtual void processError() {};
|
||||
|
||||
virtual bool processData(StunMessage& msg, NetworkAddress& address);
|
||||
virtual ByteBuffer* generateData(bool force = false);
|
||||
|
||||
int errorCode();
|
||||
std::string errorResponse();
|
||||
virtual void restart();
|
||||
virtual bool hasToRunNow();
|
||||
|
||||
std::string realm() const;
|
||||
void setRealm(std::string realm);
|
||||
|
||||
std::string nonce() const;
|
||||
void setNonce(std::string nonce);
|
||||
|
||||
protected:
|
||||
bool mActive;
|
||||
bool mComposed;
|
||||
int mErrorCode;
|
||||
std::string mErrorResponse;
|
||||
std::deque<SmartPtr<StunMessage> > mOutgoingMsgQueue;
|
||||
unsigned char mKey[16];
|
||||
bool mConformsToKeepaliveSchedule;
|
||||
std::string mRealm;
|
||||
std::string mNonce;
|
||||
bool mCredentialsEncoded;
|
||||
|
||||
void buildAuthenticatedMsg();
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif
|
||||
520
src/libs/ice/ICEBinding.cpp
Normal file
520
src/libs/ice/ICEBinding.cpp
Normal file
@@ -0,0 +1,520 @@
|
||||
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEBinding.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICETime.h"
|
||||
#include "ICELog.h"
|
||||
#include <memory>
|
||||
|
||||
using namespace ice;
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
//----------------------- AuthClientBinding -----------------
|
||||
|
||||
ConnectivityCheck::ConnectivityCheck()
|
||||
{
|
||||
setComment("ConnectivityCheck");
|
||||
mErrorCode = 0;
|
||||
}
|
||||
|
||||
ConnectivityCheck::~ConnectivityCheck()
|
||||
{
|
||||
}
|
||||
|
||||
ByteBuffer* ConnectivityCheck::generateData(bool force)
|
||||
{
|
||||
if (!mComposed)
|
||||
{
|
||||
StunMessage msg;
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.setMessageType(StunMessage::Binding);
|
||||
msg.setTransactionId(mTransactionID);
|
||||
|
||||
if (mUseCandidate)
|
||||
msg.setAttribute(new ICEUseCandidate());
|
||||
|
||||
// Use message integrity attribute
|
||||
mMessageIntegrity = true;
|
||||
|
||||
// Use fingerprint attribute
|
||||
mFingerprint = true;
|
||||
|
||||
if (mEnablePriority)
|
||||
msg.icePriorityAttr().setPriority(mPriority);
|
||||
|
||||
// Copy comment to message object
|
||||
msg.setComment(mComment);
|
||||
|
||||
enqueueMessage(msg);
|
||||
|
||||
mComposed = true;
|
||||
}
|
||||
|
||||
return Transaction::generateData(force);
|
||||
}
|
||||
|
||||
void ConnectivityCheck::confirmTransaction(NetworkAddress& mapped)
|
||||
{
|
||||
// Save resolved address&ip
|
||||
mMappedAddress = mapped;
|
||||
|
||||
// Mark transaction as succeeded
|
||||
mState = Transaction::Success;
|
||||
|
||||
// Save source IP and port
|
||||
mResponseAddress = mapped;
|
||||
}
|
||||
|
||||
bool ConnectivityCheck::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
#ifdef ICE_TEST_VERYAGGRESSIVE
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Check if it is response
|
||||
if (msg.messageClass() != StunMessage::ErrorClass &&
|
||||
msg.messageClass() != StunMessage::SuccessClass)
|
||||
return false;
|
||||
|
||||
if (msg.transactionId() != mTransactionID)
|
||||
return false;
|
||||
|
||||
// Validate againgst password used to encrypt
|
||||
if (!msg.validatePacket(mPassword))
|
||||
return false;
|
||||
|
||||
// Check for ErrorCode attribute
|
||||
if (msg.hasAttribute(StunAttribute::ErrorCode))
|
||||
{
|
||||
ErrorCode& ec = dynamic_cast<ErrorCode&>(msg.attribute(StunAttribute::ErrorCode));
|
||||
|
||||
//save error code and response
|
||||
mErrorCode = ec.errorCode();
|
||||
mErrorResponse = ec.errorPhrase();
|
||||
|
||||
//mark transaction as failed
|
||||
mState = Transaction::Failed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//check if received empty ErrorClass response for poor servers
|
||||
if (msg.messageClass() == StunMessage::ErrorClass)
|
||||
{
|
||||
//mark transaction as failed
|
||||
mState = Transaction::Failed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//check for mapped address attribute
|
||||
if (msg.hasAttribute(StunAttribute::MappedAddress))
|
||||
{
|
||||
// Save resolved address&ip
|
||||
mMappedAddress = msg.mappedAddressAttr().address();
|
||||
|
||||
// Mark transaction as succeeded
|
||||
mState = Transaction::Success;
|
||||
|
||||
// Save source IP and port
|
||||
mResponseAddress = address;
|
||||
}
|
||||
|
||||
//check for xor'ed mapped address attribute
|
||||
if (msg.hasAttribute(StunAttribute::XorMappedAddress))
|
||||
{
|
||||
// Save resolved IP and port
|
||||
mMappedAddress = msg.xorMappedAddressAttr().address();
|
||||
|
||||
// Mark transaction as succeeded
|
||||
mState = Transaction::Success;
|
||||
|
||||
// Save source IP and port
|
||||
mResponseAddress = address;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NetworkAddress& ConnectivityCheck::mappedAddress()
|
||||
{
|
||||
return mMappedAddress;
|
||||
}
|
||||
NetworkAddress& ConnectivityCheck::responseAddress()
|
||||
{
|
||||
return mResponseAddress;
|
||||
}
|
||||
void ConnectivityCheck::addUseCandidate()
|
||||
{
|
||||
mUseCandidate = true;
|
||||
}
|
||||
int ConnectivityCheck::errorCode()
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
int ConnectivityCheck::resultError()
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
NetworkAddress& ConnectivityCheck::resultSource()
|
||||
{
|
||||
return mResponseAddress;
|
||||
}
|
||||
Transaction::State ConnectivityCheck::resultState()
|
||||
{
|
||||
return state();
|
||||
}
|
||||
NetworkAddress& ConnectivityCheck::resultLocal()
|
||||
{
|
||||
return mMappedAddress;
|
||||
}
|
||||
void ConnectivityCheck::useCandidate()
|
||||
{
|
||||
addUseCandidate();
|
||||
}
|
||||
unsigned ConnectivityCheck::resultPriority()
|
||||
{
|
||||
return priorityValue();
|
||||
}
|
||||
//---------------------------- ClientBindingTransaction ----------------------------
|
||||
|
||||
ClientBinding::ClientBinding()
|
||||
:Transaction(), mErrorCode(0), mUseCandidate(false)
|
||||
{
|
||||
setComment("ClientBinding");
|
||||
}
|
||||
|
||||
ClientBinding::~ClientBinding()
|
||||
{
|
||||
}
|
||||
|
||||
int ClientBinding::errorCode()
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
std::string ClientBinding::errorResponse()
|
||||
{
|
||||
return mErrorResponse;
|
||||
}
|
||||
|
||||
NetworkAddress& ClientBinding::mappedAddress()
|
||||
{
|
||||
return mMappedAddress;
|
||||
}
|
||||
|
||||
NetworkAddress& ClientBinding::responseAddress()
|
||||
{
|
||||
return mResponseAddress;
|
||||
}
|
||||
|
||||
bool ClientBinding::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
// Check if it is response
|
||||
if (msg.messageClass() != StunMessage::ErrorClass &&
|
||||
msg.messageClass() != StunMessage::SuccessClass)
|
||||
return false;
|
||||
|
||||
if (msg.transactionId() != this->mTransactionID)
|
||||
return false;
|
||||
|
||||
// Check for ErrorCode attribute
|
||||
if (msg.hasAttribute(StunAttribute::ErrorCode))
|
||||
{
|
||||
// Save error code and response
|
||||
mErrorCode = msg.errorCodeAttr().errorCode();
|
||||
mErrorResponse = msg.errorCodeAttr().errorPhrase();
|
||||
|
||||
// Mark transaction as failed
|
||||
mState = Transaction::Failed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if received empty ErrorClass response for poor servers
|
||||
if (msg.messageClass() == StunMessage::ErrorClass)
|
||||
{
|
||||
// Mark transaction as failed
|
||||
mState = Transaction::Failed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for mapped address attribute
|
||||
if (msg.hasAttribute(StunAttribute::MappedAddress))
|
||||
{
|
||||
// Save resolved address&ip
|
||||
mMappedAddress = msg.mappedAddressAttr().address();
|
||||
|
||||
// mMark transaction as succeeded
|
||||
mState = Transaction::Success;
|
||||
|
||||
// Save source IP and port
|
||||
mResponseAddress = address;
|
||||
}
|
||||
|
||||
//check for xor'ed mapped address attribute
|
||||
if (msg.hasAttribute(StunAttribute::XorMappedAddress))
|
||||
{
|
||||
// Save resolved IP and port
|
||||
mMappedAddress = msg.xorMappedAddressAttr().address();
|
||||
|
||||
// Mark transaction as succeeded
|
||||
mState = Transaction::Success;
|
||||
|
||||
// Save source IP and port
|
||||
mResponseAddress = address;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteBuffer* ClientBinding::generateData(bool force)
|
||||
{
|
||||
if (!mComposed)
|
||||
{
|
||||
StunMessage msg;
|
||||
msg.setMessageType(ice::StunMessage::Binding);
|
||||
msg.setMessageClass(ice::StunMessage::RequestClass);
|
||||
msg.setTransactionId(mTransactionID);
|
||||
|
||||
if (mUseCandidate)
|
||||
msg.setAttribute(new ICEUseCandidate());
|
||||
|
||||
// Copy comment to message object
|
||||
msg.setComment(mComment);
|
||||
|
||||
enqueueMessage(msg);
|
||||
|
||||
mComposed = true;
|
||||
}
|
||||
|
||||
return Transaction::generateData(force);
|
||||
}
|
||||
|
||||
void ClientBinding::addUseCandidate()
|
||||
{
|
||||
mUseCandidate = true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------ ServerBindingTransaction ---------------------------
|
||||
ServerBinding::ServerBinding()
|
||||
{
|
||||
setComment("ServerBinding");
|
||||
|
||||
mGenerate400 = false;
|
||||
mGenerate487 = false;
|
||||
mRole = 0;
|
||||
}
|
||||
|
||||
ServerBinding::~ServerBinding()
|
||||
{
|
||||
}
|
||||
void ServerBinding::setLocalTieBreaker(std::string tieBreaker)
|
||||
{
|
||||
mLocalTieBreaker = tieBreaker;
|
||||
}
|
||||
|
||||
bool ServerBinding::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
if (msg.messageType() != StunMessage::Binding || msg.messageClass() != StunMessage::RequestClass)
|
||||
return false;
|
||||
ICELogDebug(<< "Received Binding request from " << address.toStdString().c_str());
|
||||
|
||||
// Save visible address
|
||||
mSourceAddress = address;
|
||||
|
||||
// Save transaction ID
|
||||
mTransactionID = msg.transactionId();
|
||||
|
||||
// Save Priority value
|
||||
if (msg.hasAttribute(StunAttribute::ICEPriority))
|
||||
{
|
||||
mEnablePriority = true;
|
||||
mPriority = msg.icePriorityAttr().priority();
|
||||
}
|
||||
|
||||
// Save UseCandidate flag
|
||||
mUseCandidate = msg.hasAttribute(StunAttribute::ICEUseCandidate);
|
||||
|
||||
// Check if auth credentials are needed
|
||||
mGenerate400 = false; //do not send 400 response by default
|
||||
mGenerate487 = false;
|
||||
|
||||
if (!msg.hasAttribute(StunAttribute::Username) || !msg.hasAttribute(StunAttribute::MessageIntegrity))
|
||||
{
|
||||
ICELogCritical(<< "There is no Username or MessageIntegrity attributes in Binding required. Error 400 will be generated.");
|
||||
// Send 400 error
|
||||
mGenerate400 = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for role
|
||||
if (msg.hasAttribute(StunAttribute::ControlledAttr))
|
||||
{
|
||||
mRemoteTieBreaker = msg.iceControlledAttr().tieBreaker();
|
||||
mRole = 1; // Session::Controlled;
|
||||
}
|
||||
else
|
||||
if (msg.hasAttribute(StunAttribute::ControllingAttr))
|
||||
{
|
||||
mRemoteTieBreaker = msg.iceControllingAttr().tieBreaker();
|
||||
mRole = 2;// Session::Controlling;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer* ServerBinding::generateData(bool force)
|
||||
{
|
||||
// Restart timer
|
||||
mRTOTimer.stop();
|
||||
mRTOTimer.start();
|
||||
|
||||
// See if remote password / username are set
|
||||
if (mPassword.empty() || mUsername.empty())
|
||||
return NULL;
|
||||
|
||||
StunMessage msg;
|
||||
|
||||
// Set transaction ID the same as processed incoming message
|
||||
msg.setTransactionId(mTransactionID);
|
||||
msg.setMessageType(StunMessage::Binding);
|
||||
|
||||
if (mGenerate400)
|
||||
{
|
||||
// Generate bad request error
|
||||
msg.setMessageClass(StunMessage::ErrorClass);
|
||||
|
||||
msg.errorCodeAttr().setErrorCode(400);
|
||||
msg.errorCodeAttr().setErrorPhrase("Bad request");
|
||||
}
|
||||
else
|
||||
if (mGenerate487)
|
||||
{
|
||||
// Generate 487 error
|
||||
msg.setMessageClass(StunMessage::ErrorClass);
|
||||
msg.errorCodeAttr().setErrorCode(487);
|
||||
msg.errorCodeAttr().setErrorPhrase("Role conflict");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.setMessageClass(StunMessage::SuccessClass);
|
||||
|
||||
msg.mappedAddressAttr().address() = mSourceAddress;
|
||||
msg.xorMappedAddressAttr().address() = mSourceAddress;
|
||||
}
|
||||
|
||||
// Build message
|
||||
|
||||
// Clear outgoing buffer
|
||||
mOutgoingData.clear();
|
||||
|
||||
// Check if message should be secured by message integrity
|
||||
//std::string password;
|
||||
if (!mGenerate400 && !mGenerate487)
|
||||
{
|
||||
// Do not create username attribute here - response does not need it
|
||||
// msg.usernameAttr().setValue(mUsername);
|
||||
|
||||
//ICELogCritical(<< "Using password " << mPassword);
|
||||
|
||||
// Add message integrity attribute
|
||||
msg.setAttribute(new MessageIntegrity());
|
||||
|
||||
if (mFingerprint)
|
||||
msg.setAttribute(new Fingerprint());
|
||||
|
||||
// Add ICE-CONTROLLED attribute if needed
|
||||
if (mEnableControlled)
|
||||
msg.iceControlledAttr().setTieBreaker(mLocalTieBreaker);
|
||||
|
||||
// Add ICE-CONTROLLING attribute if needed
|
||||
if (mEnableControlling)
|
||||
msg.iceControllingAttr().setTieBreaker(mLocalTieBreaker);
|
||||
|
||||
// Add ICE-PRIORITY attribute if needed
|
||||
if (mEnablePriority)
|
||||
msg.icePriorityAttr().setPriority(mPriority);
|
||||
}
|
||||
|
||||
// Build packet
|
||||
msg.buildPacket(mOutgoingData, mPassword);
|
||||
|
||||
// Copy comment
|
||||
msg.setComment(mComment);
|
||||
|
||||
mComposed = true;
|
||||
|
||||
return new ByteBuffer(mOutgoingData);
|
||||
}
|
||||
|
||||
bool ServerBinding::hasUseCandidate()
|
||||
{
|
||||
return mUseCandidate;
|
||||
}
|
||||
|
||||
bool ServerBinding::gotRequest()
|
||||
{
|
||||
return !mGenerate400 && !mGenerate487;
|
||||
}
|
||||
|
||||
int ServerBinding::role()
|
||||
{
|
||||
return mRole;
|
||||
}
|
||||
|
||||
void ServerBinding::generate487()
|
||||
{
|
||||
mGenerate487 = true;
|
||||
}
|
||||
|
||||
std::string ServerBinding::remoteTieBreaker()
|
||||
{
|
||||
return mRemoteTieBreaker;
|
||||
}
|
||||
|
||||
void ServerBinding::restart()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------- BindingIndication ---------------
|
||||
BindingIndication::BindingIndication(unsigned int interval)
|
||||
:mInterval(interval)
|
||||
{
|
||||
setComment("BindingIndication");
|
||||
}
|
||||
|
||||
BindingIndication::~BindingIndication()
|
||||
{
|
||||
}
|
||||
|
||||
bool BindingIndication::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
return (msg.messageClass() == StunMessage::IndicationClass &&
|
||||
msg.messageType() == StunMessage::Binding);
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer* BindingIndication::generateData(bool force)
|
||||
{
|
||||
if (!mComposed)
|
||||
{
|
||||
StunMessage msg;
|
||||
msg.setMessageClass(StunMessage::IndicationClass);
|
||||
msg.setMessageType(StunMessage::Binding);
|
||||
msg.setTransactionId(mTransactionID);
|
||||
msg.setComment(mComment);
|
||||
enqueueMessage(msg);
|
||||
mComposed = true;
|
||||
}
|
||||
|
||||
return Transaction::generateData(force);
|
||||
}
|
||||
|
||||
131
src/libs/ice/ICEBinding.h
Normal file
131
src/libs/ice/ICEBinding.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_BINDING_H
|
||||
#define __ICE_BINDING_H
|
||||
|
||||
#include "ICEStunTransaction.h"
|
||||
#include "ICEAuthTransaction.h"
|
||||
#include "ICEAddress.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class CheckResult
|
||||
{
|
||||
public:
|
||||
virtual Transaction::State resultState() = 0;
|
||||
virtual int resultError() = 0;
|
||||
virtual NetworkAddress& resultSource() = 0;
|
||||
virtual NetworkAddress& resultLocal() = 0;
|
||||
virtual void useCandidate() = 0;
|
||||
virtual unsigned resultPriority() = 0;
|
||||
};
|
||||
|
||||
class ConnectivityCheck: public Transaction, public CheckResult
|
||||
{
|
||||
public:
|
||||
ConnectivityCheck();
|
||||
virtual ~ConnectivityCheck();
|
||||
|
||||
ByteBuffer* generateData(bool force = false);
|
||||
bool processData(StunMessage& msg, NetworkAddress& sourceAddress);
|
||||
|
||||
NetworkAddress& mappedAddress(); //returns result from succesful transaction
|
||||
NetworkAddress& responseAddress(); //returns responses source address
|
||||
int errorCode();
|
||||
void addUseCandidate();
|
||||
void confirmTransaction(NetworkAddress& mapped);
|
||||
|
||||
// CheckResult interface
|
||||
int resultError();
|
||||
NetworkAddress& resultSource();
|
||||
NetworkAddress& resultLocal();
|
||||
State resultState();
|
||||
void useCandidate();
|
||||
unsigned resultPriority();
|
||||
protected:
|
||||
NetworkAddress mResponseAddress;
|
||||
NetworkAddress mMappedAddress;
|
||||
bool mUseCandidate;
|
||||
int mErrorCode;
|
||||
std::string mErrorResponse;
|
||||
};
|
||||
|
||||
class ClientBinding: public Transaction
|
||||
{
|
||||
public:
|
||||
ClientBinding();
|
||||
virtual ~ClientBinding();
|
||||
|
||||
int errorCode(); //returns error code from failed transaction
|
||||
std::string errorResponse(); //returns error msg from failed transaction
|
||||
NetworkAddress& mappedAddress(); //returns result from succesful transaction
|
||||
NetworkAddress& responseAddress(); //returns responses source address
|
||||
|
||||
bool processData(StunMessage& msg, NetworkAddress& address);
|
||||
ByteBuffer* generateData(bool force = false);
|
||||
void addUseCandidate();
|
||||
|
||||
protected:
|
||||
int mErrorCode;
|
||||
NetworkAddress mMappedAddress;
|
||||
std::string mErrorResponse;
|
||||
NetworkAddress mResponseAddress;
|
||||
bool mUseCandidate;
|
||||
};
|
||||
|
||||
class ServerBinding: public Transaction
|
||||
{
|
||||
public:
|
||||
ServerBinding();
|
||||
virtual ~ServerBinding();
|
||||
void setLocalTieBreaker(std::string tieBreaker);
|
||||
|
||||
bool processData(StunMessage& msg, NetworkAddress& address);
|
||||
ByteBuffer* generateData(bool force = false);
|
||||
void restart();
|
||||
|
||||
// Checks if incoming request has UseCandidate attribute
|
||||
bool hasUseCandidate();
|
||||
|
||||
// Checks if processed StunMessage was authenticated ok
|
||||
bool gotRequest();
|
||||
|
||||
// Gets the role from processed message. It can be Controlled or Controlling or None.
|
||||
int role();
|
||||
|
||||
// Instructs transaction to response with 487 code
|
||||
void generate487();
|
||||
|
||||
// Returns received tie breaker
|
||||
std::string remoteTieBreaker();
|
||||
|
||||
protected:
|
||||
NetworkAddress mSourceAddress;
|
||||
bool mUseCandidate;
|
||||
bool mGenerate400;
|
||||
bool mGenerate487;
|
||||
int mRole;
|
||||
std::string mLocalTieBreaker;
|
||||
std::string mRemoteTieBreaker;
|
||||
};
|
||||
|
||||
|
||||
class BindingIndication: public Transaction
|
||||
{
|
||||
public:
|
||||
BindingIndication(unsigned int interval);
|
||||
virtual ~BindingIndication();
|
||||
|
||||
bool processData(StunMessage& msg, NetworkAddress& address);
|
||||
ByteBuffer* generateData(bool force = false);
|
||||
|
||||
protected:
|
||||
unsigned mTimestamp;
|
||||
unsigned mInterval;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
60
src/libs/ice/ICEBox.cpp
Normal file
60
src/libs/ice/ICEBox.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEBox.h"
|
||||
#include "ICEBoxImpl.h"
|
||||
#include <time.h>
|
||||
|
||||
using namespace ice;
|
||||
|
||||
Stack::~Stack()
|
||||
{
|
||||
}
|
||||
|
||||
void Stack::initialize()
|
||||
{
|
||||
}
|
||||
|
||||
void Stack::finalize()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
Stack* Stack::makeICEBox(const ServerConfig& config)
|
||||
{
|
||||
return new StackImpl(config);
|
||||
}
|
||||
|
||||
bool Stack::isDataIndication(ByteBuffer& source, ByteBuffer* plain)
|
||||
{
|
||||
return Session::isDataIndication(source, plain);
|
||||
}
|
||||
|
||||
bool Stack::isStun(ByteBuffer& source)
|
||||
{
|
||||
return Session::isStun(source);
|
||||
}
|
||||
|
||||
bool Stack::isRtp(ByteBuffer& data)
|
||||
{
|
||||
return Session::isRtp(data);
|
||||
}
|
||||
|
||||
bool Stack::isChannelData(ByteBuffer& data, TurnPrefix prefix)
|
||||
{
|
||||
return Session::isChannelData(data, prefix);
|
||||
}
|
||||
|
||||
ByteBuffer Stack::makeChannelData(TurnPrefix prefix, const void* data, unsigned datasize)
|
||||
{
|
||||
ByteBuffer result;
|
||||
result.resize(4 + datasize);
|
||||
BufferWriter writer(result);
|
||||
writer.writeUShort(prefix);
|
||||
writer.writeUShort(datasize);
|
||||
writer.writeBuffer(data, datasize);
|
||||
|
||||
return result;
|
||||
}
|
||||
251
src/libs/ice/ICEBox.h
Normal file
251
src/libs/ice/ICEBox.h
Normal file
@@ -0,0 +1,251 @@
|
||||
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __NAT_ICE_H
|
||||
#define __NAT_ICE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ICESync.h"
|
||||
#include "ICEEvent.h"
|
||||
#include "ICEAddress.h"
|
||||
#include "ICEByteBuffer.h"
|
||||
#include "ICECandidate.h"
|
||||
|
||||
#define ICE_TIMEOUT 8000
|
||||
#define ICE_CHECK_INTERVAL 20
|
||||
|
||||
#define ICE_RTP_ID 1
|
||||
#define ICE_RTCP_ID 2
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
// Structure to describe used STUN/TURN configuration
|
||||
struct ServerConfig
|
||||
{
|
||||
std::vector<NetworkAddress> mServerList4, mServerList6; // List of STUN/TURN servers for IPv4 and IPv6 protocols
|
||||
bool mUseIPv4; // Marks if IPv4 should be used when gathering candidates
|
||||
bool mUseIPv6; // Marks if IPv6 should be used when gathering candidates
|
||||
std::string mHost; // Target host to get default IP interface; usually it is public IP address
|
||||
bool mRelay; // Marks if TURN is to be used instead STUN
|
||||
unsigned int mTimeout; // Timeout value in milliseconds
|
||||
unsigned int mPeriod; // Transmission interval
|
||||
std::string mUsername; // User name for TURN server [optional]
|
||||
std::string mPassword; // Password for TURN server [optional]
|
||||
|
||||
ServerConfig()
|
||||
:mUseIPv4(true), mUseIPv6(true), mRelay(false), mTimeout(ICE_TIMEOUT), mPeriod(ICE_CHECK_INTERVAL)
|
||||
{
|
||||
}
|
||||
|
||||
~ServerConfig()
|
||||
{}
|
||||
};
|
||||
|
||||
enum IceState
|
||||
{
|
||||
IceNone = 0, // Stack non active now
|
||||
IceGathering = 1, // Stack gathering candidates now
|
||||
IceGathered = 2, // Stack gathered candidates
|
||||
IceChecking = 3, // Stack runs connectivity checks now
|
||||
IceCheckSuccess = 4, // Connectivity checks were successful
|
||||
IceFailed = 5, // Connectivity checks or gathering failed
|
||||
IceTimeout = 6 // Timeout
|
||||
};
|
||||
|
||||
|
||||
enum AgentRole
|
||||
{
|
||||
RoleControlled = 1,
|
||||
RoleControlling = 2
|
||||
};
|
||||
|
||||
// ICE stack
|
||||
class Stack
|
||||
{
|
||||
public:
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
|
||||
static Stack* makeICEBox(const ServerConfig& config);
|
||||
|
||||
// Service methods to check incoming packets
|
||||
static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain);
|
||||
static bool isStun(ByteBuffer& source);
|
||||
static bool isRtp(ByteBuffer& data);
|
||||
static bool isChannelData(ByteBuffer& data, TurnPrefix prefix);
|
||||
|
||||
static ByteBuffer makeChannelData(TurnPrefix prefix, const void* data, unsigned datasize);
|
||||
|
||||
/*! Sets ICE event handler pointer in stack.
|
||||
* @param handler Pointer to ICE event handler instance.
|
||||
* @param tag Custom user tag. */
|
||||
virtual void setEventHandler(StageHandler* handler, void* tag) = 0;
|
||||
|
||||
/*! Adds new stream to ICE stack object.
|
||||
* @return ID of created stream.
|
||||
*/
|
||||
virtual int addStream() = 0;
|
||||
|
||||
/*! Adds new component (socket) to media stream.
|
||||
* @param portNumber specifies used local port number for the socket.
|
||||
* @returns component ID. This ID is unique only for specified stream. Two components in different streams can have the same */
|
||||
virtual int addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) = 0;
|
||||
|
||||
/*! Removes media stream from ICE stack object. */
|
||||
virtual void removeStream(int streamID) = 0;
|
||||
|
||||
virtual bool hasStream(int streamId) = 0;
|
||||
virtual bool hasComponent(int streamId, int componentId) = 0;
|
||||
virtual void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) = 0;
|
||||
|
||||
virtual void setRole(AgentRole role) = 0;
|
||||
virtual AgentRole role() = 0;
|
||||
|
||||
/*! Processes incoming data.
|
||||
* @param streamID ICE stream ID
|
||||
* @param componentID ICE component ID
|
||||
* @param sourceIP IP of remote peer
|
||||
* @param port number of remote peer
|
||||
* @param sourceBuffer pointer to incoming data buffer
|
||||
* @param sourceSize size of incoming data (in bytes)
|
||||
*/
|
||||
virtual bool processIncomingData(int stream, int component, ByteBuffer& incomingData) = 0;
|
||||
|
||||
/*! Generates outgoing data for sending.
|
||||
* @param response marks if the returned packet is response packet to remote peer's request
|
||||
* @param streamID ICE stream ID
|
||||
* @param componentID ICE component ID
|
||||
* @param destIP Character buffer to write destination IP address in textual form
|
||||
* @param destPort Destination port number.
|
||||
* @param dataBuffer Pointer to output buffer. It must be big enough to include at least 1500 bytes - it is biggest UDP datagram in this library.
|
||||
*/
|
||||
virtual PByteBuffer generateOutgoingData(bool& response, int& stream, int& component, void*& tag) = 0;
|
||||
|
||||
/*! Searches stream&component IDs by used local port and socket family. */
|
||||
virtual bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component) = 0;
|
||||
|
||||
/*! Starts to gather local candidates. */
|
||||
virtual void gatherCandidates() = 0;
|
||||
|
||||
/*! Starts ICE connectivity checks. */
|
||||
virtual void checkConnectivity() = 0;
|
||||
|
||||
/*! Checks if gathering is finished. */
|
||||
virtual IceState state() = 0;
|
||||
|
||||
/*! Creates common part of SDP. It includes ice-full attribute and ufrag/pwd pair.
|
||||
* @param common Common part of SDP. */
|
||||
virtual void createSdp(std::vector<std::string>& common) = 0;
|
||||
|
||||
/*! Returns default address for specified stream/component ID.
|
||||
* @param ip Default IP address.
|
||||
* @param port Default port number. */
|
||||
virtual NetworkAddress defaultAddress(int streamID, int componentID) = 0;
|
||||
|
||||
/*! Returns candidate list for specified stream/component ID.
|
||||
* @param streamID Stream ID.
|
||||
* @param componentID Component ID.
|
||||
* @param candidateList Output vector of local candidates. */
|
||||
virtual void fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList) = 0;
|
||||
|
||||
/*! Process ICE offer text for specified stream.
|
||||
* @param streamIndex ICE stream index.
|
||||
* @param candidateList Input vector of strings - it holds candidate list.
|
||||
* @param defaultIP Default IP for component ID 0.
|
||||
* @param defaultPort Default port number for component ID 0.
|
||||
* @return Returns true if processing(parsing) was ok, otherwise method returns false. */
|
||||
virtual bool processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
|
||||
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) = 0;
|
||||
|
||||
virtual NetworkAddress getRemoteRelayedCandidate(int stream, int component) = 0;
|
||||
virtual NetworkAddress getRemoteReflexiveCandidate(int stream, int component) = 0;
|
||||
|
||||
/*! Notifies stack about ICE password of remote peer.
|
||||
* @param pwd ICE password. */
|
||||
virtual void setRemotePassword(const std::string& pwd, int streamId = -1) = 0;
|
||||
virtual std::string remotePassword(int streamId = -1) const = 0;
|
||||
|
||||
/*! Notifies stack about ICE ufrag of remote peer.
|
||||
* @param ufrag ICE ufrag credential. */
|
||||
virtual void setRemoteUfrag(const std::string& ufrag, int streamId = -1) = 0;
|
||||
virtual std::string remoteUfrag(int streamId = -1) const = 0;
|
||||
|
||||
/*! Returns local ICE password.
|
||||
* @return ICE password. */
|
||||
virtual std::string localPassword() const = 0;
|
||||
|
||||
/*! Returns local ICE ufrag.
|
||||
* @return ICE ufrag credential. */
|
||||
virtual std::string localUfrag() const = 0;
|
||||
|
||||
/*! Checks if the specified value is ICE session's TURN prefix value.
|
||||
* @return Returns true if parameter is TURN prefix value, false otherwise. */
|
||||
virtual bool hasTurnPrefix(unsigned short prefix) = 0;
|
||||
|
||||
/*! Gets the discovered during connectivity checks remote party's address.
|
||||
* @return Remote party's address */
|
||||
virtual NetworkAddress remoteAddress(int stream, int component) = 0;
|
||||
virtual NetworkAddress localAddress(int stream, int component) = 0;
|
||||
|
||||
/*! Seeks for conclude pair.
|
||||
*/
|
||||
virtual bool findConcludePair(int stream, Candidate& local, Candidate& remote) = 0;
|
||||
|
||||
/*! Checks if remote candidate list contains specified address.
|
||||
* @return True if address is found in remote candidate list, false otherwise. */
|
||||
virtual bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) = 0;
|
||||
|
||||
// Dumps current state of stack to output
|
||||
virtual void dump(std::ostream& output) = 0;
|
||||
|
||||
// Returns if ICE session must be restarted after new offer.
|
||||
virtual bool mustRestart() = 0;
|
||||
|
||||
// Clears all connectivity checks and reset state of session to None. It does not delete streams and components.
|
||||
virtual void clear() = 0;
|
||||
|
||||
// Prepares stack to restart - clears remote candidate list, cancels existing connectivity checks, resets turn allocation counter
|
||||
virtual void clearForRestart(bool localNetworkChanged) = 0;
|
||||
|
||||
// Stops all connectivity & gathering checks.
|
||||
virtual void stopChecks() = 0;
|
||||
|
||||
// Refreshes local password and ufrag values. Useful when connectivity checks must be restarted.
|
||||
virtual void refreshPwdUfrag() = 0;
|
||||
|
||||
// Binds channel and return channel prefix
|
||||
virtual TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) = 0;
|
||||
virtual bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) = 0;
|
||||
|
||||
virtual void installPermissions(int stream, int component, const NetworkAddress& address, InstallPermissionsCallback* cb) = 0;
|
||||
|
||||
// Starts freeing of TURN allocations
|
||||
virtual void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) = 0;
|
||||
|
||||
// Checks if there are active allocations on TURN server
|
||||
virtual bool hasAllocations() = 0;
|
||||
|
||||
// Checks if any of stream has set error code and return it
|
||||
virtual int errorCode() = 0;
|
||||
|
||||
// Returns the list of candidates from remote peer
|
||||
virtual std::vector<Candidate>* remoteCandidates(int stream) = 0;
|
||||
|
||||
// Returns chosen stun server address during last candidate gathering
|
||||
virtual NetworkAddress activeStunServer(int stream) const = 0;
|
||||
|
||||
virtual void setup(const ServerConfig& config) = 0;
|
||||
virtual bool isRelayHost(const NetworkAddress& remote) = 0;
|
||||
virtual bool isRelayAddress(const NetworkAddress& remote) = 0;
|
||||
|
||||
virtual ~Stack();
|
||||
};
|
||||
|
||||
} //end of namespace
|
||||
|
||||
#endif
|
||||
445
src/libs/ice/ICEBoxImpl.cpp
Normal file
445
src/libs/ice/ICEBoxImpl.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
/* Copyright(C) 2007-2017 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEBoxImpl.h"
|
||||
#include "ICELog.h"
|
||||
//#include "TargetConditionals.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
StackImpl::StackImpl(const ServerConfig& config)
|
||||
:mConfig(config), mEventHandler(NULL), mEventTag(NULL), mTimeout(false), mActionTimestamp(0)
|
||||
{
|
||||
setup(config);
|
||||
}
|
||||
|
||||
StackImpl::~StackImpl()
|
||||
{
|
||||
}
|
||||
|
||||
void StackImpl::setEventHandler(StageHandler* handler, void* tag)
|
||||
{
|
||||
mEventHandler = handler;
|
||||
mEventTag = tag;
|
||||
}
|
||||
|
||||
int StackImpl::addStream()
|
||||
{
|
||||
return mSession.addStream();
|
||||
}
|
||||
|
||||
int StackImpl::addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6)
|
||||
{
|
||||
return mSession.addComponent(streamID, tag, port4, port6);
|
||||
}
|
||||
|
||||
void StackImpl::removeStream(int streamID)
|
||||
{
|
||||
mSession.removeStream(streamID);
|
||||
}
|
||||
|
||||
bool StackImpl::findStreamAndComponent(int family, unsigned short port, int* stream, int* component)
|
||||
{
|
||||
return mSession.findStreamAndComponent(family, port, stream, component);
|
||||
}
|
||||
|
||||
bool StackImpl::hasStream(int streamId)
|
||||
{
|
||||
return mSession.hasStream(streamId);
|
||||
}
|
||||
|
||||
bool StackImpl::hasComponent(int streamId, int componentId)
|
||||
{
|
||||
return mSession.hasComponent(streamId, componentId);
|
||||
}
|
||||
|
||||
void StackImpl::setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6)
|
||||
{
|
||||
mSession.setComponentPort(streamId, componentId, port4, port6);
|
||||
}
|
||||
|
||||
|
||||
void StackImpl::setRole(AgentRole role)
|
||||
{
|
||||
mSession.setRole(role);
|
||||
}
|
||||
|
||||
AgentRole StackImpl::role()
|
||||
{
|
||||
return mSession.role();
|
||||
}
|
||||
|
||||
bool StackImpl::processIncomingData(int stream, int component, ByteBuffer& incomingData)
|
||||
{
|
||||
#if defined(ICE_EMULATE_SYMMETRIC_NAT) //&& (TARGET_IPHONE_SIMULATOR)
|
||||
if (!isRelayHost(incomingData.remoteAddress()))
|
||||
{
|
||||
ICELogDebug(<<"Discard packet as symmetric NAT is emulating now");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (incomingData.remoteAddress().isEmpty())
|
||||
{
|
||||
ICELogDebug(<< "Incoming packet; remote address is unknown");
|
||||
incomingData.setRemoteAddress(NetworkAddress::LoopbackAddress4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ICELogDebug(<< "Incoming packet from " << incomingData.remoteAddress().toStdString());
|
||||
}
|
||||
// Save previous ICE stack state
|
||||
int icestate = state();
|
||||
|
||||
incomingData.setComponent(component);
|
||||
bool result = mSession.processData(incomingData, stream, component);
|
||||
|
||||
// Run handlers
|
||||
if (result && mEventHandler)
|
||||
{
|
||||
int newicestate = state();
|
||||
if (icestate < IceCheckSuccess && newicestate >= IceCheckSuccess)
|
||||
{
|
||||
// Connectivity check finished
|
||||
if (newicestate == IceCheckSuccess)
|
||||
mEventHandler->onSuccess(this, mEventTag);
|
||||
else
|
||||
mEventHandler->onFailed(this, mEventTag);
|
||||
}
|
||||
else
|
||||
if (icestate < IceGathered && newicestate >= IceGathered)
|
||||
{
|
||||
// Candidates are gathered
|
||||
mEventHandler->onGathered(this, mEventTag);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PByteBuffer StackImpl::generateOutgoingData(bool& response, int& stream, int& component, void*& tag)
|
||||
{
|
||||
// Get current timestamp
|
||||
unsigned timestamp = ICETimeHelper::timestamp();
|
||||
|
||||
// Find amount of spent time
|
||||
unsigned spent = ICETimeHelper::findDelta(mActionTimestamp, timestamp);
|
||||
|
||||
// Check for timeout
|
||||
if (mConfig.mTimeout && spent > mConfig.mTimeout)
|
||||
{
|
||||
ice::RunningState sessionState = mSession.state();
|
||||
|
||||
bool timeout = sessionState == ice::ConnCheck || sessionState == ice::CandidateGathering;
|
||||
|
||||
if (!mTimeout && timeout)
|
||||
{
|
||||
// Mark stack as timeouted
|
||||
mTimeout = true;
|
||||
ICELogInfo(<< "Timeout detected.");
|
||||
|
||||
if (sessionState == ice::CandidateGathering)
|
||||
mSession.cancelAllocations();
|
||||
|
||||
// Find default address amongst host candidates
|
||||
mSession.chooseDefaults();
|
||||
|
||||
if (mEventHandler)
|
||||
{
|
||||
if (sessionState == ice::ConnCheck)
|
||||
{
|
||||
// Session should not be cleared here - the CT uses direct path for connectivity checks and relayed if checks are failed. Relayed allocations will not be refreshed in such case
|
||||
mEventHandler->onFailed(this, this->mEventTag);
|
||||
}
|
||||
else
|
||||
mEventHandler->onGathered(this, this->mEventTag);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
// Check if keepalive transactions are scheduled
|
||||
if (!mSession.hasAllocations())
|
||||
return PByteBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// No timeout, proceed...
|
||||
PByteBuffer result = mSession.getDataToSend(response, stream, component, tag);
|
||||
if (result)
|
||||
ICELogInfo(<< "Sending: " << result->comment() << " to " << result->remoteAddress().toStdString() << ". Data: \r\n" << result->hexstring());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void StackImpl::gatherCandidates()
|
||||
{
|
||||
mActionTimestamp = ICETimeHelper::timestamp();
|
||||
mSession.gatherCandidates();
|
||||
|
||||
// If there is no STUN server set or IP6 only interfaces - the candidate gathering can finish without network I/O
|
||||
if (mSession.state() == CreatingSDP && mEventHandler)
|
||||
mEventHandler->onGathered(this, mEventTag);
|
||||
}
|
||||
|
||||
void StackImpl::checkConnectivity()
|
||||
{
|
||||
// Connectivity check can work if candidate gathering timeout-ed yet - it relies on host candidates only in this case
|
||||
// So timeout flag is reset
|
||||
mTimeout = false;
|
||||
mActionTimestamp = ICETimeHelper::timestamp();
|
||||
mSession.checkConnectivity();
|
||||
}
|
||||
|
||||
void StackImpl::stopChecks()
|
||||
{
|
||||
mTimeout = false;
|
||||
mActionTimestamp = 0;
|
||||
mSession.stopChecks();
|
||||
}
|
||||
|
||||
IceState StackImpl::state()
|
||||
{
|
||||
if (mTimeout)
|
||||
return IceTimeout;
|
||||
|
||||
switch (mSession.state())
|
||||
{
|
||||
case ice::None: return IceNone;
|
||||
case ice::CandidateGathering: return IceGathering;
|
||||
case ice::CreatingSDP: return IceGathered;
|
||||
case ice::ConnCheck: return IceChecking;
|
||||
case ice::Failed: return IceFailed;
|
||||
case ice::Success: return IceCheckSuccess;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return IceNone; // to avoid compiler warning
|
||||
}
|
||||
|
||||
void StackImpl::createSdp(std::vector<std::string>& commonPart)
|
||||
{
|
||||
mSession.createSdp(commonPart);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::defaultAddress(int stream, int component)
|
||||
{
|
||||
return mSession.defaultAddress(stream, component);
|
||||
}
|
||||
|
||||
void StackImpl::fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList)
|
||||
{
|
||||
mSession.fillCandidateList(streamID, componentID, candidateList);
|
||||
}
|
||||
|
||||
bool StackImpl::processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
|
||||
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed)
|
||||
{
|
||||
return mSession.processSdpOffer(streamIndex, candidateList, defaultIP, defaultPort, deleteRelayed);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::getRemoteRelayedCandidate(int stream, int component)
|
||||
{
|
||||
return mSession.getRemoteRelayedCandidate(stream, component);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::getRemoteReflexiveCandidate(int stream, int component)
|
||||
{
|
||||
return mSession.getRemoteReflexiveCandidate(stream, component);
|
||||
}
|
||||
|
||||
|
||||
void StackImpl::setRemotePassword(const std::string& pwd, int streamId)
|
||||
{
|
||||
mSession.setRemotePassword(pwd, streamId);
|
||||
}
|
||||
|
||||
std::string StackImpl::remotePassword(int streamId) const
|
||||
{
|
||||
return mSession.remotePassword(streamId);
|
||||
}
|
||||
|
||||
void StackImpl::setRemoteUfrag(const std::string& ufrag, int streamId)
|
||||
{
|
||||
mSession.setRemoteUfrag(ufrag, streamId);
|
||||
}
|
||||
|
||||
std::string StackImpl::remoteUfrag(int streamId) const
|
||||
{
|
||||
return mSession.remoteUfrag(streamId);
|
||||
}
|
||||
|
||||
std::string StackImpl::localPassword() const
|
||||
{
|
||||
return mSession.mLocalPwd;
|
||||
}
|
||||
|
||||
std::string StackImpl::localUfrag() const
|
||||
{
|
||||
return mSession.mLocalUfrag;
|
||||
}
|
||||
|
||||
bool StackImpl::hasTurnPrefix(unsigned short prefix)
|
||||
{
|
||||
return mSession.hasTurnPrefix((TurnPrefix)prefix);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::remoteAddress(int stream, int component)
|
||||
{
|
||||
return mSession.remoteAddress(stream, component);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::localAddress(int stream, int component)
|
||||
{
|
||||
return mSession.localAddress(stream, component);
|
||||
}
|
||||
|
||||
bool StackImpl::findConcludePair(int stream, Candidate& local, Candidate& remote)
|
||||
{
|
||||
// Find nominated pair in stream
|
||||
return mSession.findConcludePair(stream, local, remote);
|
||||
}
|
||||
|
||||
bool StackImpl::candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort)
|
||||
{
|
||||
return mSession.mStreamMap[stream]->candidateListContains(remoteIP, remotePort);
|
||||
}
|
||||
|
||||
void StackImpl::dump(std::ostream& output)
|
||||
{
|
||||
mSession.dump(output);
|
||||
}
|
||||
|
||||
bool StackImpl::mustRestart()
|
||||
{
|
||||
return mSession.mustRestart();
|
||||
}
|
||||
|
||||
void StackImpl::clear()
|
||||
{
|
||||
mSession.clear();
|
||||
mActionTimestamp = 0;
|
||||
mTimeout = false;
|
||||
}
|
||||
|
||||
void StackImpl::clearForRestart(bool localNetworkChanged)
|
||||
{
|
||||
mSession.clearForRestart(localNetworkChanged);
|
||||
mActionTimestamp = 0;
|
||||
mTimeout = false;
|
||||
}
|
||||
|
||||
void StackImpl::refreshPwdUfrag()
|
||||
{
|
||||
mSession.refreshPwdUfrag();
|
||||
}
|
||||
|
||||
TurnPrefix StackImpl::bindChannel(int stream, int component, const ice::NetworkAddress &target, ChannelBoundCallback* cb)
|
||||
{
|
||||
return mSession.bindChannel(stream, component, target, cb);
|
||||
}
|
||||
|
||||
bool StackImpl::isChannelBindingFailed(int stream, int component, TurnPrefix prefix)
|
||||
{
|
||||
return mSession.isChannelBindingFailed(stream, component, prefix);
|
||||
}
|
||||
|
||||
void StackImpl::installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb)
|
||||
{
|
||||
mSession.installPermissions(stream, component, address, cb);
|
||||
}
|
||||
|
||||
void StackImpl::freeAllocation(int stream, int component, DeleteAllocationCallback* cb)
|
||||
{
|
||||
mSession.freeAllocation(stream, component, cb);
|
||||
}
|
||||
|
||||
bool StackImpl::hasAllocations()
|
||||
{
|
||||
return mSession.hasAllocations();
|
||||
}
|
||||
|
||||
int StackImpl::errorCode()
|
||||
{
|
||||
return mSession.errorCode();
|
||||
}
|
||||
|
||||
std::vector<Candidate>* StackImpl::remoteCandidates(int stream)
|
||||
{
|
||||
return mSession.remoteCandidates(stream);
|
||||
}
|
||||
|
||||
NetworkAddress StackImpl::activeStunServer(int stream) const
|
||||
{
|
||||
return mSession.activeStunServer(stream);
|
||||
}
|
||||
|
||||
void StackImpl::setup(const ServerConfig& config)
|
||||
{
|
||||
mConfig = config;
|
||||
mSession.mConfig.mServerList4 = config.mServerList4;
|
||||
mSession.mConfig.mServerList6 = config.mServerList6;
|
||||
|
||||
// Set initial STUN/TURN server IP for case if there will no gathering candidates & selecting fastest server.
|
||||
if (mSession.mConfig.mServerList4.size())
|
||||
mSession.mConfig.mServerAddr4 = mSession.mConfig.mServerList4.front();
|
||||
if (mSession.mConfig.mServerList6.size())
|
||||
mSession.mConfig.mServerAddr6 = mSession.mConfig.mServerList6.front();
|
||||
mSession.mConfig.mUseIPv4 = config.mUseIPv4;
|
||||
mSession.mConfig.mUseIPv6 = config.mUseIPv6;
|
||||
|
||||
if (mConfig.mRelay)
|
||||
{
|
||||
mSession.mConfig.mTurnPassword = config.mPassword;
|
||||
mSession.mConfig.mTurnUsername = config.mUsername;
|
||||
|
||||
mSession.mConfig.mUseTURN = true;
|
||||
mSession.mConfig.mUseSTUN = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSession.mConfig.mUseTURN = false;
|
||||
mSession.mConfig.mUseSTUN = true;
|
||||
}
|
||||
mSession.mConfig.mTimeout = config.mTimeout;
|
||||
|
||||
mSession.setup(mSession.mConfig);
|
||||
}
|
||||
|
||||
bool StackImpl::isRelayHost(const NetworkAddress& remote)
|
||||
{
|
||||
for (unsigned i=0; i<mConfig.mServerList4.size(); i++)
|
||||
{
|
||||
if (NetworkAddress::isSameHost(mConfig.mServerList4[i], remote))
|
||||
return true;
|
||||
}
|
||||
for (unsigned i=0; i<mConfig.mServerList6.size(); i++)
|
||||
{
|
||||
if (NetworkAddress::isSameHost(mConfig.mServerList6[i], remote))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StackImpl::isRelayAddress(const NetworkAddress& remote)
|
||||
{
|
||||
for (unsigned i=0; i<mConfig.mServerList4.size(); i++)
|
||||
{
|
||||
if (mConfig.mServerList4[i] == remote)
|
||||
return true;
|
||||
}
|
||||
for (unsigned i=0; i<mConfig.mServerList6.size(); i++)
|
||||
{
|
||||
if (mConfig.mServerList6[i] == remote)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
105
src/libs/ice/ICEBoxImpl.h
Normal file
105
src/libs/ice/ICEBoxImpl.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_BOX_IMPL__H
|
||||
#define __ICE_BOX_IMPL__H
|
||||
|
||||
#include "ICEBox.h"
|
||||
#include "ICESession.h"
|
||||
#include "ICELog.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class StackImpl: public Stack
|
||||
{
|
||||
protected:
|
||||
ServerConfig mConfig;
|
||||
Mutex mGuard; //mutex to protect ICE stack object
|
||||
Session mSession;
|
||||
StageHandler* mEventHandler;
|
||||
void* mEventTag;
|
||||
bool mTimeout;
|
||||
unsigned int mActionTimestamp;
|
||||
|
||||
void logMsg(LogLevel level, const char* msg);
|
||||
|
||||
public:
|
||||
|
||||
StackImpl(const ServerConfig& config);
|
||||
~StackImpl();
|
||||
|
||||
void setEventHandler(StageHandler* handler, void* tag) override;
|
||||
int addStream() override;
|
||||
int addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6) override;
|
||||
void removeStream(int streamID) override;
|
||||
bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component) override;
|
||||
bool hasStream(int streamId) override;
|
||||
bool hasComponent(int streamId, int componentId) override;
|
||||
void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6) override;
|
||||
|
||||
void setRole(AgentRole role) override;
|
||||
AgentRole role() override;
|
||||
|
||||
bool processIncomingData(int stream, int component, ByteBuffer& incomingData) override;
|
||||
PByteBuffer generateOutgoingData(bool& response, int& stream, int& component, void*& tag) override;
|
||||
|
||||
// Attempt to gather candidates for specified channel
|
||||
void gatherCandidates() override;
|
||||
void checkConnectivity() override;
|
||||
void stopChecks() override;
|
||||
void restartCheckConnectivity();
|
||||
|
||||
IceState state() override;
|
||||
|
||||
void createSdp(std::vector<std::string>& commonPart) override;
|
||||
NetworkAddress defaultAddress(int streamID, int componentID) override;
|
||||
void fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList) override;
|
||||
|
||||
bool processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
|
||||
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed) override;
|
||||
NetworkAddress getRemoteRelayedCandidate(int stream, int component) override;
|
||||
NetworkAddress getRemoteReflexiveCandidate(int stream, int component) override;
|
||||
|
||||
void setRemotePassword(const std::string& pwd, int streamId = -1) override;
|
||||
std::string remotePassword(int streamId = -1) const override;
|
||||
void setRemoteUfrag(const std::string& ufrag, int streamId = -1) override;
|
||||
std::string remoteUfrag(int streamId = -1) const override;
|
||||
|
||||
std::string localPassword() const override;
|
||||
std::string localUfrag() const override;
|
||||
bool hasTurnPrefix(unsigned short prefix) override;
|
||||
NetworkAddress remoteAddress(int stream, int component) override;
|
||||
NetworkAddress localAddress(int stream, int component) override;
|
||||
bool findConcludePair(int stream, Candidate& local, Candidate& remote) override;
|
||||
bool candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort) override;
|
||||
void dump(std::ostream& output) override;
|
||||
bool mustRestart() override;
|
||||
void clear() override;
|
||||
void clearForRestart(bool localNetworkChanged) override;
|
||||
void refreshPwdUfrag() override;
|
||||
|
||||
// Channel binding
|
||||
TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb) override;
|
||||
bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix) override;
|
||||
|
||||
// Permissions
|
||||
void installPermissions(int stream, int component, const NetworkAddress& address, InstallPermissionsCallback* cb) override;
|
||||
|
||||
// Allocations
|
||||
void freeAllocation(int stream, int component, DeleteAllocationCallback* cb) override;
|
||||
bool hasAllocations() override;
|
||||
|
||||
|
||||
int errorCode() override;
|
||||
std::vector<Candidate>*
|
||||
remoteCandidates(int stream) override;
|
||||
NetworkAddress activeStunServer(int stream) const override;
|
||||
void setup(const ServerConfig& config) override;
|
||||
bool isRelayHost(const NetworkAddress& remote) override;
|
||||
bool isRelayAddress(const NetworkAddress& remote) override;
|
||||
};
|
||||
} //end of namespace
|
||||
|
||||
#endif
|
||||
560
src/libs/ice/ICEByteBuffer.cpp
Normal file
560
src/libs/ice/ICEByteBuffer.cpp
Normal file
@@ -0,0 +1,560 @@
|
||||
/* Copyright(C) 2007-2018 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEByteBuffer.h"
|
||||
#include "ICEError.h"
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace ice;
|
||||
ByteBuffer::ByteBuffer()
|
||||
{
|
||||
initEmpty();
|
||||
mData.reserve(512);
|
||||
}
|
||||
|
||||
ByteBuffer::ByteBuffer(size_t initialCapacity)
|
||||
{
|
||||
initEmpty();
|
||||
mData.reserve(initialCapacity);
|
||||
}
|
||||
|
||||
ByteBuffer::ByteBuffer(const ByteBuffer& src)
|
||||
:mData(src.mData), mComponent(src.mComponent), mTag(nullptr),
|
||||
mRelayed(src.mRelayed), mCopyBehavior(src.mCopyBehavior),
|
||||
mDataPtr(src.mDataPtr), mDataSize(src.mDataSize)
|
||||
{
|
||||
if (mCopyBehavior == CopyBehavior::CopyMemory && mData.size())
|
||||
mDataPtr = &mData[0];
|
||||
}
|
||||
|
||||
ByteBuffer::ByteBuffer(const void* packetPtr, size_t packetSize, CopyBehavior behavior)
|
||||
:mComponent(-1), mTag(nullptr), mRelayed(false), mCopyBehavior(behavior), mDataPtr(nullptr), mDataSize(packetSize)
|
||||
{
|
||||
switch (behavior)
|
||||
{
|
||||
case CopyBehavior::CopyMemory:
|
||||
mData.resize(packetSize);
|
||||
memcpy(&mData[0], packetPtr, packetSize);
|
||||
mDataPtr = &mData[0];
|
||||
break;
|
||||
|
||||
case CopyBehavior::UseExternal:
|
||||
mDataPtr = (uint8_t*)packetPtr;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer::~ByteBuffer()
|
||||
{
|
||||
if (mCopyBehavior == CopyBehavior::CopyMemory)
|
||||
memset(mDataPtr, 0, mDataSize);
|
||||
}
|
||||
|
||||
ByteBuffer& ByteBuffer::operator = (const ByteBuffer& src)
|
||||
{
|
||||
mRelayed = src.mRelayed;
|
||||
mComment = src.mComment;
|
||||
mComponent = src.mComponent;
|
||||
mRemoteAddress = src.mRemoteAddress;
|
||||
mTag = src.mTag;
|
||||
|
||||
if (src.mCopyBehavior == CopyBehavior::CopyMemory)
|
||||
{
|
||||
mData = src.mData;
|
||||
mCopyBehavior = CopyBehavior::CopyMemory;
|
||||
syncPointer();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mDataPtr = src.mDataPtr;
|
||||
mDataSize = src.mDataSize;
|
||||
mCopyBehavior = CopyBehavior::UseExternal;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ByteBuffer::clear()
|
||||
{
|
||||
mData.resize(0);
|
||||
mDataSize = 0;
|
||||
mDataPtr = nullptr;
|
||||
}
|
||||
|
||||
size_t ByteBuffer::size() const
|
||||
{
|
||||
return mDataSize;
|
||||
}
|
||||
|
||||
const uint8_t* ByteBuffer::data() const
|
||||
{
|
||||
return (const uint8_t*)mDataPtr;
|
||||
}
|
||||
|
||||
uint8_t* ByteBuffer::mutableData()
|
||||
{
|
||||
return mDataPtr;
|
||||
}
|
||||
|
||||
NetworkAddress& ByteBuffer::remoteAddress()
|
||||
{
|
||||
return mRemoteAddress;
|
||||
}
|
||||
|
||||
void ByteBuffer::setRemoteAddress(const NetworkAddress& addr)
|
||||
{
|
||||
mRemoteAddress = addr;
|
||||
}
|
||||
|
||||
void ByteBuffer::setComment(std::string comment)
|
||||
{
|
||||
mComment = comment;
|
||||
}
|
||||
|
||||
std::string ByteBuffer::comment()
|
||||
{
|
||||
return mComment;
|
||||
}
|
||||
|
||||
std::string ByteBuffer::hexstring()
|
||||
{
|
||||
std::string result;
|
||||
result.resize(mDataSize * 2, (char)0xCC);
|
||||
for (std::vector<uint8_t>::size_type index = 0; index < mDataSize; index++)
|
||||
{
|
||||
char value[3];
|
||||
sprintf(value, "%02X", (unsigned char)mDataPtr[index]);
|
||||
result[index*2] = value[0];
|
||||
result[index*2+1] = value[1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ByteBuffer::reserve(size_t capacity)
|
||||
{
|
||||
mData.reserve(capacity);
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
void ByteBuffer::insertTurnPrefix(unsigned short prefix)
|
||||
{
|
||||
assert(mCopyBehavior == CopyBehavior::CopyMemory);
|
||||
|
||||
mData.insert(mData.begin(), 2, 32);
|
||||
unsigned short nprefix = htons(prefix);
|
||||
mData[0] = nprefix & 0xFF;
|
||||
mData[1] = (nprefix & 0xFF00) >> 8;
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
int ByteBuffer::component()
|
||||
{
|
||||
return mComponent;
|
||||
}
|
||||
|
||||
void ByteBuffer::setComponent(int component)
|
||||
{
|
||||
mComponent = component;
|
||||
}
|
||||
|
||||
void ByteBuffer::truncate(size_t newsize)
|
||||
{
|
||||
assert (mCopyBehavior == CopyBehavior::CopyMemory);
|
||||
|
||||
mData.erase(mData.begin() + newsize, mData.end());
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
void ByteBuffer::erase(size_t p, size_t l)
|
||||
{
|
||||
assert (mCopyBehavior == CopyBehavior::CopyMemory);
|
||||
|
||||
mData.erase(mData.begin()+p, mData.begin()+p+l);
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
void ByteBuffer::resize(size_t newsize)
|
||||
{
|
||||
assert (mCopyBehavior == CopyBehavior::CopyMemory);
|
||||
|
||||
std::vector<uint8_t>::size_type sz = mData.size();
|
||||
mData.resize(newsize);
|
||||
if (newsize > sz)
|
||||
memset(&mData[sz], 0, newsize - sz);
|
||||
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
void ByteBuffer::appendBuffer(const void *data, size_t size)
|
||||
{
|
||||
assert (mCopyBehavior == CopyBehavior::CopyMemory);
|
||||
|
||||
size_t len = mData.size();
|
||||
mData.resize(len + size);
|
||||
memmove(mData.data() + len, data, size);
|
||||
syncPointer();
|
||||
}
|
||||
|
||||
void* ByteBuffer::tag()
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
void ByteBuffer::setTag(void* tag)
|
||||
{
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
bool ByteBuffer::relayed()
|
||||
{
|
||||
return mRelayed;
|
||||
}
|
||||
|
||||
void ByteBuffer::setRelayed(bool value)
|
||||
{
|
||||
mRelayed = value;
|
||||
}
|
||||
|
||||
void ByteBuffer::initEmpty()
|
||||
{
|
||||
mDataPtr = nullptr;
|
||||
mDataSize = 0;
|
||||
mCopyBehavior = CopyBehavior::CopyMemory;
|
||||
mRelayed = false;
|
||||
mComponent = -1;
|
||||
mTag = nullptr;
|
||||
}
|
||||
|
||||
void ByteBuffer::syncPointer()
|
||||
{
|
||||
mDataPtr = mData.empty() ? nullptr : &mData[0];
|
||||
mDataSize = mData.size();
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::operator[](int index) const
|
||||
{
|
||||
return mDataPtr[index];
|
||||
}
|
||||
|
||||
uint8_t& ByteBuffer::operator[](int index)
|
||||
{
|
||||
return mDataPtr[index];
|
||||
}
|
||||
|
||||
// ----------------- BitReader -------------------
|
||||
BitReader::BitReader(const ByteBuffer &buffer)
|
||||
:mStream(buffer.data()), mStreamLen(buffer.size()), mStreamOffset(0), mCurrentBit(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
BitReader::BitReader(const void *input, size_t bytes)
|
||||
:mStream((const uint8_t*)input), mStreamLen(bytes), mStreamOffset(0), mCurrentBit(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void BitReader::init()
|
||||
{
|
||||
mStreamOffset = mStreamLen << 3;
|
||||
mCurrentPosition = 0;//mStreamOffset - 1;
|
||||
mCurrentBit = 0;
|
||||
}
|
||||
|
||||
BitReader::~BitReader()
|
||||
{}
|
||||
|
||||
// Check for valid position
|
||||
uint8_t BitReader::readBit()
|
||||
{
|
||||
uint8_t value = 0x00;
|
||||
if (mCurrentPosition < mStreamOffset)
|
||||
{
|
||||
// Read single BIT
|
||||
size_t currentByte = mCurrentPosition >> 3;
|
||||
uint8_t currentBit = (uint8_t)(mCurrentPosition % 8);
|
||||
value = ((uint8_t)(mStream[currentByte] << currentBit) >> 7);
|
||||
mCurrentPosition = std::max((size_t)0, std::min(mStreamOffset-1, mCurrentPosition+1));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t BitReader::readBits(size_t nrOfBits)
|
||||
{
|
||||
assert (nrOfBits <= 32);
|
||||
|
||||
uint32_t result = 0;
|
||||
BitWriter bw(&result);
|
||||
for (int i=0; i<(int)nrOfBits; i++)
|
||||
bw.writeBit(readBit());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t BitReader::readBits(void *output, size_t nrOfBits)
|
||||
{
|
||||
// Check how much bits available
|
||||
nrOfBits = std::min(nrOfBits, mStreamOffset - mCurrentPosition);
|
||||
|
||||
BitWriter bw(output);
|
||||
for (int i=0; i<(int)nrOfBits; i++)
|
||||
bw.writeBit(readBit());
|
||||
|
||||
return nrOfBits;
|
||||
}
|
||||
|
||||
size_t BitReader::count() const
|
||||
{
|
||||
return mStreamOffset;
|
||||
}
|
||||
|
||||
size_t BitReader::position() const
|
||||
{
|
||||
return mCurrentPosition;
|
||||
}
|
||||
|
||||
// ----------------- BitWriter -------------------
|
||||
BitWriter::BitWriter(ByteBuffer &buffer)
|
||||
:mStream(buffer.mutableData()), mStreamLen(0), mStreamOffset(0), mCurrentBit(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
BitWriter::BitWriter(void *output)
|
||||
:mStream((uint8_t*)output), mStreamLen(0), mStreamOffset(0), mCurrentBit(0)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void BitWriter::init()
|
||||
{
|
||||
mStreamOffset = mStreamLen << 3;
|
||||
mCurrentPosition = 0;//mStreamOffset - 1;
|
||||
mCurrentBit = 0;
|
||||
}
|
||||
|
||||
BitWriter::~BitWriter()
|
||||
{}
|
||||
|
||||
BitWriter& BitWriter::writeBit(int bit)
|
||||
{
|
||||
bit = bit ? 1 : 0;
|
||||
|
||||
// Check for current bit offset
|
||||
if ((mCurrentBit % 8) == 0)
|
||||
{
|
||||
// Write new zero byte to the end of stream
|
||||
mCurrentBit = 0;
|
||||
mStreamLen++;
|
||||
mStream[mStreamLen-1] = 0;
|
||||
}
|
||||
|
||||
// Write single BIT
|
||||
mStream[mStreamLen-1] <<= 1;
|
||||
mStream[mStreamLen-1] |= bit;
|
||||
mStreamOffset++;
|
||||
mCurrentPosition = mStreamOffset - 1;
|
||||
mCurrentBit++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t BitWriter::count() const
|
||||
{
|
||||
return mStreamOffset;
|
||||
}
|
||||
|
||||
// ----------------- BufferReader ----------------
|
||||
BufferReader::BufferReader(const ByteBuffer &buffer)
|
||||
:mData(buffer.data()), mSize(buffer.size()), mIndex(0)
|
||||
{}
|
||||
|
||||
BufferReader::BufferReader(const void *input, size_t bytes)
|
||||
:mData((const uint8_t*)input), mSize(bytes), mIndex(0)
|
||||
{}
|
||||
|
||||
|
||||
uint32_t BufferReader::readUInt()
|
||||
{
|
||||
uint32_t nresult = 0;
|
||||
readBuffer(&nresult, 4);
|
||||
|
||||
return ntohl(nresult);
|
||||
}
|
||||
|
||||
uint32_t BufferReader::readNativeUInt()
|
||||
{
|
||||
uint32_t nresult = 0;
|
||||
readBuffer(&nresult, 4);
|
||||
|
||||
return nresult;
|
||||
}
|
||||
|
||||
uint16_t BufferReader::readUShort()
|
||||
{
|
||||
uint16_t result = 0;
|
||||
readBuffer(&result, 2);
|
||||
|
||||
return ntohs(result);
|
||||
}
|
||||
|
||||
uint16_t BufferReader::readNativeUShort()
|
||||
{
|
||||
uint16_t result = 0;
|
||||
readBuffer(&result, 2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t BufferReader::readUChar()
|
||||
{
|
||||
uint8_t result = 0;
|
||||
readBuffer(&result, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NetworkAddress BufferReader::readIp(int family)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = 0;
|
||||
readBuffer(&addr.sin_addr.s_addr, 4);
|
||||
|
||||
return NetworkAddress((sockaddr&)addr, sizeof(addr));
|
||||
}
|
||||
else
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
sockaddr_in6 addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = 0;
|
||||
readBuffer(&addr.sin6_addr, 16);
|
||||
|
||||
return NetworkAddress((sockaddr&)addr, sizeof(addr));
|
||||
}
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
size_t BufferReader::readBuffer(void* dataPtr, size_t dataSize)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
size_t available = mSize - mIndex;
|
||||
if (available < dataSize)
|
||||
dataSize = available;
|
||||
if (NULL != dataPtr)
|
||||
memcpy(dataPtr, mData + mIndex, dataSize);
|
||||
|
||||
mIndex += dataSize;
|
||||
return dataSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t BufferReader::readBuffer(ByteBuffer& bb, size_t dataSize)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
// Find how much data are available in fact
|
||||
size_t available = mSize - mIndex;
|
||||
if (available < dataSize)
|
||||
dataSize = available;
|
||||
|
||||
// Extend byte buffer
|
||||
size_t startIndex = bb.size();
|
||||
bb.resize(bb.size() + dataSize);
|
||||
memcpy(bb.mutableData() + startIndex, mData + mIndex, dataSize);
|
||||
mIndex += dataSize;
|
||||
return dataSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t BufferReader::count() const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
// -------------- BufferWriter ----------------------
|
||||
BufferWriter::BufferWriter(ByteBuffer &buffer)
|
||||
:mData(buffer.mutableData()), mIndex(0)
|
||||
{}
|
||||
|
||||
BufferWriter::BufferWriter(void *output)
|
||||
:mData((uint8_t*)output), mIndex(0)
|
||||
{}
|
||||
|
||||
|
||||
void BufferWriter::writeUInt(uint32_t value)
|
||||
{
|
||||
// Convert to network order bytes
|
||||
uint32_t nvalue = htonl(value);
|
||||
|
||||
writeBuffer(&nvalue, 4);
|
||||
}
|
||||
|
||||
|
||||
void BufferWriter::writeUShort(uint16_t value)
|
||||
{
|
||||
uint16_t nvalue = htons(value);
|
||||
writeBuffer(&nvalue, 2);
|
||||
}
|
||||
|
||||
void BufferWriter::writeUChar(uint8_t value)
|
||||
{
|
||||
writeBuffer(&value, 1);
|
||||
}
|
||||
|
||||
void BufferWriter::writeIp(const NetworkAddress& ip)
|
||||
{
|
||||
switch (ip.stunType())
|
||||
{
|
||||
case 1/*IPv4*/:
|
||||
writeBuffer(&ip.sockaddr4()->sin_addr, 4);
|
||||
break;
|
||||
|
||||
case 2/*IPv6*/:
|
||||
writeBuffer(&ip.sockaddr6()->sin6_addr, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void BufferWriter::writeBuffer(const void* dataPtr, size_t dataSize)
|
||||
{
|
||||
memmove(mData + mIndex, dataPtr, dataSize);
|
||||
mIndex += dataSize;
|
||||
}
|
||||
|
||||
void BufferWriter::rewind()
|
||||
{
|
||||
mIndex = 0;
|
||||
}
|
||||
|
||||
void BufferWriter::skip(int count)
|
||||
{
|
||||
mIndex += count;
|
||||
}
|
||||
|
||||
size_t BufferWriter::offset() const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
187
src/libs/ice/ICEByteBuffer.h
Normal file
187
src/libs/ice/ICEByteBuffer.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/* Copyright(C) 2007-2016 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_BYTE_BUFFER_H
|
||||
#define __ICE_BYTE_BUFFER_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICETypes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "ICETypes.h"
|
||||
#include "ICEAddress.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class ByteBuffer
|
||||
{
|
||||
public:
|
||||
enum class CopyBehavior
|
||||
{
|
||||
CopyMemory,
|
||||
UseExternal
|
||||
};
|
||||
|
||||
ByteBuffer();
|
||||
ByteBuffer(size_t initialCapacity);
|
||||
ByteBuffer(const ByteBuffer& src);
|
||||
ByteBuffer(const void* packetPtr, size_t packetSize, CopyBehavior behavior = CopyBehavior::CopyMemory);
|
||||
~ByteBuffer();
|
||||
|
||||
ByteBuffer& operator = (const ByteBuffer& src);
|
||||
|
||||
void clear();
|
||||
|
||||
size_t size() const;
|
||||
const uint8_t* data() const;
|
||||
uint8_t* mutableData();
|
||||
|
||||
NetworkAddress& remoteAddress();
|
||||
void setRemoteAddress(const NetworkAddress& addr);
|
||||
int component();
|
||||
void setComponent(int component);
|
||||
void setComment(std::string comment);
|
||||
std::string comment();
|
||||
std::string hexstring();
|
||||
|
||||
void reserve(size_t capacity);
|
||||
void insertTurnPrefix(unsigned short prefix);
|
||||
void truncate(size_t newsize);
|
||||
void erase(size_t p, size_t l);
|
||||
void resize(size_t newsize);
|
||||
void appendBuffer(const void* data, size_t size);
|
||||
void* tag();
|
||||
void setTag(void* tag);
|
||||
void trim();
|
||||
bool relayed();
|
||||
void setRelayed(bool value);
|
||||
void syncPointer();
|
||||
|
||||
uint8_t operator[](int index) const;
|
||||
uint8_t& operator[](int index);
|
||||
|
||||
|
||||
protected:
|
||||
std::vector<uint8_t> mData; // Internal storage
|
||||
uint8_t* mDataPtr; // Pointer to internal storage or external data
|
||||
uint32_t mDataSize; // Used only for mCopyBehavior == UseExternal
|
||||
NetworkAddress mRemoteAddress; // Associates buffer with IP address
|
||||
int mComponent; // Associates buffer with component ID
|
||||
std::string mComment; // Comment's for this buffer - useful in debugging
|
||||
void* mTag; // User tag
|
||||
bool mRelayed; // Marks if buffer was received via relay
|
||||
CopyBehavior mCopyBehavior; // Determines if buffer manages internal or external data
|
||||
|
||||
void initEmpty();
|
||||
int bitsInBuffer(uint8_t bufferMask);
|
||||
};
|
||||
|
||||
|
||||
typedef std::shared_ptr<ByteBuffer> PByteBuffer;
|
||||
|
||||
class BitReader
|
||||
{
|
||||
protected:
|
||||
const uint8_t* mStream;
|
||||
size_t mStreamLen;
|
||||
size_t mStreamOffset;
|
||||
size_t mCurrentPosition;
|
||||
size_t mCurrentBit;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
BitReader(const void* input, size_t bytes);
|
||||
BitReader(const ByteBuffer& buffer);
|
||||
~BitReader();
|
||||
|
||||
uint8_t readBit();
|
||||
uint32_t readBits(size_t nrOfBits);
|
||||
size_t readBits(void* output, size_t nrOfBits);
|
||||
|
||||
size_t count() const;
|
||||
size_t position() const;
|
||||
};
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
protected:
|
||||
uint8_t* mStream;
|
||||
size_t mStreamLen;
|
||||
size_t mStreamOffset;
|
||||
size_t mCurrentPosition;
|
||||
size_t mCurrentBit;
|
||||
|
||||
void init();
|
||||
public:
|
||||
BitWriter(void* output);
|
||||
BitWriter(ByteBuffer& buffer);
|
||||
~BitWriter();
|
||||
|
||||
// Bit must be 0 or 1
|
||||
BitWriter& writeBit(int bit);
|
||||
size_t count() const;
|
||||
};
|
||||
|
||||
class BufferReader
|
||||
{
|
||||
protected:
|
||||
const uint8_t* mData;
|
||||
size_t mSize;
|
||||
size_t mIndex;
|
||||
|
||||
public:
|
||||
BufferReader(const void* input, size_t bytes);
|
||||
BufferReader(const ByteBuffer& buffer);
|
||||
|
||||
// This methods reads uint32_t from stream and converts network byte order to host byte order.
|
||||
uint32_t readUInt();
|
||||
|
||||
// This method reads uint32_t from stream. No conversion between byte orders.
|
||||
uint32_t readNativeUInt();
|
||||
|
||||
// This method reads uint16_t from stream and converts network byte order to host byte order.
|
||||
uint16_t readUShort();
|
||||
|
||||
// This method reads uint16_t. No conversion between byte orders.
|
||||
uint16_t readNativeUShort();
|
||||
uint8_t readUChar();
|
||||
|
||||
// Reads in_addr or in6_addr from stream and wraps it to NetworkAddress
|
||||
NetworkAddress readIp(int family);
|
||||
|
||||
// Reads to plain memory buffer
|
||||
size_t readBuffer(void* dataPtr, size_t dataSize);
|
||||
|
||||
// Read directly to byte buffer. New data will be appended to byte buffer
|
||||
size_t readBuffer(ByteBuffer& bb, size_t dataSize);
|
||||
|
||||
size_t count() const;
|
||||
};
|
||||
|
||||
class BufferWriter
|
||||
{
|
||||
protected:
|
||||
uint8_t* mData;
|
||||
size_t mIndex;
|
||||
|
||||
public:
|
||||
BufferWriter(void* output);
|
||||
BufferWriter(ByteBuffer& buffer);
|
||||
|
||||
void writeUInt(uint32_t value);
|
||||
void writeUShort(uint16_t value);
|
||||
void writeUChar(uint8_t value);
|
||||
void writeIp(const NetworkAddress& ip);
|
||||
void writeBuffer(const void* dataPtr, size_t dataSize);
|
||||
void rewind();
|
||||
void skip(int count);
|
||||
|
||||
size_t offset() const;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
177
src/libs/ice/ICECRC32.cpp
Normal file
177
src/libs/ice/ICECRC32.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _CCRC32_CPP
|
||||
#define _CCRC32_CPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ICECRC32.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
using namespace ice;
|
||||
|
||||
CRC32::CRC32(void)
|
||||
{
|
||||
this->initialize();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CRC32::~CRC32(void)
|
||||
{
|
||||
//No destructor code.
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
This function initializes "CRC Lookup Table". You only need to call it once to
|
||||
initalize the table before using any of the other CRC32 calculation functions.
|
||||
*/
|
||||
|
||||
void CRC32::initialize(void)
|
||||
{
|
||||
//0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet.
|
||||
unsigned long ulPolynomial = 0x04C11DB7;
|
||||
|
||||
//memset(&this->ulTable, 0, sizeof(this->ulTable));
|
||||
|
||||
// 256 values representing ASCII character codes.
|
||||
for(int iCodes = 0; iCodes <= 0xFF; iCodes++)
|
||||
{
|
||||
this->ulTable[iCodes] = this->reflect(iCodes, 8) << 24;
|
||||
|
||||
for(int iPos = 0; iPos < 8; iPos++)
|
||||
{
|
||||
this->ulTable[iCodes] = (this->ulTable[iCodes] << 1)
|
||||
^ ((this->ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0);
|
||||
}
|
||||
|
||||
this->ulTable[iCodes] = this->reflect(this->ulTable[iCodes], 32);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Reflection is a requirement for the official CRC-32 standard.
|
||||
You can create CRCs without it, but they won't conform to the standard.
|
||||
*/
|
||||
|
||||
unsigned long CRC32::reflect(unsigned long ulReflect, const char cChar)
|
||||
{
|
||||
unsigned long ulValue = 0;
|
||||
|
||||
// Swap bit 0 for bit 7, bit 1 For bit 6, etc....
|
||||
for(int iPos = 1; iPos < (cChar + 1); iPos++)
|
||||
{
|
||||
if(ulReflect & 1)
|
||||
{
|
||||
ulValue |= (1 << (cChar - iPos));
|
||||
}
|
||||
ulReflect >>= 1;
|
||||
}
|
||||
|
||||
return ulValue;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Calculates the CRC32 by looping through each of the bytes in sData.
|
||||
|
||||
Note: For Example usage example, see FileCRC().
|
||||
*/
|
||||
|
||||
void CRC32::partialCrc(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength)
|
||||
{
|
||||
while(ulDataLength--)
|
||||
{
|
||||
//If your compiler complains about the following line, try changing each
|
||||
// occurrence of *ulCRC with "((unsigned long)*ulCRC)" or "*(unsigned long *)ulCRC".
|
||||
|
||||
*(unsigned long *)ulCRC =
|
||||
((*(unsigned long *)ulCRC) >> 8) ^ this->ulTable[((*(unsigned long *)ulCRC) & 0xFF) ^ *sData++];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Returns the calculated CRC32 (through ulOutCRC) for the given string.
|
||||
*/
|
||||
|
||||
void CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLength, unsigned long *ulOutCRC)
|
||||
{
|
||||
*(unsigned long *)ulOutCRC = 0xffffffff; //Initilaize the CRC.
|
||||
this->partialCrc(ulOutCRC, sData, ulDataLength);
|
||||
*(unsigned long *)ulOutCRC ^= 0xffffffff; //Finalize the CRC.
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Returns the calculated CRC23 for the given string.
|
||||
*/
|
||||
|
||||
unsigned long CRC32::fullCrc(const unsigned char *sData, unsigned long ulDataLength)
|
||||
{
|
||||
unsigned long ulCRC = 0xffffffff; //Initilaize the CRC.
|
||||
this->partialCrc(&ulCRC, sData, ulDataLength);
|
||||
return(ulCRC ^ 0xffffffff); //Finalize the CRC and return.
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Calculates the CRC32 of a file using the a user defined buffer.
|
||||
|
||||
Note: The buffer size DOES NOT affect the resulting CRC,
|
||||
it has been provided for performance purposes only.
|
||||
*/
|
||||
|
||||
bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned long ulBufferSize)
|
||||
{
|
||||
*(unsigned long *)ulOutCRC = 0xffffffff; //Initilaize the CRC.
|
||||
|
||||
FILE *fSource = NULL;
|
||||
unsigned char *sBuf = NULL;
|
||||
int iBytesRead = 0;
|
||||
|
||||
if((fSource = fopen(sFileName, "rb")) == NULL)
|
||||
{
|
||||
return false; //Failed to open file for read access.
|
||||
}
|
||||
|
||||
if(!(sBuf = (unsigned char *)malloc(ulBufferSize))) //Allocate memory for file buffering.
|
||||
{
|
||||
fclose(fSource);
|
||||
return false; //Out of memory.
|
||||
}
|
||||
|
||||
while((iBytesRead = fread(sBuf, sizeof(char), ulBufferSize, fSource)))
|
||||
{
|
||||
this->partialCrc(ulOutCRC, sBuf, iBytesRead);
|
||||
}
|
||||
|
||||
free(sBuf);
|
||||
fclose(fSource);
|
||||
|
||||
*(unsigned long *)ulOutCRC ^= 0xffffffff; //Finalize the CRC.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Calculates the CRC32 of a file using the a default buffer size of 1MB.
|
||||
|
||||
Note: The buffer size DOES NOT affect the resulting CRC,
|
||||
it has been provided for performance purposes only.
|
||||
*/
|
||||
|
||||
bool CRC32::fileCrc(const char *sFileName, unsigned long *ulOutCRC)
|
||||
{
|
||||
return this->fileCrc(sFileName, ulOutCRC, 1048576);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
32
src/libs/ice/ICECRC32.h
Normal file
32
src/libs/ice/ICECRC32.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_CRC32_H
|
||||
#define __ICE_CRC32_H
|
||||
namespace ice
|
||||
{
|
||||
class CRC32
|
||||
{
|
||||
public:
|
||||
CRC32(void);
|
||||
~CRC32(void);
|
||||
|
||||
void initialize(void);
|
||||
|
||||
bool fileCrc(const char *sFileName, unsigned long *ulOutCRC);
|
||||
bool fileCrc(const char *sFileName, unsigned long *ulOutCRC, unsigned long ulBufferSize);
|
||||
|
||||
unsigned long fullCrc(const unsigned char *sData, unsigned long ulDataLength);
|
||||
void fullCrc(const unsigned char *sData, unsigned long ulLength, unsigned long *ulOutCRC);
|
||||
|
||||
void partialCrc(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength);
|
||||
|
||||
private:
|
||||
unsigned long reflect(unsigned long ulReflect, const char cChar);
|
||||
unsigned long ulTable[256]; // CRC lookup table array.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
188
src/libs/ice/ICECandidate.cpp
Normal file
188
src/libs/ice/ICECandidate.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICECandidate.h"
|
||||
#include "ICEError.h"
|
||||
#include "ICELog.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
void Candidate::setLocalAndExternalAddresses(std::string& ip, unsigned short portNumber)
|
||||
{
|
||||
mLocalAddr.setIp(ip);
|
||||
mLocalAddr.setPort(portNumber);
|
||||
mExternalAddr.setIp(ip);
|
||||
mExternalAddr.setPort(portNumber);
|
||||
}
|
||||
|
||||
void Candidate::setLocalAndExternalAddresses(NetworkAddress& addr)
|
||||
{
|
||||
mLocalAddr = addr;
|
||||
mExternalAddr = addr;
|
||||
}
|
||||
|
||||
void Candidate::setLocalAndExternalAddresses(NetworkAddress &addr, unsigned short altPort)
|
||||
{
|
||||
mLocalAddr = addr;
|
||||
mExternalAddr = addr;
|
||||
mLocalAddr.setPort(altPort);
|
||||
mExternalAddr.setPort(altPort);
|
||||
}
|
||||
|
||||
void Candidate::computePriority(int* typepreflist)
|
||||
{
|
||||
mPriority = (typepreflist[mType] << 24) + (mInterfacePriority << 8) + (256 - mComponentId);
|
||||
}
|
||||
|
||||
void Candidate::computeFoundation()
|
||||
{
|
||||
sprintf(mFoundation, "%u", unsigned((mType << 24) + inet_addr(mLocalAddr.ip().c_str())));
|
||||
}
|
||||
|
||||
const char* Candidate::type()
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case Candidate::Host:
|
||||
return "host";
|
||||
|
||||
case Candidate::ServerReflexive:
|
||||
return "srflx";
|
||||
|
||||
case Candidate::ServerRelayed:
|
||||
return "relay";
|
||||
|
||||
case Candidate::PeerReflexive:
|
||||
return "prflx";
|
||||
|
||||
default:
|
||||
ICELogCritical(<< "Bad candidate type, reverted to Host.");
|
||||
return "host";
|
||||
}
|
||||
}
|
||||
|
||||
std::string Candidate::createSdp()
|
||||
{
|
||||
char buffer[512];
|
||||
|
||||
unsigned port = (unsigned)mExternalAddr.port();
|
||||
|
||||
#define SDP_CANDIDATE_FORMAT "%s %u %s %u %s %u typ %s"
|
||||
|
||||
sprintf(buffer, SDP_CANDIDATE_FORMAT, strlen(mFoundation) ? mFoundation : "16777000" , mComponentId, "UDP", mPriority, mExternalAddr.ip().c_str(), port, type());
|
||||
|
||||
if (mType != Candidate::Host)
|
||||
{
|
||||
char relattr[64];
|
||||
sprintf(relattr, " raddr %s rport %u", mLocalAddr.ip().c_str(), (unsigned int)mLocalAddr.port());
|
||||
strcat(buffer, relattr);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Candidate Candidate::parseSdp(const char* sdp)
|
||||
{
|
||||
Candidate result(Candidate::Host);
|
||||
|
||||
char protocol[32], externalIP[128], candtype[32], raddr[64];
|
||||
unsigned int remoteport = 0;
|
||||
|
||||
unsigned int externalPort = 0;
|
||||
|
||||
// Look for "typ" string
|
||||
const char* formatstring;
|
||||
if (strstr(sdp, "typ"))
|
||||
formatstring = "%s %u %s %u %s %u typ %s raddr %s rport %u";
|
||||
else
|
||||
formatstring = "%s %u %s %u %s %u %s raddr %s rport %u";
|
||||
int wasread = sscanf(sdp, formatstring, &result.mFoundation, &result.mComponentId, protocol,
|
||||
&result.mPriority, externalIP, &externalPort, candtype, raddr, &remoteport);
|
||||
|
||||
if (wasread >= 7)
|
||||
{
|
||||
// Save external address
|
||||
result.mExternalAddr.setIp( externalIP );
|
||||
result.mExternalAddr.setPort( externalPort );
|
||||
|
||||
result.mLocalAddr = result.mExternalAddr;
|
||||
|
||||
// Check the protocol (UDP4/6 is supported only)
|
||||
#ifdef _WIN32
|
||||
_strupr(protocol); _strupr(candtype);
|
||||
#else
|
||||
strupr(protocol); strupr(candtype);
|
||||
#endif
|
||||
if (strcmp(protocol, "UDP") != 0)
|
||||
throw Exception(UDP_SUPPORTED_ONLY);
|
||||
|
||||
// Save candidate type
|
||||
result.mType = typeFromString(candtype);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Candidate::Type Candidate::typeFromString(const char* candtype)
|
||||
{
|
||||
if (!strcmp(candtype, "HOST"))
|
||||
return Candidate::Host;
|
||||
else
|
||||
if (!strcmp(candtype, "SRFLX"))
|
||||
return Candidate::ServerReflexive;
|
||||
else
|
||||
if (!strcmp(candtype, "PRFLX"))
|
||||
return Candidate::PeerReflexive;
|
||||
else
|
||||
if (!strcmp(candtype, "RELAY"))
|
||||
return Candidate::ServerRelayed;
|
||||
else
|
||||
{
|
||||
ICELogCritical(<< "Bad candidate type in parser. Reverted to Host");
|
||||
return Candidate::Host;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Candidate::equal(Candidate& cand1, Candidate& cand2)
|
||||
{
|
||||
if (cand1.mType != cand2.mType)
|
||||
return false;
|
||||
switch (cand1.mType)
|
||||
{
|
||||
case Candidate::Host:
|
||||
return (cand1.mLocalAddr == cand2.mLocalAddr);
|
||||
|
||||
case Candidate::ServerReflexive:
|
||||
case Candidate::PeerReflexive:
|
||||
case Candidate::ServerRelayed:
|
||||
return (cand1.mExternalAddr == cand2.mExternalAddr);
|
||||
|
||||
}
|
||||
|
||||
ICELogCritical(<< "Bad candidate type, comparing as Host");
|
||||
return cand1.mLocalAddr == cand2.mLocalAddr;
|
||||
}
|
||||
|
||||
bool Candidate::operator == (const Candidate& rhs) const
|
||||
{
|
||||
bool relayed1 = mType == ServerRelayed, relayed2 = rhs.mType == ServerRelayed;
|
||||
|
||||
return relayed1 == relayed2 && mLocalAddr == rhs.mLocalAddr && mExternalAddr == rhs.mExternalAddr;
|
||||
}
|
||||
|
||||
void Candidate::dump(std::ostream& output)
|
||||
{
|
||||
output << Logger::TabPrefix<< Logger::TabPrefix << createSdp().c_str() << std::endl;
|
||||
}
|
||||
|
||||
int Candidate::component()
|
||||
{
|
||||
return mComponentId;
|
||||
}
|
||||
113
src/libs/ice/ICECandidate.h
Normal file
113
src/libs/ice/ICECandidate.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_CANDIDATE_H
|
||||
#define __ICE_CANDIDATE_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICESmartPtr.h"
|
||||
#include "ICEAddress.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
struct Candidate
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
Host = 0,
|
||||
ServerReflexive = 1,
|
||||
PeerReflexive = 2,
|
||||
ServerRelayed = 3
|
||||
};
|
||||
|
||||
// Type of candidate - host, server reflexive/relayes or peer reflexive
|
||||
Type mType;
|
||||
|
||||
// External address
|
||||
NetworkAddress mExternalAddr;
|
||||
|
||||
// The component ID in ICE session
|
||||
int mComponentId;
|
||||
|
||||
// Mark the gathered candidate
|
||||
bool mReady;
|
||||
|
||||
// Mark the failed candidate - gathering is failed
|
||||
bool mFailed;
|
||||
|
||||
// The candidate priority
|
||||
unsigned int mPriority;
|
||||
|
||||
// Candidate's foundation
|
||||
char mFoundation[33];
|
||||
|
||||
// Interface priority
|
||||
unsigned int mInterfacePriority;
|
||||
|
||||
// Local used address
|
||||
NetworkAddress mLocalAddr;
|
||||
|
||||
Candidate()
|
||||
:mType(Host), mComponentId(0), mReady(false), mFailed(false), mPriority(0),
|
||||
mInterfacePriority(0)
|
||||
{
|
||||
memset(mFoundation, 0, sizeof mFoundation);
|
||||
}
|
||||
|
||||
/* Constructor.
|
||||
* @param _type Type of candidate - host, reflexive or relayed.
|
||||
* @param componentID ID of component where candidate is used.
|
||||
* @param portNumber Local port number.
|
||||
* @param ipAddress Local IP address.
|
||||
* @param interfacePriority Priority of specified interface.
|
||||
* @param startTimeout Start time for STUN/TURN checks. */
|
||||
Candidate(Type _type)
|
||||
: mType(_type), mComponentId(0), mReady(false), mFailed(false), mPriority(0),
|
||||
mInterfacePriority(0)
|
||||
{
|
||||
// Check if type is "host" - the candidate is ready in this case
|
||||
if (_type == Host)
|
||||
mReady = true;
|
||||
memset(mFoundation, 0, sizeof mFoundation);
|
||||
}
|
||||
|
||||
~Candidate()
|
||||
{}
|
||||
|
||||
// Sets local and external address simultaneously
|
||||
void setLocalAndExternalAddresses(std::string& ip, unsigned short portNumber);
|
||||
void setLocalAndExternalAddresses(NetworkAddress& addr);
|
||||
void setLocalAndExternalAddresses(NetworkAddress &addr, unsigned short altPort);
|
||||
|
||||
// Returns type of candidate as string - 'host', 'reflexive' or 'relayed'
|
||||
const char* type();
|
||||
|
||||
// Computes priority value basing on members and type priority list
|
||||
void computePriority(int* typepreflist);
|
||||
|
||||
// Updates foundation value depending on members
|
||||
void computeFoundation();
|
||||
|
||||
// Returns SDP line for this candidate
|
||||
std::string createSdp();
|
||||
|
||||
// Creates ICECandidate instance based on SDP line
|
||||
static Candidate parseSdp(const char* sdp);
|
||||
|
||||
// Returns candidate type basing on string type representation
|
||||
static Type typeFromString(const char* candtype);
|
||||
|
||||
// Compares if two candidates are equal
|
||||
static bool equal(Candidate& cand1, Candidate& cand2);
|
||||
|
||||
bool operator == (const Candidate& rhs) const;
|
||||
void dump(std::ostream& output);
|
||||
int component();
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
||||
223
src/libs/ice/ICECandidatePair.cpp
Normal file
223
src/libs/ice/ICECandidatePair.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICECandidatePair.h"
|
||||
#include "ICEBinding.h"
|
||||
#include "ICERelaying.h"
|
||||
#include "ICELog.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace ice;
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
CandidatePair::CandidatePair()
|
||||
:mPriority(0), mState(CandidatePair::Frozen), mControlledIndex(0), mControllingIndex(1),
|
||||
mNomination(Nomination_None), mRole(Regular), mTransaction(NULL)
|
||||
{
|
||||
memset(mFoundation, 0, sizeof mFoundation);
|
||||
}
|
||||
|
||||
CandidatePair::CandidatePair(const CandidatePair& src)
|
||||
:mPriority(src.mPriority), mState(src.mState), mControlledIndex(src.mControlledIndex),
|
||||
mControllingIndex(src.mControllingIndex), mNomination(src.mNomination),
|
||||
mRole(src.mRole), mTransaction(src.mTransaction)
|
||||
{
|
||||
mCandidate[0] = src.mCandidate[0];
|
||||
mCandidate[1] = src.mCandidate[1];
|
||||
memcpy(mFoundation, src.mFoundation, sizeof mFoundation);
|
||||
}
|
||||
|
||||
CandidatePair& CandidatePair::operator = (const CandidatePair& src)
|
||||
{
|
||||
mPriority = src.mPriority;
|
||||
mState = src.mState;
|
||||
memcpy(mFoundation, src.mFoundation, sizeof mFoundation);
|
||||
mControlledIndex = src.mControlledIndex;
|
||||
mControllingIndex = src.mControllingIndex;
|
||||
mNomination = src.mNomination;
|
||||
mTransaction = src.mTransaction;
|
||||
mRole = src.mRole;
|
||||
mCandidate[0] = src.mCandidate[0];
|
||||
mCandidate[1] = src.mCandidate[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
CandidatePair::~CandidatePair()
|
||||
{
|
||||
}
|
||||
|
||||
const char* CandidatePair::stateToString(State s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case Waiting: return "Waiting";
|
||||
case InProgress: return "InProgress";
|
||||
case Succeeded: return "Succeeded";
|
||||
case Failed: return "Failed";
|
||||
case Frozen: return "Frozen";
|
||||
}
|
||||
return "UNEXPECTED";
|
||||
}
|
||||
|
||||
const char* CandidatePair::nominationToString(ice::CandidatePair::Nomination n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case Nomination_None: return "nomination:none";
|
||||
case Nomination_Started: return "nomination:started";
|
||||
case Nomination_Finished: return "nomination:finished";
|
||||
}
|
||||
return "nomination:bad";
|
||||
}
|
||||
|
||||
void CandidatePair::updatePriority()
|
||||
{
|
||||
unsigned int G = mCandidate[mControllingIndex].mPriority;
|
||||
unsigned int D = mCandidate[mControlledIndex].mPriority;
|
||||
// As RFC says...
|
||||
mPriority = 0xFFFFFFFF * MINVALUE(G, D) + 2*MAXVALUE(G,D) + ((G>D)?1:0);
|
||||
|
||||
// ICELogDebug(<< "G=" << G << ", D=" << D << ", priority=" << mPriority);
|
||||
}
|
||||
|
||||
void CandidatePair::updateFoundation()
|
||||
{
|
||||
// Get a combination of controlling and controlled foundations
|
||||
strcpy(mFoundation, mCandidate[mControlledIndex].mFoundation);
|
||||
strcat(mFoundation, mCandidate[mControlledIndex].mFoundation);
|
||||
}
|
||||
|
||||
bool CandidatePair::operator == (const CandidatePair& rhs) const
|
||||
{
|
||||
return this->mCandidate[0] == rhs.mCandidate[0] && this->mCandidate[1] == rhs.mCandidate[1];
|
||||
}
|
||||
|
||||
const char* CandidatePair::roleToString(Role r)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case Regular: return "regular";
|
||||
case Triggered: return "triggered";
|
||||
case Valid: return "valid";
|
||||
case None: return "none";
|
||||
}
|
||||
return "UNEXPECTED";
|
||||
}
|
||||
|
||||
std::string CandidatePair::toStdString()
|
||||
{
|
||||
char result[256];
|
||||
|
||||
sprintf(result, "(%s%s) %s %s -> %s %s ", roleToString(mRole), nominationToString(mNomination),
|
||||
mCandidate[0].type(), mCandidate[0].mLocalAddr.toStdString().c_str(), mCandidate[1].type(),
|
||||
mCandidate[1].mExternalAddr.toStdString().c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CandidatePair::isLanOnly() const
|
||||
{
|
||||
return first().mLocalAddr.isLAN() &&
|
||||
second().mExternalAddr.isLAN();
|
||||
}
|
||||
|
||||
CandidatePair::Role CandidatePair::role() const
|
||||
{
|
||||
return mRole;
|
||||
};
|
||||
|
||||
void CandidatePair::setRole(Role role)
|
||||
{
|
||||
mRole = role;
|
||||
}
|
||||
|
||||
CandidatePair::Nomination CandidatePair::nomination() const
|
||||
{
|
||||
return mNomination;
|
||||
}
|
||||
|
||||
void CandidatePair::setNomination(ice::CandidatePair::Nomination n)
|
||||
{
|
||||
mNomination = n;
|
||||
}
|
||||
|
||||
const char* CandidatePair::foundation() const
|
||||
{
|
||||
return mFoundation;
|
||||
};
|
||||
|
||||
void CandidatePair::setFoundation(const char* foundation)
|
||||
{
|
||||
strcpy(mFoundation, foundation);
|
||||
}
|
||||
|
||||
CandidatePair::State CandidatePair::state() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void CandidatePair::setState(CandidatePair::State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
int64_t CandidatePair::priority() const
|
||||
{
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
void CandidatePair::setPriority(int64_t priority)
|
||||
{
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
Candidate& CandidatePair::first()
|
||||
{
|
||||
return mCandidate[0];
|
||||
}
|
||||
|
||||
const Candidate& CandidatePair::first() const
|
||||
{
|
||||
return mCandidate[0];
|
||||
}
|
||||
|
||||
Candidate& CandidatePair::second()
|
||||
{
|
||||
return mCandidate[1];
|
||||
}
|
||||
|
||||
const Candidate& CandidatePair::second() const
|
||||
{
|
||||
return mCandidate[1];
|
||||
}
|
||||
unsigned CandidatePair::controlledIndex()
|
||||
{
|
||||
return mControlledIndex;
|
||||
}
|
||||
|
||||
void CandidatePair::setControlledIndex(unsigned index)
|
||||
{
|
||||
mControlledIndex = index;
|
||||
}
|
||||
|
||||
unsigned CandidatePair::controllingIndex()
|
||||
{
|
||||
return mControllingIndex;
|
||||
}
|
||||
|
||||
void CandidatePair::setControllingIndex(unsigned index)
|
||||
{
|
||||
mControllingIndex = index;
|
||||
}
|
||||
|
||||
void* CandidatePair::transaction()
|
||||
{
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
void CandidatePair::setTransaction(void* t)
|
||||
{
|
||||
mTransaction = t;
|
||||
}
|
||||
113
src/libs/ice/ICECandidatePair.h
Normal file
113
src/libs/ice/ICECandidatePair.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_CANDIDATE_PAIR_H
|
||||
#define __ICE_CANDIDATE_PAIR_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICECandidate.h"
|
||||
#include "ICEByteBuffer.h"
|
||||
#include "ICESmartPtr.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class CandidatePair
|
||||
{
|
||||
public:
|
||||
/// Possible pair states
|
||||
enum State
|
||||
{
|
||||
Waiting = 0,
|
||||
InProgress,
|
||||
Succeeded,
|
||||
Failed,
|
||||
Frozen
|
||||
};
|
||||
|
||||
enum Role
|
||||
{
|
||||
None = 0,
|
||||
Regular = 1,
|
||||
Triggered = 2,
|
||||
Valid = 3
|
||||
};
|
||||
|
||||
enum Nomination
|
||||
{
|
||||
Nomination_None,
|
||||
Nomination_Started,
|
||||
Nomination_Finished
|
||||
};
|
||||
|
||||
static const char* stateToString(State s);
|
||||
static const char* nominationToString(Nomination n);
|
||||
|
||||
|
||||
protected:
|
||||
/// Local and remote candidates. First (zero index) is local candidate, second (index one) is remote candidate
|
||||
Candidate mCandidate[2];
|
||||
|
||||
/// Pair's priority, computed in UpdatePriority() method
|
||||
int64_t mPriority;
|
||||
|
||||
/// Pair's state
|
||||
State mState;
|
||||
|
||||
/// Index of controlled candidate in mCandidate array
|
||||
int mControlledIndex;
|
||||
|
||||
/// Index of controlling candidate in mCandidate array
|
||||
int mControllingIndex;
|
||||
|
||||
/// Combination of controlled and controlling candidates foundations, computed in UpdateFoundation() method.
|
||||
char mFoundation[65];
|
||||
|
||||
/// Marks nominated pair
|
||||
Nomination mNomination;
|
||||
|
||||
/// Mark pair role - regular, triggered, valid, nominated
|
||||
Role mRole;
|
||||
void* mTransaction;
|
||||
|
||||
static const char* roleToString(Role r);
|
||||
|
||||
public:
|
||||
CandidatePair();
|
||||
CandidatePair(const CandidatePair& src);
|
||||
~CandidatePair();
|
||||
|
||||
Candidate& first();
|
||||
const Candidate& first() const;
|
||||
Candidate& second();
|
||||
const Candidate& second() const;
|
||||
|
||||
int64_t priority() const;
|
||||
void setPriority(int64_t priority);
|
||||
State state() const;
|
||||
void setState(State state);
|
||||
const char* foundation() const;
|
||||
void setFoundation(const char* foundation);
|
||||
Role role() const;
|
||||
void setRole(Role role);
|
||||
Nomination nomination() const;
|
||||
void setNomination(Nomination n);
|
||||
unsigned controlledIndex();
|
||||
void setControlledIndex(unsigned index);
|
||||
unsigned controllingIndex();
|
||||
void setControllingIndex(unsigned index);
|
||||
void updatePriority();
|
||||
void updateFoundation();
|
||||
std::string toStdString();
|
||||
bool isLanOnly() const;
|
||||
|
||||
void* transaction();
|
||||
void setTransaction(void* t);
|
||||
CandidatePair& operator = (const CandidatePair& rhs);
|
||||
bool operator == (const CandidatePair& rhs) const;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<CandidatePair> PCandidatePair;
|
||||
}
|
||||
#endif
|
||||
436
src/libs/ice/ICECheckList.cpp
Normal file
436
src/libs/ice/ICECheckList.cpp
Normal file
@@ -0,0 +1,436 @@
|
||||
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICECheckList.h"
|
||||
#include "ICENetworkHelper.h"
|
||||
#include "ICELog.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <strstream>
|
||||
|
||||
using namespace ice;
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
const char* CheckList::stateToString(int state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case Running: return "Running";
|
||||
case Completed: return "Completed";
|
||||
case Failed: return "Failed";
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
CheckList::CheckList()
|
||||
:mState(CheckList::Running)
|
||||
{
|
||||
}
|
||||
|
||||
CheckList::State CheckList::state()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void CheckList::setState(CheckList::State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
CheckList::PairList& CheckList::pairlist()
|
||||
{
|
||||
return mPairList;
|
||||
}
|
||||
|
||||
static bool ComparePairByPriority(const PCandidatePair& pair1, const PCandidatePair& pair2)
|
||||
{
|
||||
return pair1->priority() > pair2->priority();
|
||||
}
|
||||
|
||||
void CheckList::pruneDuplicates()
|
||||
{
|
||||
// Remove duplicates
|
||||
for (PairList::iterator pairIter = mPairList.begin(); pairIter != mPairList.end(); pairIter++)
|
||||
{
|
||||
PCandidatePair& pair = *pairIter;
|
||||
|
||||
// Get the iterator to next element
|
||||
PairList::iterator nextPairIter = pairIter; std::advance(nextPairIter, 1);
|
||||
|
||||
// Iterate next elements to find duplicates
|
||||
while (nextPairIter != mPairList.end())
|
||||
{
|
||||
PCandidatePair& nextPair = *nextPairIter;
|
||||
|
||||
bool sameType = pair->first().mLocalAddr.family() == nextPair->second().mLocalAddr.family();
|
||||
bool sameAddress = pair->second().mExternalAddr == nextPair->second().mExternalAddr;
|
||||
bool relayed1 = pair->first().mType == Candidate::ServerRelayed;
|
||||
bool relayed2 = nextPair->first().mType == Candidate::ServerRelayed;
|
||||
bool sameRelayed = relayed1 == relayed2;
|
||||
#ifdef ICE_SMART_PRUNE_CHECKLIST
|
||||
if (sameType && sameAddress && sameRelayed)
|
||||
#else
|
||||
if (equalCandidates && sameAddress && sameRelayed)
|
||||
#endif
|
||||
nextPairIter = mPairList.erase(nextPairIter);
|
||||
else
|
||||
nextPairIter++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CheckList::prune(int /*checkLimit*/)
|
||||
{
|
||||
// Sort list by priority
|
||||
std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority);
|
||||
|
||||
// Replace server reflexive candidates with bases
|
||||
for (unsigned ci=0; ci<mPairList.size(); ci++)
|
||||
{
|
||||
PCandidatePair& pair = mPairList[ci];
|
||||
if (pair->first().mType == Candidate::ServerReflexive)
|
||||
pair->first().mType = Candidate::Host;
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
Win32Preprocess();
|
||||
#endif
|
||||
*/
|
||||
|
||||
pruneDuplicates();
|
||||
|
||||
// Erase all relayed checks to LAN candidates
|
||||
PairList::iterator pairIter = mPairList.begin();
|
||||
while (pairIter != mPairList.end())
|
||||
{
|
||||
PCandidatePair& pair = *pairIter;
|
||||
if (pair->first().mType == Candidate::ServerRelayed && !pair->second().mExternalAddr.isPublic())
|
||||
pairIter = mPairList.erase(pairIter);
|
||||
else
|
||||
pairIter++;
|
||||
}
|
||||
|
||||
#ifndef ICE_LOOPBACK_SUPPORT
|
||||
pairIter = mPairList.begin();
|
||||
while (pairIter != mPairList.end())
|
||||
{
|
||||
PCandidatePair& pair = *pairIter;
|
||||
if (pair->second().mExternalAddr.isLoopback())
|
||||
pairIter = mPairList.erase(pairIter);
|
||||
else
|
||||
pairIter++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ICE_SKIP_LINKLOCAL
|
||||
pairIter = mPairList.begin();
|
||||
while (pairIter != mPairList.end())
|
||||
{
|
||||
PCandidatePair& pair = *pairIter;
|
||||
if (pair->second().mExternalAddr.isLinkLocal())
|
||||
pairIter = mPairList.erase(pairIter);
|
||||
else
|
||||
pairIter++;
|
||||
}
|
||||
#endif
|
||||
pruneDuplicates();
|
||||
|
||||
#ifdef ICE_POSTPONE_RELAYEDCHECKS
|
||||
postponeRelayed();
|
||||
#endif
|
||||
|
||||
// Put all LAN checks before other.
|
||||
// Therefore it should be priorities sorting should be enough.
|
||||
// But in answer's SDP remote peer can put external IP to the top of the list
|
||||
// It can cause its promote to the top of list of connectivity checks
|
||||
std::sort(mPairList.begin(), mPairList.end(), [](const PCandidatePair& p1, const PCandidatePair& p2) -> bool
|
||||
{
|
||||
return p1->isLanOnly() && !p2->isLanOnly();
|
||||
});
|
||||
|
||||
// Cut all checks that are behind the limit
|
||||
if (mPairList.size() > ICE_CONNCHECK_LIMIT)
|
||||
{
|
||||
ICELogDebug(<<"Cut extra connection checks. The total number of checks should not exceed " << ICE_CONNCHECK_LIMIT);
|
||||
PairList::iterator bcIter = mPairList.begin();
|
||||
std::advance(bcIter, ICE_CONNCHECK_LIMIT);
|
||||
mPairList.erase(bcIter, mPairList.end());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckList::win32Preprocess()
|
||||
{
|
||||
for (unsigned i=0; i<mPairList.size(); i++)
|
||||
{
|
||||
PCandidatePair& pair = mPairList[i];
|
||||
ICELogDebug(<<"Win32Preprocess pair " << pair->toStdString());
|
||||
|
||||
if (pair->first().mType == Candidate::Host)
|
||||
{
|
||||
// Get best source interface for remote candidate
|
||||
NetworkAddress bestInterface = NetworkHelper::instance().sourceInterface(pair->second().mExternalAddr);
|
||||
|
||||
// Replace IP address to found
|
||||
if (!bestInterface.isEmpty())
|
||||
pair->first().mLocalAddr.setIp(bestInterface.ip());
|
||||
else
|
||||
ICELogDebug(<<"Failed to find source interface for remote candidate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findEqualPair(CandidatePair& _pair, ComparisionType ct)
|
||||
{
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
if (p->role() != CandidatePair::None)
|
||||
{
|
||||
switch (ct)
|
||||
{
|
||||
case CT_TreatHostAsUniform:
|
||||
if (p->first().mType == Candidate::Host && _pair.first().mType == Candidate::Host && p->second() == _pair.second())
|
||||
return p;
|
||||
if (p->first().mLocalAddr == _pair.first().mLocalAddr && p->first().mType == Candidate::Host && p->second() == _pair.second() && _pair.first().mType != Candidate::ServerRelayed)
|
||||
return p;
|
||||
if (_pair == *p)
|
||||
return p;
|
||||
|
||||
break;
|
||||
|
||||
case CT_Strict:
|
||||
if (_pair == *p)
|
||||
return p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PCandidatePair();
|
||||
}
|
||||
|
||||
unsigned CheckList::add(CandidatePair& p)
|
||||
{
|
||||
mPairList.push_back(PCandidatePair(new CandidatePair(p)));
|
||||
|
||||
// Sort list by priority
|
||||
std::sort(mPairList.begin(), mPairList.end(), ComparePairByPriority);
|
||||
|
||||
return (unsigned)mPairList.size();
|
||||
}
|
||||
|
||||
unsigned CheckList::count()
|
||||
{
|
||||
return (unsigned)mPairList.size();
|
||||
}
|
||||
std::string CheckList::toStdString()
|
||||
{
|
||||
std::string dump = "";
|
||||
for (size_t i=0; i<mPairList.size(); i++)
|
||||
{
|
||||
dump += mPairList[i]->toStdString();
|
||||
dump += "\n";
|
||||
}
|
||||
|
||||
return dump;
|
||||
}
|
||||
|
||||
PCandidatePair& CheckList::operator[] (size_t index)
|
||||
{
|
||||
return mPairList[index];
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findNominatedPair(int component)
|
||||
{
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
if (p->first().component() == component &&
|
||||
p->role() != CandidatePair::None &&
|
||||
p->nomination() == CandidatePair::Nomination_Finished)
|
||||
return p;
|
||||
}
|
||||
return PCandidatePair();
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findValidPair(int component)
|
||||
{
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
if (p->first().component() == component &&
|
||||
p->role() == CandidatePair::Valid)
|
||||
return p;
|
||||
}
|
||||
return PCandidatePair();
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findBestValidPair(int componentId)
|
||||
{
|
||||
PairList found;
|
||||
std::copy_if(mPairList.begin(), mPairList.end(), std::back_inserter(found),
|
||||
[componentId](const PCandidatePair& p) -> bool
|
||||
{
|
||||
return (p->first().component() == componentId &&
|
||||
p->role() == CandidatePair::Valid &&
|
||||
p->first().mExternalAddr.isLAN() &&
|
||||
p->second().mExternalAddr.isLAN());
|
||||
});
|
||||
|
||||
if (found.size())
|
||||
return found.front();
|
||||
|
||||
return findValidPair(componentId);
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findHighestNominatedPair(int component)
|
||||
{
|
||||
#ifdef ICE_POSTPONE_RELAYEDCHECKS
|
||||
PairList found;
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
if (p->first().component() == component &&
|
||||
p->role() != CandidatePair::None &&
|
||||
p->nomination() == CandidatePair::Nomination_Finished &&
|
||||
p->first().mType != Candidate::ServerRelayed &&
|
||||
p->second().mType != Candidate::ServerRelayed)
|
||||
found.push_back( p );
|
||||
}
|
||||
|
||||
if (found.size())
|
||||
{
|
||||
PCandidatePair& f0 = found.front();
|
||||
for (PCandidatePair& p: mPairList)
|
||||
if (p == f0)
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
int64_t priority = -1;
|
||||
PCandidatePair result;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Looking for highest nominated pair in list:";
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
oss << "\n " << p->toStdString().c_str() << ", priority " << p->priority();
|
||||
|
||||
if (p->first().component() == component &&
|
||||
p->role() != CandidatePair::None &&
|
||||
p->nomination() == CandidatePair::Nomination_Finished &&
|
||||
p->priority() > priority )
|
||||
{
|
||||
result = p;
|
||||
priority = p->priority();
|
||||
}
|
||||
}
|
||||
|
||||
// ICELogDebug( << oss.str() );
|
||||
|
||||
if (result)
|
||||
{
|
||||
ICELogDebug(<< "Result is " << result->toStdString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// ICELogDebug(<< "No nominated pair");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CheckList::removePairs(CandidatePair::State state, int component)
|
||||
{
|
||||
for (unsigned i=0; i<mPairList.size(); i++)
|
||||
{
|
||||
CandidatePair& p = *mPairList[i];
|
||||
if (p.first().component() == component &&
|
||||
p.state() == state &&
|
||||
p.role() != CandidatePair::None)
|
||||
p.setRole(CandidatePair::None);
|
||||
}
|
||||
}
|
||||
|
||||
PCandidatePair CheckList::findLowestNominatedPair(int component)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
int64_t priority = 0x7FFFFFFFFFFF;
|
||||
#else
|
||||
int64_t priority = 0x7FFFFFFFFFFFLL;
|
||||
#endif
|
||||
PCandidatePair result;
|
||||
|
||||
for (PCandidatePair& p: mPairList)
|
||||
{
|
||||
if (p->first().component() == component &&
|
||||
p->role() != CandidatePair::None &&
|
||||
p->nomination() == CandidatePair::Nomination_Finished &&
|
||||
p->priority() < priority )
|
||||
{
|
||||
result = p;
|
||||
priority = p->priority();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CheckList::updatePairPriorities()
|
||||
{
|
||||
for (unsigned i=0; i<mPairList.size(); i++)
|
||||
mPairList[i]->updatePriority();
|
||||
}
|
||||
|
||||
void CheckList::clear()
|
||||
{
|
||||
mState = Running;
|
||||
mPairList.clear();
|
||||
}
|
||||
|
||||
void CheckList::dump(std::ostream& output)
|
||||
{
|
||||
output << Logger::TabPrefix << Logger::TabPrefix << "State: " << CheckList::stateToString(mState) << std::endl;
|
||||
for (unsigned i=0; i<mPairList.size(); i++)
|
||||
if (mPairList[i]->role() != CandidatePair::None)
|
||||
output << Logger::TabPrefix << Logger::TabPrefix << mPairList[i]->toStdString().c_str() << std::endl;
|
||||
}
|
||||
|
||||
unsigned CheckList::countOfValidPairs()
|
||||
{
|
||||
unsigned result = 0;
|
||||
for (unsigned i=0; i<mPairList.size(); i++)
|
||||
if (mPairList[i]->role() >= CandidatePair::Valid)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
void CheckList::postponeRelayed()
|
||||
{
|
||||
PairList relayed, relayedTarget;
|
||||
|
||||
PairList::iterator pairIter = mPairList.begin();
|
||||
while ( pairIter != mPairList.end() )
|
||||
{
|
||||
PCandidatePair& p = *pairIter;
|
||||
if (p->first().mType == Candidate::ServerRelayed)
|
||||
{
|
||||
relayed.push_back(p);
|
||||
pairIter = mPairList.erase( pairIter );
|
||||
}
|
||||
else
|
||||
if (p->second().mType == Candidate::ServerRelayed)
|
||||
{
|
||||
relayedTarget.push_back(p);
|
||||
pairIter = mPairList.erase( pairIter );
|
||||
}
|
||||
else
|
||||
pairIter++;
|
||||
}
|
||||
|
||||
for (pairIter = relayedTarget.begin(); pairIter != relayedTarget.end(); pairIter++)
|
||||
mPairList.push_back(*pairIter);
|
||||
|
||||
for (pairIter = relayed.begin(); pairIter != relayed.end(); pairIter++)
|
||||
mPairList.push_back(*pairIter);
|
||||
}
|
||||
102
src/libs/ice/ICECheckList.h
Normal file
102
src/libs/ice/ICECheckList.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_CHECK_LIST_H
|
||||
#define __ICE_CHECK_LIST_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICECandidatePair.h"
|
||||
#include "ICESmartPtr.h"
|
||||
#include <vector>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class CheckList
|
||||
{
|
||||
public:
|
||||
enum State
|
||||
{
|
||||
Running = 0,
|
||||
Completed,
|
||||
Failed
|
||||
};
|
||||
static const char* stateToString(int state);
|
||||
typedef std::vector<PCandidatePair> PairList;
|
||||
|
||||
protected:
|
||||
/// Check list state
|
||||
State mState;
|
||||
|
||||
/// Vector of pairs
|
||||
PairList mPairList;
|
||||
|
||||
void pruneDuplicates();
|
||||
void postponeRelayed();
|
||||
|
||||
public:
|
||||
CheckList();
|
||||
|
||||
State state();
|
||||
void setState(State state);
|
||||
PairList& pairlist();
|
||||
|
||||
/// Sorts check list, prunes from duplicate pairs and cuts to checkLimit number of elements.
|
||||
void prune(int checkLimit);
|
||||
|
||||
/// Replaces local host candidates IP addresses with best source interface.
|
||||
void win32Preprocess();
|
||||
|
||||
/// Finds&returns smart pointer to pair
|
||||
enum ComparisionType
|
||||
{
|
||||
CT_TreatHostAsUniform,
|
||||
CT_Strict
|
||||
};
|
||||
PCandidatePair findEqualPair(CandidatePair& p, ComparisionType ct);
|
||||
|
||||
/// Add&sort
|
||||
unsigned add(CandidatePair& p);
|
||||
|
||||
/// Returns number of pairs in list
|
||||
unsigned count();
|
||||
|
||||
/// Returns items of list
|
||||
//ICECandidatePair operator[] (size_t index) const;
|
||||
PCandidatePair& operator[] (size_t index);
|
||||
|
||||
/// Dumps check list to string
|
||||
std::string toStdString();
|
||||
|
||||
/// Updates state of list based on items state
|
||||
void updateState();
|
||||
|
||||
/// Find first nominated pair for specified component ID
|
||||
PCandidatePair findNominatedPair(int componentID);
|
||||
|
||||
/// Finds valid pair for specified component ID. It is used for valid lists only.
|
||||
PCandidatePair findValidPair(int componentID);
|
||||
|
||||
/// Finds best valid pair for specified component ID. 'Best' means to prefer 1) LAN addresses 2) reflexive addresses 3)relayed addresses is low priority
|
||||
PCandidatePair findBestValidPair(int componentId);
|
||||
|
||||
/// Finds nominated pair with highest priority and specified component ID
|
||||
PCandidatePair findHighestNominatedPair(int componentID);
|
||||
|
||||
/// Finds nominated pair with highest priority and specified component ID
|
||||
PCandidatePair findLowestNominatedPair(int componentID);
|
||||
|
||||
/// Removes from list pairs with specified state and component ID.
|
||||
void removePairs(CandidatePair::State state, int componentID);
|
||||
|
||||
/// Recomputes pair priorities
|
||||
void updatePairPriorities();
|
||||
|
||||
void clear();
|
||||
void dump(std::ostream& output);
|
||||
unsigned countOfValidPairs();
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
84
src/libs/ice/ICEError.cpp
Normal file
84
src/libs/ice/ICEError.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEError.h"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
std::string ErrorInfo::errorMsg(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case 403: return "(Forbidden): The request was valid, but cannot be performed due \
|
||||
to administrative or similar restrictions.";
|
||||
|
||||
case 437: return "(Allocation Mismatch): A request was received by the server that \
|
||||
requires an allocation to be in place, but there is none, or a \
|
||||
request was received which requires no allocation, but there is \
|
||||
one.";
|
||||
|
||||
case 441: return "(Wrong Credentials): The credentials in the (non-Allocate) \
|
||||
request, though otherwise acceptable to the server, do not match \
|
||||
those used to create the allocation.";
|
||||
|
||||
case 442: return "(Unsupported Transport Protocol): The Allocate request asked the \
|
||||
server to use a transport protocol between the server and the peer \
|
||||
that the server does not support. NOTE: This does NOT refer to \
|
||||
the transport protocol used in the 5-tuple.";
|
||||
|
||||
case 486: return "(Allocation Quota Reached): No more allocations using this \
|
||||
username can be created at the present time.";
|
||||
|
||||
case 508: return "(Insufficient Capacity): The server is unable to carry out the \
|
||||
request due to some capacity limit being reached. In an Allocate \
|
||||
response, this could be due to the server having no more relayed \
|
||||
transport addresses available right now, or having none with the \
|
||||
requested properties, or the one that corresponds to the specified \
|
||||
reservation token is not available.";
|
||||
}
|
||||
|
||||
return "Unknown error.";
|
||||
|
||||
}
|
||||
|
||||
Exception::Exception(int errorCode, std::string errorMsg)
|
||||
:mErrorCode(errorCode), mSubcode(0), mErrorMsg(errorMsg)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(int code)
|
||||
:mErrorCode(code), mSubcode(0)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::Exception(int code, int subcode)
|
||||
:mErrorCode(code), mSubcode(subcode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Exception::Exception(const Exception& src)
|
||||
:mErrorCode(src.mErrorCode), mErrorMsg(src.mErrorMsg)
|
||||
{
|
||||
}
|
||||
|
||||
Exception::~Exception()
|
||||
{
|
||||
}
|
||||
|
||||
int Exception::code()
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
int Exception::subcode()
|
||||
{
|
||||
return mSubcode;
|
||||
}
|
||||
|
||||
std::string Exception::message()
|
||||
{
|
||||
return mErrorMsg;
|
||||
}
|
||||
57
src/libs/ice/ICEError.h
Normal file
57
src/libs/ice/ICEError.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_ERROR_H
|
||||
#define __ICE_ERROR_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
class ErrorInfo
|
||||
{
|
||||
public:
|
||||
static std::string errorMsg(int errorCode);
|
||||
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GETIFADDRS_FAILED = 1,
|
||||
WRONG_CANDIDATE_TYPE,
|
||||
UDP_SUPPORTED_ONLY,
|
||||
NOT_ENOUGH_DATA,
|
||||
CANNOT_FIND_INTERFACES,
|
||||
NO_PRIORITY_ATTRIBUTE,
|
||||
CANNOT_FIND_ATTRIBUTE,
|
||||
UNKNOWN_ATTRIBUTE,
|
||||
WRONG_IP_ADDRESS
|
||||
};
|
||||
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
|
||||
Exception(int code, std::string msg);
|
||||
Exception(int code);
|
||||
Exception(int code, int subcode);
|
||||
|
||||
Exception(const Exception& src);
|
||||
~Exception();
|
||||
|
||||
int code();
|
||||
int subcode();
|
||||
std::string message();
|
||||
|
||||
protected:
|
||||
int mErrorCode;
|
||||
int mSubcode;
|
||||
std::string mErrorMsg;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
62
src/libs/ice/ICEEvent.h
Normal file
62
src/libs/ice/ICEEvent.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_EVENT_H
|
||||
#define __ICE_EVENT_H
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class Stack;
|
||||
|
||||
class StageHandler
|
||||
{
|
||||
public:
|
||||
// Fires when candidates are gathered
|
||||
virtual void onGathered(Stack* stack, void* tag) = 0;
|
||||
|
||||
// Fires when connectivity checks finished ok
|
||||
virtual void onSuccess(Stack* stack, void* tag) = 0;
|
||||
|
||||
// Fires when connectivity checks failed (timeout usually)
|
||||
virtual void onFailed(Stack* stack, void* tag) = 0;
|
||||
};
|
||||
|
||||
class ChannelBoundCallback
|
||||
{
|
||||
public:
|
||||
virtual ~ChannelBoundCallback() {}
|
||||
virtual void onChannelBound(int /*stream*/, int /*component*/, int /*error*/) {}
|
||||
};
|
||||
|
||||
class InstallPermissionsCallback
|
||||
{
|
||||
public:
|
||||
virtual ~InstallPermissionsCallback() {}
|
||||
virtual void onPermissionsInstalled(int /*stream*/, int /*component*/, int /*error*/) {}
|
||||
};
|
||||
|
||||
class DeletePermissionsCallback
|
||||
{
|
||||
public:
|
||||
virtual ~DeletePermissionsCallback() {}
|
||||
virtual void onPermissionsDeleted(int /*stream*/, int /*component*/, int /*error*/) {}
|
||||
};
|
||||
|
||||
class DeleteAllocationCallback
|
||||
{
|
||||
public:
|
||||
virtual ~DeleteAllocationCallback() {}
|
||||
virtual void onAllocationDeleted(int /*stream*/, int /*component*/, int /*error*/) {}
|
||||
};
|
||||
|
||||
class RefreshAllocationCallback
|
||||
{
|
||||
public:
|
||||
virtual ~RefreshAllocationCallback();
|
||||
virtual void onAllocationRefreshed(int /*stream*/, int /*component*/, int /*error*/) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
65
src/libs/ice/ICEHMAC.cpp
Normal file
65
src/libs/ice/ICEHMAC.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//******************************************************************************
|
||||
//* HMAC_SHA1.cpp : Implementation of HMAC SHA1 algorithm
|
||||
//* Comfort to RFC 2104
|
||||
//*
|
||||
//******************************************************************************
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include "ICEHMAC.h"
|
||||
#include "ICESHA1.h"
|
||||
|
||||
void ICEHMAC::GetDigest(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest)
|
||||
{
|
||||
memset(SHA1_Key, 0, SHA1_BLOCK_SIZE);
|
||||
|
||||
/* repeated 64 times for values in ipad and opad */
|
||||
memset(m_ipad, 0x36, sizeof(m_ipad));
|
||||
memset(m_opad, 0x5c, sizeof(m_opad));
|
||||
|
||||
/* STEP 1 */
|
||||
if (key_len > SHA1_DIGEST_LENGTH)
|
||||
{
|
||||
ICESHA1::Reset();
|
||||
ICESHA1::Update((UINT_8 *)key, key_len);
|
||||
ICESHA1::Final();
|
||||
|
||||
ICESHA1::GetHash((UINT_8 *)SHA1_Key);
|
||||
}
|
||||
else
|
||||
memcpy(SHA1_Key, key, key_len);
|
||||
|
||||
/* STEP 2 */
|
||||
for (int i=0; i<sizeof(m_ipad); i++)
|
||||
{
|
||||
m_ipad[i] ^= SHA1_Key[i];
|
||||
}
|
||||
|
||||
/* STEP 3 */
|
||||
memcpy(AppendBuf1, m_ipad, sizeof(m_ipad));
|
||||
memcpy(AppendBuf1 + sizeof(m_ipad), text, text_len);
|
||||
|
||||
/* STEP 4 */
|
||||
ICESHA1::Reset();
|
||||
ICESHA1::Update((unsigned char *)AppendBuf1, sizeof(m_ipad) + text_len);
|
||||
ICESHA1::Final();
|
||||
|
||||
ICESHA1::GetHash((unsigned char *)szReport);
|
||||
|
||||
/* STEP 5 */
|
||||
for (int j=0; j<sizeof(m_opad); j++)
|
||||
{
|
||||
m_opad[j] ^= SHA1_Key[j];
|
||||
}
|
||||
|
||||
/* STEP 6 */
|
||||
memcpy(AppendBuf2, m_opad, sizeof(m_opad));
|
||||
memcpy(AppendBuf2 + sizeof(m_opad), szReport, SHA1_DIGEST_LENGTH);
|
||||
|
||||
/*STEP 7 */
|
||||
ICESHA1::Reset();
|
||||
ICESHA1::Update((unsigned char*)AppendBuf2, sizeof(m_opad) + SHA1_DIGEST_LENGTH);
|
||||
ICESHA1::Final();
|
||||
|
||||
ICESHA1::GetHash((unsigned char *)digest);
|
||||
}
|
||||
50
src/libs/ice/ICEHMAC.h
Normal file
50
src/libs/ice/ICEHMAC.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Based on 100% free public domain implementation of the HMAC-SHA1 algorithm
|
||||
by Chien-Chung, Chung (Jim Chung) <jimchung1221@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __ICE_HMAC_H
|
||||
#define __ICE_HMAC_H
|
||||
|
||||
#include "ICESHA1.h"
|
||||
|
||||
class ICEHMAC: public ICESHA1
|
||||
{
|
||||
private:
|
||||
unsigned char m_ipad[64];
|
||||
unsigned char m_opad[64];
|
||||
|
||||
unsigned char * szReport ;
|
||||
unsigned char * SHA1_Key ;
|
||||
unsigned char * AppendBuf1 ;
|
||||
unsigned char * AppendBuf2 ;
|
||||
|
||||
|
||||
public:
|
||||
enum {
|
||||
SHA1_DIGEST_LENGTH = 20,
|
||||
SHA1_BLOCK_SIZE = 64,
|
||||
HMAC_BUF_LEN = 4096
|
||||
} ;
|
||||
|
||||
ICEHMAC()
|
||||
:szReport(new unsigned char[HMAC_BUF_LEN]),
|
||||
AppendBuf1(new unsigned char[HMAC_BUF_LEN]),
|
||||
AppendBuf2(new unsigned char[HMAC_BUF_LEN]),
|
||||
SHA1_Key(new unsigned char[HMAC_BUF_LEN])
|
||||
{
|
||||
}
|
||||
|
||||
~ICEHMAC()
|
||||
{
|
||||
delete[] szReport ;
|
||||
delete[] AppendBuf1 ;
|
||||
delete[] AppendBuf2 ;
|
||||
delete[] SHA1_Key ;
|
||||
}
|
||||
|
||||
void GetDigest(unsigned char *text, int text_len, unsigned char* key, int key_len, unsigned char *digest);
|
||||
};
|
||||
|
||||
|
||||
#endif /* __HMAC_SHA1_H__ */
|
||||
18
src/libs/ice/ICEIosSupport.h
Normal file
18
src/libs/ice/ICEIosSupport.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_IOS_SUPPORT_H
|
||||
#define __ICE_IOS_SUPPORT_H
|
||||
|
||||
#include <vector>
|
||||
#include "ICEAddress.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
int getIosIp(int networkType, int family, char* adress);
|
||||
int fillIosInterfaceList(int family, int networkType, std::vector<ice::NetworkAddress>& output);
|
||||
}
|
||||
|
||||
#endif
|
||||
224
src/libs/ice/ICEIosSupport.mm
Normal file
224
src/libs/ice/ICEIosSupport.mm
Normal file
@@ -0,0 +1,224 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEIosSupport.h"
|
||||
#include "ICENetworkHelper.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <arpa/inet.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include "TargetConditionals.h"
|
||||
#include "ICEAddress.h"
|
||||
#include "ICELog.h"
|
||||
#include "ICENetworkHelper.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
typedef enum {
|
||||
ConnectionTypeUnknown,
|
||||
ConnectionTypeNone,
|
||||
ConnectionType3G,
|
||||
ConnectionTypeWiFi
|
||||
} ConnectionType;
|
||||
|
||||
|
||||
ConnectionType FindConnectionType(int family)
|
||||
{
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, family == AF_INET ? "8.8.8.8" : "2001:4860:4860::8888");
|
||||
SCNetworkReachabilityFlags flags;
|
||||
BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags);
|
||||
CFRelease(reachability);
|
||||
if (!success) {
|
||||
return ConnectionTypeUnknown;
|
||||
}
|
||||
BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
|
||||
BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
|
||||
BOOL isNetworkReachable = (isReachable && !needsConnection);
|
||||
|
||||
if (!isNetworkReachable) {
|
||||
return ConnectionTypeNone;
|
||||
} else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
|
||||
return ConnectionType3G;
|
||||
} else {
|
||||
return ConnectionTypeWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
int fillIosInterfaceList(int family, int networkType, std::vector<ice::NetworkAddress>& output)
|
||||
{
|
||||
if (networkType == NetworkHelper::NetworkType_None)
|
||||
{
|
||||
switch (FindConnectionType(family))
|
||||
{
|
||||
case ConnectionTypeNone:
|
||||
return 0;
|
||||
|
||||
case ConnectionType3G:
|
||||
networkType = NetworkHelper::NetworkType_3G;
|
||||
break;
|
||||
|
||||
case ConnectionTypeWiFi:
|
||||
networkType = NetworkHelper::NetworkType_WiFi;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
struct ifaddrs *interfaces = NULL;
|
||||
struct ifaddrs *temp_addr = NULL;
|
||||
|
||||
// retrieve the current interfaces - returns 0 on success
|
||||
if(!getifaddrs(&interfaces))
|
||||
{
|
||||
// Loop through linked list of interfaces
|
||||
for (temp_addr = interfaces; temp_addr != NULL; temp_addr = temp_addr->ifa_next)
|
||||
{
|
||||
sa_family_t sa_type = temp_addr->ifa_addr->sa_family;
|
||||
|
||||
if (sa_type == family)
|
||||
{
|
||||
NSString* name = [NSString stringWithUTF8String: temp_addr->ifa_name];
|
||||
|
||||
if (networkType != NetworkHelper::NetworkType_None)
|
||||
{
|
||||
bool wifi = [name rangeOfString: @"en"].location == 0;
|
||||
bool cell = [name rangeOfString: @"pdp_ip"].location == 0;
|
||||
/*bool vpn = [name rangeOfString: @"tun"].location == 0 || [name rangeOfString: @"tap"].location == 0;*/
|
||||
|
||||
switch (networkType)
|
||||
{
|
||||
case NetworkHelper::NetworkType_3G:
|
||||
if (wifi) // Skip wifi addresses here. Use cell and vpn addresses here.
|
||||
continue;
|
||||
break;
|
||||
|
||||
case NetworkHelper::NetworkType_WiFi:
|
||||
if (cell) // Skip cell addresses here. Use other addresses - wifi and vpn.
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ice::NetworkAddress addr;
|
||||
if (sa_type == AF_INET6)
|
||||
addr = ice::NetworkAddress(((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, 1000);
|
||||
else
|
||||
addr = ice::NetworkAddress(((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, 1000);
|
||||
|
||||
//ICELogDebug(<< "Found: " << addr.toStdString());
|
||||
|
||||
if (!addr.isLoopback() && !addr.isLinkLocal())
|
||||
output.push_back(addr);
|
||||
}
|
||||
|
||||
}
|
||||
// Free memory
|
||||
freeifaddrs(interfaces);
|
||||
}
|
||||
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getIosIp(int networkType, int family, char* address)
|
||||
{
|
||||
assert(address);
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
struct ifaddrs *interfaces = NULL;
|
||||
struct ifaddrs *temp_addr = NULL;
|
||||
NSString *wifiAddress = nil;
|
||||
NSString *cellAddress = nil;
|
||||
|
||||
// retrieve the current interfaces - returns 0 on success
|
||||
if(!getifaddrs(&interfaces))
|
||||
{
|
||||
// Loop through linked list of interfaces
|
||||
temp_addr = interfaces;
|
||||
while(temp_addr != NULL)
|
||||
{
|
||||
sa_family_t sa_type = temp_addr->ifa_addr->sa_family;
|
||||
|
||||
if (sa_type == family)
|
||||
{
|
||||
NSString* name = [NSString stringWithUTF8String: temp_addr->ifa_name];
|
||||
char buffer[128];
|
||||
if (sa_type == AF_INET6)
|
||||
inet_ntop(AF_INET6, &((sockaddr_in6*)temp_addr->ifa_addr)->sin6_addr, buffer, sizeof(buffer));
|
||||
else
|
||||
inet_ntop(AF_INET, &((sockaddr_in*)temp_addr->ifa_addr)->sin_addr, buffer, sizeof(buffer));
|
||||
|
||||
NSString* addr = [NSString stringWithUTF8String: buffer];
|
||||
|
||||
if([name rangeOfString: @"en"].location == 0)
|
||||
{
|
||||
// Interface is the wifi connection on the iPhone
|
||||
wifiAddress = addr;
|
||||
}
|
||||
else
|
||||
if([name isEqualToString: @"pdp_ip0"])
|
||||
{
|
||||
// Interface is the cell connection on the iPhone
|
||||
cellAddress = addr;
|
||||
}
|
||||
else
|
||||
if ([name rangeOfString: @"tun"].location == 0 || [name rangeOfString: @"tap"].location == 0)
|
||||
{
|
||||
wifiAddress = addr;
|
||||
}
|
||||
}
|
||||
temp_addr = temp_addr->ifa_next;
|
||||
}
|
||||
// Free memory
|
||||
freeifaddrs(interfaces);
|
||||
}
|
||||
|
||||
NSString* currentAddr = nil;
|
||||
switch (networkType)
|
||||
{
|
||||
case ice::NetworkHelper::NetworkType_None:
|
||||
currentAddr = wifiAddress ? wifiAddress : cellAddress;
|
||||
break;
|
||||
|
||||
case ice::NetworkHelper::NetworkType_WiFi:
|
||||
currentAddr = wifiAddress;
|
||||
break;
|
||||
|
||||
case ice::NetworkHelper::NetworkType_3G:
|
||||
currentAddr = cellAddress;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentAddr)
|
||||
strcpy(address, [currentAddr UTF8String]);
|
||||
else
|
||||
if (wifiAddress)
|
||||
strcpy(address, [wifiAddress UTF8String]);
|
||||
else
|
||||
if (cellAddress)
|
||||
strcpy(address, [cellAddress UTF8String]);
|
||||
else
|
||||
strcpy(address, "127.0.0.1");
|
||||
|
||||
[pool release];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
251
src/libs/ice/ICELog.cpp
Normal file
251
src/libs/ice/ICELog.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICELog.h"
|
||||
#include "ICETime.h"
|
||||
#include "ICESync.h"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if defined(__ANDROID_API__)
|
||||
# include <android/log.h>
|
||||
#endif
|
||||
|
||||
using namespace ice;
|
||||
|
||||
ice::Logger ice::GLogger;
|
||||
const char* ice::Logger::TabPrefix = " ";
|
||||
|
||||
Logger::Logger()
|
||||
:mStream(nullptr)
|
||||
{
|
||||
mFile = nullptr;
|
||||
mUseDebugWindow = false;
|
||||
mDelegate = nullptr;
|
||||
mLevel = LL_DEBUG;
|
||||
}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
//LogGuard l(mGuard);
|
||||
if (mFile)
|
||||
{
|
||||
fclose(mFile);
|
||||
mFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Logger::useDebugWindow(bool enable)
|
||||
{
|
||||
LogGuard l(mGuard);
|
||||
|
||||
mUseDebugWindow = enable;
|
||||
}
|
||||
|
||||
void
|
||||
Logger::useFile(const char* filepath)
|
||||
{
|
||||
LogGuard l(mGuard);
|
||||
|
||||
mLogPath = filepath ? filepath : "";
|
||||
if (mLogPath.empty())
|
||||
return;
|
||||
|
||||
FILE* f = fopen(filepath, "at");
|
||||
if (f)
|
||||
{
|
||||
if (mFile)
|
||||
fclose(mFile);
|
||||
mFile = f;
|
||||
}
|
||||
|
||||
if (f)
|
||||
{
|
||||
fprintf(f, "New log chunk starts here.\n");
|
||||
fflush(f);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Logger::useNull()
|
||||
{
|
||||
LogGuard l(mGuard);
|
||||
|
||||
mUseDebugWindow = false;
|
||||
if (mFile)
|
||||
{
|
||||
fflush(mFile);
|
||||
fclose(mFile);
|
||||
mFile = NULL;
|
||||
}
|
||||
|
||||
mDelegate = NULL;
|
||||
}
|
||||
|
||||
void Logger::closeFile()
|
||||
{
|
||||
LogGuard l(mGuard);
|
||||
if (mFile)
|
||||
{
|
||||
fflush(mFile);
|
||||
fclose(mFile);
|
||||
mFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::openFile()
|
||||
{
|
||||
LogGuard l(mGuard);
|
||||
if (mLogPath.empty())
|
||||
return;
|
||||
|
||||
remove(mLogPath.c_str());
|
||||
useFile(mLogPath.c_str());
|
||||
}
|
||||
|
||||
|
||||
void Logger::useDelegate(LogHandler* delegate_)
|
||||
{
|
||||
mDelegate = delegate_;
|
||||
}
|
||||
|
||||
LogGuard& Logger::mutex()
|
||||
{
|
||||
return mGuard;
|
||||
}
|
||||
|
||||
LogLevel Logger::level()
|
||||
{
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
void Logger::setLevel(LogLevel level)
|
||||
{
|
||||
mLevel = level;
|
||||
}
|
||||
|
||||
void Logger::beginLine(LogLevel level, const char* filename, int linenumber, const char* subsystem)
|
||||
{
|
||||
mMsgLevel = level;
|
||||
mStream = new std::ostringstream();
|
||||
|
||||
#ifdef WIN32
|
||||
const char* filenamestart = strrchr(filename, '\\');
|
||||
#else
|
||||
const char* filenamestart = strrchr(filename, '/');
|
||||
#endif
|
||||
if (!filenamestart)
|
||||
filenamestart = filename;
|
||||
else
|
||||
filenamestart++;
|
||||
|
||||
mFilename = filenamestart;
|
||||
mLine = linenumber;
|
||||
mSubsystem = subsystem;
|
||||
|
||||
//*mStream << std::setw(8) << ICETimeHelper::timestamp() << " | " << std::setw(8) << ThreadInfo::currentThread() << " | " << std::setw(30) << filenamestart << " | " << std::setw(4) << linenumber << " | " << std::setw(12) << subsystem << " | ";
|
||||
}
|
||||
|
||||
void
|
||||
Logger::endLine()
|
||||
{
|
||||
*mStream << std::endl;
|
||||
*mStream << std::flush;
|
||||
mStream->flush();
|
||||
|
||||
std::ostringstream result;
|
||||
result << std::setw(8) << ICETimeHelper::timestamp() << " | " << std::setw(8) << ThreadInfo::currentThread() << " | " << std::setw(30) << mFilename.c_str() << " | " << std::setw(4) << mLine << " | " << std::setw(12) << mSubsystem.c_str() << " | " << mStream->str().c_str();
|
||||
|
||||
std::string t = result.str();
|
||||
if (mUseDebugWindow)
|
||||
#ifdef TARGET_WIN
|
||||
OutputDebugStringA(t.c_str());
|
||||
#elif defined(TARGET_ANDROID)
|
||||
if (t.size() > 512)
|
||||
{
|
||||
std::string cut = t; cut.erase(480); // Erase tail of string
|
||||
cut += "\r\n... [cut]";
|
||||
__android_log_print(ANDROID_LOG_INFO, "VoipAgent", "%s", cut.c_str());
|
||||
}
|
||||
else {
|
||||
__android_log_print(ANDROID_LOG_INFO, "VoipAgent", "%s", t.c_str());
|
||||
}
|
||||
#else
|
||||
std::cerr << result.str() << std::endl << std::flush;
|
||||
#endif
|
||||
if (mFile)
|
||||
{
|
||||
fprintf(mFile, "%s", result.str().c_str());
|
||||
fflush(mFile);
|
||||
}
|
||||
if (mDelegate)
|
||||
mDelegate->onIceLog(mMsgLevel, mFilename, mLine, mSubsystem, mStream->str());
|
||||
|
||||
delete mStream; mStream = NULL;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator << (const char* data)
|
||||
{
|
||||
*mStream << data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator << (const wchar_t* data)
|
||||
{
|
||||
*mStream << data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator << (const int data)
|
||||
{
|
||||
*mStream << data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator << (const float data)
|
||||
{
|
||||
*mStream << data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator<<(const int64_t data)
|
||||
{
|
||||
*mStream << data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Logger&
|
||||
Logger::operator<<(const unsigned int data)
|
||||
{
|
||||
*mStream << data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Logger&
|
||||
Logger::operator<<(const uint64_t data)
|
||||
{
|
||||
*mStream << data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Logger&
|
||||
Logger::operator << (const std::string& data)
|
||||
{
|
||||
*mStream << data.c_str();
|
||||
return *this;
|
||||
}
|
||||
163
src/libs/ice/ICELog.h
Normal file
163
src/libs/ice/ICELog.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_LOG_H
|
||||
#define __ICE_LOG_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICETypes.h"
|
||||
#include "ICEEvent.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
// Defines log levels
|
||||
enum LogLevel
|
||||
{
|
||||
LL_NONE = -1,
|
||||
LL_CRITICAL = 0,
|
||||
LL_INFO = 1,
|
||||
LL_DEBUG = 2,
|
||||
LL_MEDIA = 3
|
||||
};
|
||||
|
||||
class LogHandler
|
||||
{
|
||||
public:
|
||||
virtual void onIceLog(LogLevel level, const std::string& filename, int line, const std::string& subsystem, const std::string& msg) = 0;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
class LogGuard
|
||||
{
|
||||
public:
|
||||
LogGuard() { ::InitializeCriticalSection(&mCS); }
|
||||
~LogGuard() { ::DeleteCriticalSection(&mCS); }
|
||||
void Lock() { ::EnterCriticalSection(&mCS); }
|
||||
void Unlock() { ::LeaveCriticalSection(&mCS); }
|
||||
|
||||
protected:
|
||||
CRITICAL_SECTION mCS;
|
||||
};
|
||||
|
||||
class LogLock
|
||||
{
|
||||
public:
|
||||
LogLock(LogGuard& g) :mGuard(g) { mGuard.Lock(); }
|
||||
~LogLock() { mGuard.Unlock(); }
|
||||
|
||||
protected:
|
||||
LogGuard& mGuard;
|
||||
};
|
||||
#else
|
||||
class LogGuard
|
||||
{
|
||||
public:
|
||||
LogGuard() { ::pthread_mutex_init(&mMutex, NULL); }
|
||||
~LogGuard() { ::pthread_mutex_destroy(&mMutex); }
|
||||
void Lock() { ::pthread_mutex_lock(&mMutex); }
|
||||
void Unlock() { ::pthread_mutex_unlock(&mMutex); }
|
||||
|
||||
protected:
|
||||
pthread_mutex_t mMutex;
|
||||
};
|
||||
|
||||
class LogLock
|
||||
{
|
||||
public:
|
||||
LogLock(LogGuard& g) :mGuard(g) { mGuard.Lock(); }
|
||||
~LogLock() { mGuard.Unlock(); }
|
||||
|
||||
protected:
|
||||
LogGuard& mGuard;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static const char* TabPrefix;
|
||||
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
void useDebugWindow(bool enable);
|
||||
void useFile(const char* filepath);
|
||||
void useDelegate(LogHandler* delegate_);
|
||||
void useNull();
|
||||
void closeFile();
|
||||
void openFile();
|
||||
|
||||
LogGuard& mutex();
|
||||
LogLevel level();
|
||||
void setLevel(LogLevel level);
|
||||
void beginLine(LogLevel level, const char* filename, int linenumber, const char* subsystem);
|
||||
void endLine();
|
||||
|
||||
Logger& operator << (const char* data);
|
||||
Logger& operator << (const wchar_t* data);
|
||||
Logger& operator << (const int data);
|
||||
Logger& operator << (const float data);
|
||||
Logger& operator << (const std::string& data);
|
||||
Logger& operator << (const int64_t data);
|
||||
Logger& operator << (const unsigned int data);
|
||||
Logger& operator << (const uint64_t data);
|
||||
|
||||
protected:
|
||||
LogGuard mGuard;
|
||||
FILE* mFile;
|
||||
std::string mLogPath;
|
||||
|
||||
bool mUseDebugWindow;
|
||||
LogHandler* mDelegate;
|
||||
LogLevel mLevel;
|
||||
std::ostringstream* mStream;
|
||||
|
||||
LogLevel mMsgLevel;
|
||||
std::string mFilename;
|
||||
int mLine;
|
||||
std::string mSubsystem;
|
||||
};
|
||||
|
||||
|
||||
extern Logger GLogger;
|
||||
|
||||
|
||||
#define ICELog(level_, subsystem_, args_)\
|
||||
{do\
|
||||
{\
|
||||
if (GLogger.level() >= level_)\
|
||||
{\
|
||||
LogLock l(GLogger.mutex());\
|
||||
GLogger.beginLine(level_, __FILE__, __LINE__, subsystem_);\
|
||||
GLogger args_;\
|
||||
GLogger.endLine();\
|
||||
}\
|
||||
} while (false);}
|
||||
|
||||
#define ICELogCritical(args_) ICELog(LL_CRITICAL, LOG_SUBSYSTEM, args_)
|
||||
#define ICELogInfo(args_) ICELog(LL_INFO, LOG_SUBSYSTEM, args_)
|
||||
#define ICELogDebug(args_) ICELog(LL_DEBUG, LOG_SUBSYSTEM, args_)
|
||||
#define ICELogMedia(args_) ICELog(LL_MEDIA, LOG_SUBSYSTEM, args_)
|
||||
|
||||
|
||||
/*
|
||||
#define ICELogCritical(args_)
|
||||
#define ICELogInfo(args_)
|
||||
#define ICELogDebug(args_)
|
||||
#define ICELogMedia(args_)
|
||||
*/
|
||||
|
||||
} //end of namespace
|
||||
|
||||
#endif
|
||||
305
src/libs/ice/ICEMD5.cpp
Normal file
305
src/libs/ice/ICEMD5.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEMD5.h"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
#ifdef USE_CRYPTOPP
|
||||
|
||||
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
|
||||
#include "../CryptoPP/md5.h"
|
||||
using namespace CryptoPP;
|
||||
|
||||
void ice::md5Bin(const void* inputData, size_t inputSize, void* digest)
|
||||
{
|
||||
Weak::MD5 md5;
|
||||
md5.Update((const byte*)inputData, inputSize);
|
||||
|
||||
md5.Final((byte*)digest);
|
||||
}
|
||||
|
||||
#elif defined(USE_OPENSSL)
|
||||
|
||||
#ifdef USE_FIPS
|
||||
typedef unsigned int MD5_u32plus;
|
||||
|
||||
typedef struct {
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
*/
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them
|
||||
* in a properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned
|
||||
* memory accesses is just an optimization. Nothing will break if it
|
||||
* doesn't work.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
|
||||
#define SET(n) \
|
||||
(*(MD5_u32plus *)&ptr[(n) * 4])
|
||||
#define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
#define SET(n) \
|
||||
(ctx->block[(n)] = \
|
||||
(MD5_u32plus)ptr[(n) * 4] | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
|
||||
#define GET(n) \
|
||||
(ctx->block[(n)])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
static void *body(MD5_CTX *ctx, void *data, unsigned long size)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (unsigned char*)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MD5_Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
|
||||
{
|
||||
MD5_u32plus saved_lo;
|
||||
unsigned long used, free;
|
||||
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
|
||||
ctx->hi++;
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
free = 64 - used;
|
||||
|
||||
if (size < free) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, free);
|
||||
data = (unsigned char *)data + free;
|
||||
size -= free;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~(unsigned long)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
{
|
||||
unsigned long used, free;
|
||||
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
free = 64 - used;
|
||||
|
||||
if (free < 8) {
|
||||
memset(&ctx->buffer[used], 0, free);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
free = 64;
|
||||
}
|
||||
|
||||
memset(&ctx->buffer[used], 0, free - 8);
|
||||
|
||||
ctx->lo <<= 3;
|
||||
ctx->buffer[56] = ctx->lo;
|
||||
ctx->buffer[57] = ctx->lo >> 8;
|
||||
ctx->buffer[58] = ctx->lo >> 16;
|
||||
ctx->buffer[59] = ctx->lo >> 24;
|
||||
ctx->buffer[60] = ctx->hi;
|
||||
ctx->buffer[61] = ctx->hi >> 8;
|
||||
ctx->buffer[62] = ctx->hi >> 16;
|
||||
ctx->buffer[63] = ctx->hi >> 24;
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
result[0] = ctx->a;
|
||||
result[1] = ctx->a >> 8;
|
||||
result[2] = ctx->a >> 16;
|
||||
result[3] = ctx->a >> 24;
|
||||
result[4] = ctx->b;
|
||||
result[5] = ctx->b >> 8;
|
||||
result[6] = ctx->b >> 16;
|
||||
result[7] = ctx->b >> 24;
|
||||
result[8] = ctx->c;
|
||||
result[9] = ctx->c >> 8;
|
||||
result[10] = ctx->c >> 16;
|
||||
result[11] = ctx->c >> 24;
|
||||
result[12] = ctx->d;
|
||||
result[13] = ctx->d >> 8;
|
||||
result[14] = ctx->d >> 16;
|
||||
result[15] = ctx->d >> 24;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
#else
|
||||
#include <openssl/md5.h>
|
||||
#endif
|
||||
|
||||
void ice::md5Bin(const void* inputData, size_t inputSize, void* digest)
|
||||
{
|
||||
MD5_CTX md5;
|
||||
MD5_Init(&md5);
|
||||
#ifdef USE_FIPS
|
||||
MD5_Update(&md5, (void*)inputData, inputSize);
|
||||
#else
|
||||
MD5_Update(&md5, (const unsigned char*)inputData, inputSize);
|
||||
#endif
|
||||
MD5_Final((unsigned char*)digest, &md5);
|
||||
}
|
||||
|
||||
#endif
|
||||
15
src/libs/ice/ICEMD5.h
Normal file
15
src/libs/ice/ICEMD5.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_MD5_H
|
||||
#define __ICE_MD5_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
extern void md5Bin(const void* inputData, size_t inputSize, void* digest );
|
||||
}
|
||||
#endif
|
||||
484
src/libs/ice/ICENetworkHelper.cpp
Normal file
484
src/libs/ice/ICENetworkHelper.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICENetworkHelper.h"
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICELog.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef TARGET_WIN
|
||||
# include <tchar.h>
|
||||
# if defined(WINDOWS_RT)
|
||||
# include "ICEWinRtSupport.h"
|
||||
# endif
|
||||
#else
|
||||
#if defined(TARGET_IOS)
|
||||
# include "ICEIosSupport.h"
|
||||
#endif
|
||||
# include <unistd.h>
|
||||
# if defined(TARGET_ANDROID) || defined(TARGET_LINUX)
|
||||
# include <linux/in6.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "ICEError.h"
|
||||
using namespace ice;
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
class IPHlpApi
|
||||
{
|
||||
public:
|
||||
HMODULE mHandle;
|
||||
DWORD (WINAPI *pGetBestInterfaceEx) (struct sockaddr* pDestAddr, PDWORD pdwBestIfIndex);
|
||||
DWORD (WINAPI *pGetBestInterface) (IPAddr dwDestAddr, PDWORD pdwBestIfIndex);
|
||||
ULONG (WINAPI *pGetAdaptersAddresses) (ULONG Family, ULONG Flags, PVOID Reserved, PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer);
|
||||
|
||||
void ResolveProc(const char* name, FARPROC& proc)
|
||||
{
|
||||
proc = GetProcAddress(mHandle, name);
|
||||
}
|
||||
|
||||
public:
|
||||
IPHlpApi()
|
||||
{
|
||||
pGetBestInterfaceEx = NULL;
|
||||
pGetBestInterface = NULL;
|
||||
pGetAdaptersAddresses = NULL;
|
||||
mHandle = ::LoadLibraryW(L"iphlpapi.dll");
|
||||
if (mHandle)
|
||||
{
|
||||
ResolveProc("GetBestInterfaceEx", (FARPROC&)pGetBestInterfaceEx);
|
||||
ResolveProc("GetBestInterface", (FARPROC&)pGetBestInterface);
|
||||
ResolveProc("GetAdaptersAddresses", (FARPROC&)pGetAdaptersAddresses);
|
||||
}
|
||||
}
|
||||
|
||||
~IPHlpApi()
|
||||
{
|
||||
if (mHandle)
|
||||
FreeLibrary(mHandle);
|
||||
}
|
||||
|
||||
};
|
||||
IPHlpApi IPHelper;
|
||||
#endif
|
||||
|
||||
NetworkHelper::NetworkHelper()
|
||||
{
|
||||
reload(NetworkType_None);
|
||||
}
|
||||
|
||||
NetworkHelper::~NetworkHelper()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkHelper::reload(int networkType)
|
||||
{
|
||||
Lock l(mInstanceGuard);
|
||||
|
||||
// Get list of interfaces
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
mInterfaceList.clear();
|
||||
mIP2IndexList.clear();
|
||||
|
||||
DWORD dwRet, dwSize;
|
||||
DWORD flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
|
||||
IP_ADAPTER_ADDRESSES* ipAdapters = NULL;
|
||||
dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, NULL, &dwSize);
|
||||
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize);
|
||||
if (!ipAdapters)
|
||||
return;
|
||||
|
||||
dwRet = IPHelper.pGetAdaptersAddresses(AF_INET, flags, NULL, ipAdapters, &dwSize);
|
||||
if (dwRet != ERROR_SUCCESS)
|
||||
{
|
||||
free(ipAdapters);
|
||||
throw Exception(CANNOT_FIND_INTERFACES);
|
||||
}
|
||||
processAdaptersList(ipAdapters);
|
||||
free(ipAdapters);
|
||||
}
|
||||
|
||||
#ifdef ICE_IPV6SUPPORT
|
||||
dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, NULL, &dwSize);
|
||||
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
ipAdapters = (IP_ADAPTER_ADDRESSES*)malloc(dwSize);
|
||||
if (!ipAdapters)
|
||||
return;
|
||||
|
||||
dwRet = IPHelper.pGetAdaptersAddresses(AF_INET6, flags, NULL, ipAdapters, &dwSize);
|
||||
if (dwRet != ERROR_SUCCESS)
|
||||
{
|
||||
free(ipAdapters);
|
||||
throw NetworkAddress(CANNOT_FIND_INTERFACES);
|
||||
}
|
||||
processAdaptersList(ipAdapters);
|
||||
free(ipAdapters);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned i=0; i<mIP2IndexList.size(); i++)
|
||||
{
|
||||
bool handleIt = true;
|
||||
NetworkAddress ip = mIP2IndexList[i].mIP;
|
||||
#ifndef ICE_LOOPBACK_SUPPORT
|
||||
handleIt = !ip.isLoopback();
|
||||
#endif
|
||||
#ifdef ICE_SKIP_LINKLOCAL
|
||||
handleIt &= !ip.isLinkLocal();
|
||||
#endif
|
||||
if (handleIt)
|
||||
mInterfaceList.push_back(ip);
|
||||
}
|
||||
#else
|
||||
mIPList.clear();
|
||||
#if defined(TARGET_OS_IPHONE)
|
||||
ICELogDebug(<< "Obtaining IPv4 interfaces.");
|
||||
fillIosInterfaceList(AF_INET, networkType, mIPList);
|
||||
ICELogDebug(<< "Obtaining IPv6 interfaces.");
|
||||
fillIosInterfaceList(AF_INET6, networkType, mIPList);
|
||||
for (auto& addr: mIPList)
|
||||
ICELogDebug(<< " " << addr.toStdString());
|
||||
#elif defined(WINDOWS_RT)
|
||||
fillUwpInterfaceList(AF_INET, networkType, mIPList);
|
||||
fillUwpInterfaceList(AF_INET6, networkType, mIPList);
|
||||
#else
|
||||
struct ifaddrs* il = NULL;
|
||||
if (getifaddrs(&il))
|
||||
throw Exception(GETIFADDRS_FAILED, errno);
|
||||
if (il)
|
||||
{
|
||||
struct ifaddrs* current = il;
|
||||
while (current)
|
||||
{
|
||||
//char ipbuffer[64];
|
||||
NetworkAddress addr;
|
||||
addr.setPort(1000); // Set fake address to keep NetworkAddress initialized
|
||||
bool handleIt = true;
|
||||
switch(current->ifa_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
// just for debug
|
||||
// printf("%s", inet_ntoa(reinterpret_cast<sockaddr_in*>(current->ifa_addr)->sin_addr));
|
||||
addr.setIp(reinterpret_cast<sockaddr_in*>(current->ifa_addr)->sin_addr);
|
||||
#ifndef ICE_LOOPBACK_SUPPORT
|
||||
handleIt = !addr.isLoopback();
|
||||
#endif
|
||||
#ifdef ICE_SKIP_LINKLOCAL
|
||||
handleIt &= !addr.isLinkLocal();
|
||||
#endif
|
||||
if (handleIt)
|
||||
mIPList.push_back(addr);
|
||||
break;
|
||||
|
||||
#ifdef ICE_IPV6SUPPORT
|
||||
case AF_INET6:
|
||||
addr.setIp(reinterpret_cast<sockaddr_in6*>(current->ifa_addr)->sin6_addr);
|
||||
#ifndef ICE_LOOPBACK_SUPPORT
|
||||
if (!addr.isLoopback())
|
||||
#endif
|
||||
mIPList.push_back(addr);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
current = current->ifa_next;
|
||||
}
|
||||
freeifaddrs(il);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
void NetworkHelper::processAdaptersList(IP_ADAPTER_ADDRESSES* addresses)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES *AI;
|
||||
int i;
|
||||
for (i = 0, AI = addresses; AI != NULL; AI = AI->Next, i++)
|
||||
{
|
||||
for (PIP_ADAPTER_UNICAST_ADDRESS unicast = AI->FirstUnicastAddress; unicast; unicast = unicast->Next)
|
||||
{
|
||||
#ifdef ICE_IPV6SUPPORT
|
||||
if (unicast->Address.lpSockaddr->sa_family != AF_INET && unicast->Address.lpSockaddr->sa_family != AF_INET6)
|
||||
continue;
|
||||
#else
|
||||
if (unicast->Address.lpSockaddr->sa_family != AF_INET)
|
||||
continue;
|
||||
#endif
|
||||
IP2Index rec;
|
||||
rec.mIP = NetworkAddress(*unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength);
|
||||
rec.mIndex = AI->IfIndex;
|
||||
mIP2IndexList.push_back(rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Mutex& NetworkHelper::guard()
|
||||
{
|
||||
return mInstanceGuard;
|
||||
}
|
||||
|
||||
std::vector<NetworkAddress>& NetworkHelper::interfaceList()
|
||||
{
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
return mInterfaceList;
|
||||
#else
|
||||
return mIPList;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
NetworkAddress NetworkHelper::sourceInterface(const NetworkAddress& remoteIP)
|
||||
{
|
||||
//Lock l(mInstanceGuard);
|
||||
|
||||
if (remoteIP.isLoopback())
|
||||
return remoteIP.family() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6;
|
||||
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
if (IPHelper.pGetBestInterfaceEx)
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD rescode = IPHelper.pGetBestInterfaceEx(remoteIP.genericsockaddr(), &index);
|
||||
if (rescode == NO_ERROR)
|
||||
return ipInterfaceByIndex(index);
|
||||
}
|
||||
else
|
||||
if (IPHelper.pGetBestInterface)
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD rescode = IPHelper.pGetBestInterface(remoteIP.sockaddr4()->sin_addr.S_un.S_addr, &index);
|
||||
if (rescode == NO_ERROR)
|
||||
return ipInterfaceByIndex(index);
|
||||
}
|
||||
#ifdef ICE_LOOPBACK_SUPPORT
|
||||
return NetworkAddress::LoopbackAddress4;
|
||||
#else
|
||||
return remoteIP;
|
||||
#endif
|
||||
|
||||
#elif defined(WINDOWS_RT)
|
||||
std::vector<NetworkAddress>& il = interfaceList();
|
||||
if (il.size())
|
||||
return il.front();
|
||||
else
|
||||
return NetworkAddress();
|
||||
#else
|
||||
if (remoteIP.isLoopback())
|
||||
return remoteIP;
|
||||
|
||||
/*#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR)
|
||||
// There is only one interface - return it
|
||||
std::vector<NetworkAddress>& il = interfaceList();
|
||||
if (il.size())
|
||||
{
|
||||
if (!il.front().isZero())
|
||||
return il.front();
|
||||
}
|
||||
|
||||
#endif*/
|
||||
|
||||
// Here magic goes.
|
||||
// 1) Check if remoteIP is IP4 or IP6
|
||||
// 2) Check if it is LAN or loopback or internet address
|
||||
// 3) For LAN address - try to find interface from the same network
|
||||
// For Loopback address - return loopback address
|
||||
// For internet address - find default interface
|
||||
|
||||
//printf("remote ip %s\n", remoteIP.GetIP().c_str());
|
||||
if (remoteIP.isLAN())
|
||||
{
|
||||
for (unsigned i=0; i<mIPList.size(); i++)
|
||||
{
|
||||
//printf("local ip %s\n", mIPList[i].GetIP().c_str());
|
||||
if (NetworkAddress::isSameLAN(mIPList[i], remoteIP))
|
||||
return mIPList[i];
|
||||
}
|
||||
}
|
||||
#ifdef ICE_LOOPBACK_SUPPORT
|
||||
NetworkAddress result = remoteIP.type() == AF_INET ? NetworkAddress::LoopbackAddress4 : NetworkAddress::LoopbackAddress6;
|
||||
#else
|
||||
NetworkAddress result = remoteIP;
|
||||
#endif
|
||||
|
||||
// Find default interface - this operation costs, so the result must be cached
|
||||
SOCKET s = INVALID_SOCKET;
|
||||
int rescode = 0;
|
||||
sockaddr_in ipv4;
|
||||
#ifdef ICE_IPV6SUPPORT
|
||||
sockaddr_in6 ipv6;
|
||||
#endif
|
||||
socklen_t addrLen = 0;
|
||||
switch (remoteIP.family())
|
||||
{
|
||||
case AF_INET:
|
||||
s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s != INVALID_SOCKET)
|
||||
{
|
||||
rescode = ::connect(s, remoteIP.genericsockaddr(), remoteIP.sockaddrLen());
|
||||
if (rescode != -1)
|
||||
{
|
||||
addrLen = sizeof(ipv4);
|
||||
if (::getsockname(s, (sockaddr*)&ipv4, &addrLen) != -1)
|
||||
result = NetworkAddress((sockaddr&)ipv4, addrLen);
|
||||
}
|
||||
::close(s);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ICE_IPV6SUPPORT
|
||||
case AF_INET6:
|
||||
s = ::socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s != INVALID_SOCKET)
|
||||
{
|
||||
rescode = ::connect(s, remoteIP.genericsockaddr(), remoteIP.sockaddrLen());
|
||||
if (rescode != -1)
|
||||
{
|
||||
addrLen = sizeof(ipv6);
|
||||
if (::getsockname(s, (sockaddr*)&ipv6, &addrLen) != -1)
|
||||
result = NetworkAddress((sockaddr&)ipv6, addrLen);
|
||||
}
|
||||
::close(s);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (result.isEmpty())
|
||||
{
|
||||
// Get first available interface
|
||||
for (unsigned i=0; i<mIPList.size() && result.isEmpty(); i++)
|
||||
{
|
||||
if (!mIPList[i].isLoopback() && mIPList[i].family() == remoteIP.family())
|
||||
result = mIPList[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
NetworkAddress NetworkHelper::ipInterfaceByIndex(int index)
|
||||
{
|
||||
for (unsigned i=0; i<mIP2IndexList.size(); i++)
|
||||
{
|
||||
if (mIP2IndexList[i].mIndex == index)
|
||||
return mIP2IndexList[i].mIP;
|
||||
}
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NetworkHelper& NetworkHelper::instance()
|
||||
{
|
||||
mGuard.lock();
|
||||
try
|
||||
{
|
||||
if (!mInstance)
|
||||
mInstance = new NetworkHelper();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
ICELogCritical(<< "Failed to create NetworkHelper instance");
|
||||
}
|
||||
mGuard.unlock();
|
||||
|
||||
return *mInstance;
|
||||
}
|
||||
|
||||
void NetworkHelper::destroyInstance()
|
||||
{
|
||||
delete mInstance;
|
||||
}
|
||||
|
||||
bool NetworkHelper::hasIPv4() const
|
||||
{
|
||||
// Check interface list and see if it has LAN or public IP
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
for (const auto& item: mInterfaceList)
|
||||
#else
|
||||
for (const auto& item: mIPList)
|
||||
#endif
|
||||
if (item.family() == AF_INET && (item.isLAN() || item.isPublic()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkHelper::hasIPv6() const
|
||||
{
|
||||
#if defined(TARGET_WIN) && !defined(WINDOWS_RT)
|
||||
for (const auto& item : mInterfaceList)
|
||||
#else
|
||||
for (const auto& item: mIPList)
|
||||
#endif
|
||||
if (item.family() == AF_INET6 && (item.isLAN() || item.isPublic()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkHelper::NetworkToHost(const in6_addr& addr6, uint32_t* output)
|
||||
{
|
||||
for (int i=0; i<4; i++)
|
||||
#if defined(TARGET_WIN)
|
||||
output[i] = ntohl(((uint32_t*)addr6.u.Byte[0])[i]);
|
||||
#elif defined(TARGET_IOS) || defined(TARGET_OSX)
|
||||
output[i] = ntohl(addr6.__u6_addr.__u6_addr32[i]);
|
||||
#elif defined(TARGET_LINUX)
|
||||
output[i] = ntohl(addr6.__in6_u.__u6_addr32[i]);
|
||||
#elif defined(TARGET_ANDROID)
|
||||
output[i] = ntohl(addr6.in6_u.u6_addr32[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkHelper::HostToNetwork(const uint32_t* input, in6_addr& output)
|
||||
{
|
||||
for (int i=0; i<4; i++)
|
||||
#if defined(TARGET_WIN)
|
||||
((uint32_t*)&output.u.Byte[0])[i] = htonl(input[i]);
|
||||
#elif defined(TARGET_OSX) || defined(TARGET_IOS)
|
||||
output.__u6_addr.__u6_addr32[i] = htonl(input[i]);
|
||||
#elif defined(TARGET_LINUX)
|
||||
output.__in6_u.__u6_addr32[i] = htonl(input[i]);
|
||||
#elif defined(TARGET_ANDROID)
|
||||
output.in6_u.u6_addr32[i] = htonl(input[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
NetworkHelper* NetworkHelper::mInstance = NULL;
|
||||
Mutex NetworkHelper::mGuard;
|
||||
|
||||
//-------------------------------------- INHDestroy ---------------------------------
|
||||
class INHDestroy
|
||||
{
|
||||
public:
|
||||
INHDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
~INHDestroy()
|
||||
{
|
||||
NetworkHelper::destroyInstance();
|
||||
}
|
||||
};
|
||||
|
||||
INHDestroy GINHDestroyer;
|
||||
79
src/libs/ice/ICENetworkHelper.h
Normal file
79
src/libs/ice/ICENetworkHelper.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_NETWORK_HELPER_H
|
||||
#define __ICE_NETWORK_HELPER_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICESync.h"
|
||||
#include "ICEAddress.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <Iphlpapi.h>
|
||||
#else
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
class NetworkHelper
|
||||
{
|
||||
public:
|
||||
NetworkHelper();
|
||||
~NetworkHelper();
|
||||
|
||||
enum
|
||||
{
|
||||
NetworkType_None,
|
||||
NetworkType_WiFi,
|
||||
NetworkType_3G
|
||||
};
|
||||
|
||||
Mutex& guard();
|
||||
|
||||
/* Returns list of IP4 interfaces installed in system. */
|
||||
std::vector<NetworkAddress>& interfaceList();
|
||||
|
||||
bool hasIPv4() const;
|
||||
bool hasIPv6() const;
|
||||
|
||||
/* Finds source interface for specified remote address. */
|
||||
NetworkAddress sourceInterface(const NetworkAddress& remoteIP);
|
||||
|
||||
void reload(int networkType);
|
||||
|
||||
static NetworkHelper& instance();
|
||||
static void destroyInstance();
|
||||
|
||||
static void NetworkToHost(const in6_addr& addr6, uint32_t* output);
|
||||
static void HostToNetwork(const uint32_t* input, in6_addr& output);
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
struct IP2Index
|
||||
{
|
||||
NetworkAddress mIP;
|
||||
DWORD mIndex;
|
||||
};
|
||||
std::vector<IP2Index> mIP2IndexList;
|
||||
std::vector<NetworkAddress> mInterfaceList;
|
||||
|
||||
void processAdaptersList(IP_ADAPTER_ADDRESSES* addresses);
|
||||
NetworkAddress ipInterfaceByIndex(int index);
|
||||
#else
|
||||
std::vector<NetworkAddress> mIPList;
|
||||
#endif
|
||||
static NetworkHelper* mInstance;
|
||||
static Mutex mGuard;
|
||||
Mutex mInstanceGuard;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
94
src/libs/ice/ICEPacketTimer.cpp
Normal file
94
src/libs/ice/ICEPacketTimer.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEPacketTimer.h"
|
||||
#include "ICETime.h"
|
||||
|
||||
using namespace ice;
|
||||
PacketScheduler::PacketScheduler()
|
||||
{
|
||||
mTimestamp = 0;
|
||||
mAttemptCounter = 0;
|
||||
mInitialRTO = 100;
|
||||
mLastRTO = 100;
|
||||
}
|
||||
|
||||
PacketScheduler::~PacketScheduler()
|
||||
{
|
||||
}
|
||||
|
||||
void PacketScheduler::setInitialRTO(int value)
|
||||
{
|
||||
mInitialRTO = value;
|
||||
}
|
||||
|
||||
int PacketScheduler::initialRTO()
|
||||
{
|
||||
return mInitialRTO;
|
||||
}
|
||||
|
||||
void PacketScheduler::start()
|
||||
{
|
||||
mLastRTO = mInitialRTO;
|
||||
mAttemptCounter = 0;
|
||||
mTimestamp = 0;//ICETimeHelper::timestamp();
|
||||
}
|
||||
|
||||
void PacketScheduler::stop()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
bool PacketScheduler::isTimeToRetransmit()
|
||||
{
|
||||
if (!mTimestamp)
|
||||
{
|
||||
mTimestamp = ICETimeHelper::timestamp();
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned currentTime = ICETimeHelper::timestamp();
|
||||
unsigned delta = ICETimeHelper::findDelta(mTimestamp, currentTime);
|
||||
|
||||
return delta >= mLastRTO;
|
||||
}
|
||||
|
||||
/// Instructs timer that attempt made
|
||||
void PacketScheduler::attemptMade()
|
||||
{
|
||||
// Increase attempt counter
|
||||
mAttemptCounter++;
|
||||
|
||||
// Save new timestamp
|
||||
mTimestamp = ICETimeHelper::timestamp();
|
||||
|
||||
// Increase mLastRTO
|
||||
#ifndef ICE_SIMPLE_SCHEDULE
|
||||
mLastRTO *= 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Checks if attempt limit reached
|
||||
bool PacketScheduler::isAttemptLimitReached()
|
||||
{
|
||||
return mAttemptCounter >= ICE_TRANSACTION_RTO_LIMIT;
|
||||
}
|
||||
|
||||
/// Checks if timeout happens
|
||||
bool PacketScheduler::isTimeout()
|
||||
{
|
||||
// Are attempts to send finished?
|
||||
if (!isAttemptLimitReached())
|
||||
return false;
|
||||
|
||||
// Get current time
|
||||
unsigned int currentTime = ICETimeHelper::timestamp();
|
||||
|
||||
// Get difference between current time and last send attempt
|
||||
unsigned int delta = ICETimeHelper::findDelta(mTimestamp, currentTime);
|
||||
|
||||
return delta > mLastRTO * 16;
|
||||
}
|
||||
43
src/libs/ice/ICEPacketTimer.h
Normal file
43
src/libs/ice/ICEPacketTimer.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_PACKET_TIMER_H
|
||||
#define __ICE_PACKET_TIMER_H
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
class PacketScheduler
|
||||
{
|
||||
public:
|
||||
PacketScheduler();
|
||||
~PacketScheduler();
|
||||
|
||||
void setInitialRTO(int value);
|
||||
int initialRTO();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
bool isTimeToRetransmit();
|
||||
|
||||
/// Instructs timer that attempt made
|
||||
void attemptMade();
|
||||
|
||||
/// Checks if attempt limit reached
|
||||
bool isAttemptLimitReached();
|
||||
|
||||
/// Checks if timeout happens
|
||||
bool isTimeout();
|
||||
|
||||
protected:
|
||||
unsigned int mTimestamp;
|
||||
unsigned int mAttemptCounter;
|
||||
unsigned int mInitialRTO;
|
||||
unsigned int mLastRTO;
|
||||
};
|
||||
|
||||
} //end of namespace
|
||||
|
||||
#endif
|
||||
22
src/libs/ice/ICEPlatform.cpp
Normal file
22
src/libs/ice/ICEPlatform.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <ctype.h>
|
||||
char* strupr(char* buffer)
|
||||
{
|
||||
char* result = buffer;
|
||||
|
||||
while (*buffer)
|
||||
{
|
||||
*buffer = toupper(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
119
src/libs/ice/ICEPlatform.h
Normal file
119
src/libs/ice/ICEPlatform.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_PLATFORM_H
|
||||
#define __ICE_PLATFORM_H
|
||||
|
||||
#define NoIndex 0xFFFFFFFF
|
||||
|
||||
enum AddressFamily
|
||||
{
|
||||
IPv4 = 1,
|
||||
IPv6 = 2
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include <ws2tcpip.h>
|
||||
# include <time.h>
|
||||
# define MINVALUE(X,Y) (((X)<(Y)) ? (X) : (Y))
|
||||
# define MAXVALUE(X,Y) (((X)>(Y)) ? (X) : (Y))
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <stdlib.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netinet/in.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
# include <algorithm>
|
||||
# define MINVALUE(X,Y) (((X)<(Y)) ? (X) : (Y))
|
||||
# define MAXVALUE(X,Y) (((X)>(Y)) ? (X) : (Y))
|
||||
|
||||
#ifndef SOCKET
|
||||
typedef int SOCKET;
|
||||
#endif
|
||||
|
||||
extern char* strupr(char*);
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
# define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// TURN channel prefix
|
||||
typedef unsigned short TurnPrefix;
|
||||
|
||||
|
||||
// Limit of candidates per SIP offer/answer
|
||||
#define ICE_CANDIDATE_LIMIT 64
|
||||
|
||||
// Limit of connection checks
|
||||
#define ICE_CONNCHECK_LIMIT 100
|
||||
|
||||
// Connection checks timer interval (in milliseconds)
|
||||
#define ICE_SCHEDULE_TIMER_INTERVAL 5
|
||||
|
||||
#define ICE_PERMISSIONS_REFRESH_INTERVAL 240
|
||||
|
||||
// Turns on OutputDebugString() logging
|
||||
#define ICE_REALTIME_LOG
|
||||
|
||||
// Enables keep-alive packets. It MUST be defined! There is only 1 reason to undefine it - debugging.
|
||||
#define ICE_ENABLE_KEEPALIVE
|
||||
|
||||
#define ICE_SKIP_LINKLOCAL
|
||||
#define ICE_SKIP_RELAYED_CHECKS
|
||||
|
||||
//#define ICE_IPV6_SUPPORT
|
||||
//#define ICE_LOOPBACK_SUPPORT
|
||||
|
||||
//#define ICE_DISABLE_KEEP
|
||||
|
||||
// Makes check list shorter. Most checks are triggered in this case.
|
||||
#define ICE_SMART_PRUNE_CHECKLIST
|
||||
|
||||
// Simulates symmetric NAT behavior - stack rejects all data coming not from specified STUN/TURN servers.
|
||||
//#define ICE_EMULATE_SYMMETRIC_NAT
|
||||
|
||||
// Publishes more reflexive candidates than was gathered.
|
||||
// The virtual candidates will have port number +1 +2 +3 ... +ICE_VIRTUAL_CANDIDATES
|
||||
//
|
||||
#define ICE_VIRTUAL_CANDIDATES (0)
|
||||
|
||||
// Use simple model to schedule connectivity checks
|
||||
//#define ICE_SIMPLE_SCHEDULE
|
||||
|
||||
// Limit of packet retransmission during ice checks
|
||||
#define ICE_TRANSACTION_RTO_LIMIT (10)
|
||||
|
||||
#define ICE_POSTPONE_RELAYEDCHECKS
|
||||
|
||||
// #define ICE_AGGRESSIVE
|
||||
// Use aggressive nomination + treat requests as confirmations
|
||||
// #define ICE_VERYAGGRESSIVE
|
||||
|
||||
// Define to emulate network problem
|
||||
//#define ICE_TEST_VERYAGGRESSIVE
|
||||
|
||||
// Use this define to avoid gathering reflexive/relayed candidates for public IP address
|
||||
//#define ICE_REST_ON_PUBLICIP
|
||||
|
||||
// #define ICE_DONT_CANCEL_CHECKS_ON_SUCCESS
|
||||
|
||||
// Defines the waiting time to accumulate valid pairs to choose best of them later. Can be zero.
|
||||
#define ICE_NOMINATION_WAIT_INTERVAL (50)
|
||||
|
||||
#define MAX_CLIENTCHANNELBIND_ATTEMPTS (1)
|
||||
|
||||
#define ICE_CACHE_REALM_NONCE
|
||||
|
||||
// Should be 1100 in normal conditions. 1000000 is for debugging
|
||||
#define ICE_TIMEOUT_VALUE 1100
|
||||
|
||||
|
||||
#endif
|
||||
417
src/libs/ice/ICERelaying.cpp
Normal file
417
src/libs/ice/ICERelaying.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICERelaying.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICETime.h"
|
||||
#include "ICEMD5.h"
|
||||
#include "ICELog.h"
|
||||
#include "ICEStream.h"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
// ------------------ ClientAllocate -----------------
|
||||
|
||||
ClientAllocate::ClientAllocate(unsigned int lifetime)
|
||||
:AuthTransaction(), mLifetime(lifetime), mWireFamily(AF_INET), mAllocFamily(AF_INET)
|
||||
{
|
||||
assert(lifetime > 60 || !lifetime);
|
||||
setComment("ClientAllocate");
|
||||
addLongTermCredentials(true);
|
||||
}
|
||||
|
||||
ClientAllocate::~ClientAllocate()
|
||||
{
|
||||
}
|
||||
|
||||
NetworkAddress& ClientAllocate::relayedAddress()
|
||||
{
|
||||
return mRelayedAddr;
|
||||
}
|
||||
|
||||
NetworkAddress& ClientAllocate::reflexiveAddress()
|
||||
{
|
||||
return mReflexiveAddr;
|
||||
}
|
||||
|
||||
NetworkAddress& ClientAllocate::responseAddress()
|
||||
{
|
||||
return mResponseAddr;
|
||||
}
|
||||
|
||||
void ClientAllocate::setInitialRequest(StunMessage& msg)
|
||||
{
|
||||
if (keepalive())
|
||||
{
|
||||
// Build refresh request
|
||||
msg.setMessageType(ice::StunMessage::Refresh);
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Build allocate request
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.setMessageType(StunMessage::Allocate);
|
||||
|
||||
// Add UDP transport attribute (RequestedTransport is UDP by default)
|
||||
msg.setAttribute(new RequestedTransport());
|
||||
|
||||
// Add request family attribute
|
||||
if (mAllocFamily != mWireFamily)
|
||||
msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientAllocate::setAuthenticatedRequest(StunMessage& msg)
|
||||
{
|
||||
if (keepalive())
|
||||
{
|
||||
// Build refresh request
|
||||
msg.setMessageType(ice::StunMessage::Refresh);
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.lifetimeAttr().setLifetime(mLifetime);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.setMessageType(StunMessage::Allocate);
|
||||
|
||||
// Add UDP transport attribute
|
||||
msg.setAttribute(new RequestedTransport());
|
||||
|
||||
// Add LIFETIME
|
||||
msg.lifetimeAttr().setLifetime(mLifetime);
|
||||
|
||||
// Add request family attribute
|
||||
if (mAllocFamily != mWireFamily)
|
||||
msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6));
|
||||
}
|
||||
}
|
||||
|
||||
void ClientAllocate::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress)
|
||||
{
|
||||
if (msg.hasAttribute(StunAttribute::XorMappedAddress))
|
||||
mReflexiveAddr = msg.xorMappedAddressAttr().address();
|
||||
|
||||
if (msg.hasAttribute(StunAttribute::XorRelayedAddress))
|
||||
mRelayedAddr = msg.xorRelayedAddressAttr().address();
|
||||
|
||||
if (msg.hasAttribute(StunAttribute::Lifetime))
|
||||
mLifetime = msg.lifetimeAttr().lifetime();
|
||||
|
||||
mResponseAddr = sourceAddress;
|
||||
ICELogDebug(<< "Allocated for " << (int)mLifetime << " seconds.");
|
||||
}
|
||||
|
||||
int ClientAllocate::lifetime()
|
||||
{
|
||||
return mLifetime;
|
||||
}
|
||||
|
||||
void ClientAllocate::setWireFamily(int family)
|
||||
{
|
||||
mWireFamily = family;
|
||||
}
|
||||
|
||||
int ClientAllocate::getWireFamily() const
|
||||
{
|
||||
return mWireFamily;
|
||||
}
|
||||
|
||||
void ClientAllocate::setAllocFamily(int family)
|
||||
{
|
||||
mAllocFamily = family;
|
||||
}
|
||||
|
||||
int ClientAllocate::getAllocFamily() const
|
||||
{
|
||||
return mAllocFamily;
|
||||
}
|
||||
|
||||
|
||||
//------------------- ClientRefresh -------------------------------
|
||||
ClientRefresh::ClientRefresh(unsigned int lifetime, Stream* stream, ClientAllocate* allocate)
|
||||
:AuthTransaction(), mLifetime(lifetime), mStream(stream)
|
||||
{
|
||||
assert(stream);
|
||||
setComment("ClientRefresh");
|
||||
addLongTermCredentials(true);
|
||||
|
||||
// Copy data from Allocate transaction
|
||||
if (allocate)
|
||||
{
|
||||
setDestination( allocate->destination() );
|
||||
setPassword( stream->mConfig.mTurnPassword );
|
||||
setUsername( stream->mConfig.mTurnUsername );
|
||||
setComponent( allocate->component() );
|
||||
#ifdef ICE_CACHE_REALM_NONCE
|
||||
setRealm( allocate->realm() );
|
||||
setNonce( allocate->nonce() );
|
||||
#endif
|
||||
mRelayed = allocate->relayedAddress();
|
||||
mReflexive = allocate->reflexiveAddress();
|
||||
}
|
||||
}
|
||||
|
||||
ClientRefresh::~ClientRefresh()
|
||||
{
|
||||
}
|
||||
|
||||
void ClientRefresh::setInitialRequest(StunMessage& msg)
|
||||
{
|
||||
ICELogDebug(<< "Prepare to run ClientRefresh on TURN server with lifetime " << mLifetime);
|
||||
msg.setMessageType(ice::StunMessage::Refresh);
|
||||
msg.setMessageClass(ice::StunMessage::RequestClass);
|
||||
}
|
||||
|
||||
void ClientRefresh::setAuthenticatedRequest(StunMessage& msg)
|
||||
{
|
||||
msg.setMessageType(StunMessage::Refresh);
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.lifetimeAttr().setLifetime(mLifetime);
|
||||
}
|
||||
|
||||
void ClientRefresh::processSuccessMessage(StunMessage& /*msg*/, NetworkAddress& /*sourceAddress*/)
|
||||
{
|
||||
if (mLifetime)
|
||||
{
|
||||
ICELogDebug(<< "TURN allocation refreshed for " << (int)mLifetime << " seconds.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mStream)
|
||||
{
|
||||
if (mStream->mTurnAllocated > 0)
|
||||
mStream->mTurnAllocated--;
|
||||
}
|
||||
ICELogDebug(<< "TURN allocation is deleted.");
|
||||
}
|
||||
}
|
||||
|
||||
void ClientRefresh::processError()
|
||||
{
|
||||
if (mStream)
|
||||
{
|
||||
if (!mLifetime)
|
||||
{
|
||||
if (mStream->mTurnAllocated > 0)
|
||||
mStream->mTurnAllocated--;
|
||||
ICELogCritical(<< "TURN allocation is not deleted due to error " << errorCode() << " " << errorResponse());
|
||||
}
|
||||
else
|
||||
ICELogDebug(<< "ClientRefresh failed due to error " << errorCode() << " " << errorResponse());
|
||||
}
|
||||
}
|
||||
|
||||
NetworkAddress ClientRefresh::relayedAddress()
|
||||
{
|
||||
return mRelayed;
|
||||
}
|
||||
|
||||
NetworkAddress ClientRefresh::reflexiveAddress()
|
||||
{
|
||||
return mReflexive;
|
||||
}
|
||||
|
||||
//------------------- ClientChannelBind ----------------------------
|
||||
|
||||
static TurnPrefix GPrefix = 0;
|
||||
static Mutex GPrefixGuard;
|
||||
static TurnPrefix obtainNewPrefix()
|
||||
{
|
||||
Lock l(GPrefixGuard);
|
||||
|
||||
// Generate initial value if needed
|
||||
if (!GPrefix)
|
||||
GPrefix = (rand() % (0x7FFE - 0x4000)) + 0x4000;
|
||||
|
||||
// Avoid logical overflow
|
||||
if (GPrefix == 0x7FFE)
|
||||
GPrefix = 0x4000;
|
||||
|
||||
return ++GPrefix;
|
||||
}
|
||||
|
||||
ClientChannelBind::ClientChannelBind(const NetworkAddress& address)
|
||||
:AuthTransaction(), mPeerAddress(address)
|
||||
{
|
||||
setComment( "ClientChannelBind" );
|
||||
// Compute prefix
|
||||
mChannelPrefix = obtainNewPrefix();
|
||||
ICELogInfo(<< "Channel prefix for TURN channel bind is " << mChannelPrefix);
|
||||
addLongTermCredentials(true);
|
||||
}
|
||||
|
||||
ClientChannelBind::~ClientChannelBind()
|
||||
{
|
||||
}
|
||||
|
||||
void ClientChannelBind::setInitialRequest(StunMessage& msg)
|
||||
{
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.setMessageType(StunMessage::ChannelBind);
|
||||
|
||||
msg.channelNumberAttr().setChannelNumber(mChannelPrefix);
|
||||
msg.xorPeerAddressAttr().address() = mPeerAddress;
|
||||
}
|
||||
|
||||
void ClientChannelBind::setAuthenticatedRequest(StunMessage& msg)
|
||||
{
|
||||
setInitialRequest(msg);
|
||||
}
|
||||
|
||||
unsigned short ClientChannelBind::channelPrefix()
|
||||
{
|
||||
return mChannelPrefix;
|
||||
}
|
||||
|
||||
bool ClientChannelBind::processData(StunMessage& msg, NetworkAddress& address)
|
||||
{
|
||||
return AuthTransaction::processData(msg, address);
|
||||
}
|
||||
|
||||
void ClientChannelBind::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress)
|
||||
{
|
||||
ICELogDebug(<< mPeerAddress.toStdString() << " is bound to " << mChannelPrefix);
|
||||
// Make this transaction keepalive
|
||||
setKeepalive( true );
|
||||
setType( KeepAlive );
|
||||
setInterval( ICE_PERMISSIONS_REFRESH_INTERVAL );
|
||||
setTimestamp( ICETimeHelper::timestamp() );
|
||||
}
|
||||
|
||||
void ClientChannelBind::processError()
|
||||
{
|
||||
ICELogCritical(<< "Failed to bind channel with error " << errorCode());
|
||||
}
|
||||
|
||||
NetworkAddress ClientChannelBind::peerAddress()
|
||||
{
|
||||
return mPeerAddress;
|
||||
}
|
||||
//----------------- ClientCreatePermission ------------------------
|
||||
|
||||
ClientCreatePermission::ClientCreatePermission()
|
||||
:AuthTransaction()
|
||||
{
|
||||
setComment("ClientCreatePermission");
|
||||
addLongTermCredentials(true);
|
||||
}
|
||||
|
||||
ClientCreatePermission::~ClientCreatePermission()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void ClientCreatePermission::addIpAddress(const NetworkAddress& ip)
|
||||
{
|
||||
// Skip loopback / empty / LAN / IPv6 addresses addresses
|
||||
if (!ip.isLoopback() && !ip.isEmpty() && !ip.isLAN() && ip.family() == AF_INET)
|
||||
{
|
||||
for (unsigned i=0; i<mIPAddressList.size(); i++)
|
||||
if (mIPAddressList[i].ip() == ip.ip())
|
||||
return;
|
||||
|
||||
ICELogInfo( << "Permission is to be installed for " << ip.toStdString());
|
||||
mIPAddressList.push_back(ip);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientCreatePermission::processSuccessMessage(StunMessage& /*msg*/, NetworkAddress& /*sourceAddress*/)
|
||||
{
|
||||
ICELogDebug(<< "Set permissions ok.");
|
||||
setKeepalive( true );
|
||||
setType( KeepAlive );
|
||||
setInterval( ICE_PERMISSIONS_REFRESH_INTERVAL );
|
||||
setTimestamp( ICETimeHelper::timestamp() );
|
||||
}
|
||||
|
||||
void ClientCreatePermission::setInitialRequest(StunMessage& msg)
|
||||
{
|
||||
msg.setMessageClass(StunMessage::RequestClass);
|
||||
msg.setMessageType(StunMessage::CreatePermission);
|
||||
|
||||
for (unsigned i=0; i<mIPAddressList.size(); i++)
|
||||
{
|
||||
XorPeerAddress* xpa = new XorPeerAddress();
|
||||
xpa->address() = mIPAddressList[i];
|
||||
msg.addAttribute(xpa);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClientCreatePermission::setAuthenticatedRequest(StunMessage& msg)
|
||||
{
|
||||
setInitialRequest(msg);
|
||||
}
|
||||
|
||||
ClientCreatePermission::IpList& ClientCreatePermission::ipList()
|
||||
{
|
||||
return mIPAddressList;
|
||||
}
|
||||
|
||||
// ------------------ SendIndication ----------------------------------
|
||||
SendIndication::SendIndication()
|
||||
{
|
||||
}
|
||||
|
||||
SendIndication::~SendIndication()
|
||||
{
|
||||
}
|
||||
|
||||
void SendIndication::setTarget(NetworkAddress& addr)
|
||||
{
|
||||
mTarget = addr;
|
||||
}
|
||||
|
||||
NetworkAddress& SendIndication::target()
|
||||
{
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
void SendIndication::setPlainData(ByteBuffer& plain)
|
||||
{
|
||||
mPlainData = plain;
|
||||
}
|
||||
|
||||
ByteBuffer& SendIndication::plainData()
|
||||
{
|
||||
return mPlainData;
|
||||
}
|
||||
|
||||
ByteBuffer* SendIndication::buildPacket()
|
||||
{
|
||||
StunMessage m;
|
||||
m.setMessageClass(StunMessage::IndicationClass);
|
||||
m.setMessageType(StunMessage::Send);
|
||||
|
||||
XorPeerAddress* xpa = new XorPeerAddress();
|
||||
xpa->address() = mTarget;
|
||||
|
||||
DataAttribute* da = new DataAttribute();
|
||||
da->setData(mPlainData);
|
||||
|
||||
m.setAttribute(xpa);
|
||||
m.setAttribute(da);
|
||||
|
||||
ByteBuffer* result = new ByteBuffer();
|
||||
m.buildPacket(*result, "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ByteBuffer* SendIndication::buildPacket(NetworkAddress& target, ByteBuffer& data, NetworkAddress& relay, int component)
|
||||
{
|
||||
SendIndication si;
|
||||
si.setTarget( target );
|
||||
si.setPlainData( data );
|
||||
|
||||
ByteBuffer* result = si.buildPacket();
|
||||
result->setComponent( component );
|
||||
result->setRemoteAddress( relay );
|
||||
|
||||
return result;
|
||||
}
|
||||
136
src/libs/ice/ICERelaying.h
Normal file
136
src/libs/ice/ICERelaying.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_RELAYING_H
|
||||
#define __ICE_RELAYING_H
|
||||
|
||||
#include "ICEStunTransaction.h"
|
||||
#include "ICEAddress.h"
|
||||
#include "ICEAuthTransaction.h"
|
||||
#include "ICEBinding.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
const int ChannelBindTimeout = 10 * 60 * 1000;
|
||||
const int PermissionTimeout = 5 * 60 * 1000;
|
||||
|
||||
// This class encapsulates TURN Allocate transaction
|
||||
// Usage: create instance, set password and login, generate data.
|
||||
// pass incoming data while GetState() != StunTransaction::Failed or Success
|
||||
|
||||
class ClientAllocate: public AuthTransaction
|
||||
{
|
||||
public:
|
||||
ClientAllocate(unsigned int lifetime);
|
||||
virtual ~ClientAllocate();
|
||||
|
||||
NetworkAddress& relayedAddress();
|
||||
NetworkAddress& reflexiveAddress();
|
||||
NetworkAddress& responseAddress();
|
||||
int lifetime();
|
||||
void setWireFamily(int family);
|
||||
int getWireFamily() const;
|
||||
void setAllocFamily(int family);
|
||||
int getAllocFamily() const;
|
||||
|
||||
virtual void setInitialRequest(StunMessage& msg);
|
||||
virtual void setAuthenticatedRequest(StunMessage& msg);
|
||||
virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress);
|
||||
|
||||
protected:
|
||||
NetworkAddress mRelayedAddr;
|
||||
NetworkAddress mReflexiveAddr;
|
||||
NetworkAddress mResponseAddr;
|
||||
unsigned int mLifetime;
|
||||
int mWireFamily;
|
||||
int mAllocFamily;
|
||||
};
|
||||
|
||||
class ClientChannelBind: public AuthTransaction
|
||||
{
|
||||
public:
|
||||
ClientChannelBind(const NetworkAddress& peerAddress);
|
||||
virtual ~ClientChannelBind();
|
||||
|
||||
/*Channel prefix must be 0x4000 through 0x7FFF: These values are the allowed channel
|
||||
numbers (16,383 possible values)
|
||||
*/
|
||||
unsigned short channelPrefix();
|
||||
|
||||
void setInitialRequest(StunMessage& msg);
|
||||
void setAuthenticatedRequest(StunMessage& msg);
|
||||
void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress);
|
||||
bool processData(StunMessage& msg, NetworkAddress& address);
|
||||
void processError();
|
||||
NetworkAddress peerAddress();
|
||||
|
||||
protected:
|
||||
unsigned short mChannelPrefix;
|
||||
NetworkAddress mPeerAddress;
|
||||
};
|
||||
|
||||
class ClientCreatePermission: public AuthTransaction
|
||||
{
|
||||
public:
|
||||
typedef std::vector<NetworkAddress> IpList;
|
||||
|
||||
ClientCreatePermission();
|
||||
virtual ~ClientCreatePermission();
|
||||
|
||||
void addIpAddress(const NetworkAddress& ip);
|
||||
|
||||
virtual void setInitialRequest(StunMessage& msg);
|
||||
virtual void setAuthenticatedRequest(StunMessage& msg);
|
||||
virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress);
|
||||
|
||||
IpList& ipList();
|
||||
|
||||
protected:
|
||||
IpList mIPAddressList;
|
||||
};
|
||||
|
||||
struct Stream;
|
||||
class ClientRefresh: public AuthTransaction
|
||||
{
|
||||
public:
|
||||
ClientRefresh(unsigned int lifetime, Stream* stream, ClientAllocate* allocate = NULL);
|
||||
virtual ~ClientRefresh();
|
||||
|
||||
virtual void setInitialRequest(StunMessage& msg);
|
||||
virtual void setAuthenticatedRequest(StunMessage& msg);
|
||||
virtual void processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress);
|
||||
virtual void processError();
|
||||
unsigned int lifetime() { return mLifetime; }
|
||||
NetworkAddress relayedAddress();
|
||||
NetworkAddress reflexiveAddress();
|
||||
|
||||
protected:
|
||||
unsigned int mLifetime;
|
||||
Stream* mStream;
|
||||
NetworkAddress mRelayed, mReflexive;
|
||||
};
|
||||
|
||||
class SendIndication
|
||||
{
|
||||
public:
|
||||
SendIndication();
|
||||
~SendIndication();
|
||||
|
||||
void setTarget(NetworkAddress& addr);
|
||||
NetworkAddress& target();
|
||||
void setPlainData(ByteBuffer& plain);
|
||||
ByteBuffer& plainData();
|
||||
|
||||
ByteBuffer* buildPacket();
|
||||
|
||||
static ByteBuffer* buildPacket(NetworkAddress& target, ByteBuffer& data, NetworkAddress& relay, int component);
|
||||
|
||||
protected:
|
||||
NetworkAddress mTarget;
|
||||
ByteBuffer mPlainData;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
446
src/libs/ice/ICEReliableTransport.cpp
Normal file
446
src/libs/ice/ICEReliableTransport.cpp
Normal file
@@ -0,0 +1,446 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEReliableTransport.h"
|
||||
#include "ICETypes.h"
|
||||
#include <algorithm>
|
||||
using namespace ICEImpl;
|
||||
|
||||
//------------------- ReliableTransport::Packet --------------------------
|
||||
ReliableTransport::Packet::Packet()
|
||||
{
|
||||
mType = AppData;
|
||||
mSeqno = 0;
|
||||
mAppSeqno = 0;
|
||||
}
|
||||
|
||||
ReliableTransport::Packet::~Packet()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ReliableTransport::Packet::parse(const void* dataptr, int datasize, Encryption* encryption)
|
||||
{
|
||||
assert(encryption != NULL);
|
||||
assert(dataptr != NULL);
|
||||
assert(datasize != 0);
|
||||
|
||||
// 1) Check if packet has mEncryption->GetBlockSize() bytes boundary
|
||||
if (datasize % encryption->blockSize())
|
||||
return false;
|
||||
|
||||
// 2) Save data
|
||||
mData.enqueueBuffer(dataptr, datasize);
|
||||
|
||||
// 2) Decrypt it using mEncryption provider
|
||||
encryption->decrypt(mData.mutableData(), mData.size());
|
||||
|
||||
// 3) Check CRC from first 4 bytes (it is for little endian only)
|
||||
unsigned crc = mData.dequeueUInt();
|
||||
if (crc != encryption->crc(mData.data(), mData.size()))
|
||||
return false;
|
||||
|
||||
// 4) Check next byte for signature
|
||||
unsigned char signature = mData.dequeueUChar();
|
||||
if (signature != RTSignature)
|
||||
return false;
|
||||
|
||||
// 5) Next 2 bits are type of packet - AppData, Confirmation, Request or Ack
|
||||
unsigned short ts = mData.dequeueUShort();
|
||||
|
||||
mType = (Packet::Type)((ts & 0xC000) >> 14);
|
||||
|
||||
// 6) Next 14 bits are real size of packet
|
||||
unsigned short realsize = ts & 0x3FFF;
|
||||
|
||||
// 7) Seqno
|
||||
mSeqno = mData.dequeueUShort();
|
||||
|
||||
// 7) Check if we deal with AppData
|
||||
if (mType == AppData)
|
||||
mAppSeqno = mData.dequeueUShort();
|
||||
|
||||
// 8) Truncate app data to real size
|
||||
mData.truncate(realsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::Packet::build(const void* dataptr, int datasize, Encryption* encryption)
|
||||
{
|
||||
assert(encryption && dataptr && datasize);
|
||||
|
||||
mData.clear();
|
||||
|
||||
// Reserve place for CRC
|
||||
mData.enqueueUInt(0);
|
||||
|
||||
// Signature
|
||||
mData.enqueueUChar(RTSignature);
|
||||
|
||||
// Real size and type of packet
|
||||
unsigned short ts = (unsigned short)datasize;
|
||||
ts |= mType << 14;
|
||||
|
||||
// Enqueue real size and type of packet
|
||||
mData.enqueueUShort(ts);
|
||||
|
||||
// Enqueue sequence number
|
||||
mData.enqueueUShort(mSeqno);
|
||||
|
||||
// Enqueue application sequence number if needed
|
||||
if (mType == Packet::AppData)
|
||||
mData.enqueueUShort(mAppSeqno);
|
||||
|
||||
// Enqueue payload data
|
||||
mData.enqueueBuffer(dataptr, datasize);
|
||||
|
||||
// Padding with zero bytes
|
||||
int tail = mData.size() % encryption->blockSize();
|
||||
if (tail)
|
||||
{
|
||||
for (int i=0; i < encryption->blockSize() - tail; i++)
|
||||
mData.enqueueUChar(0);
|
||||
}
|
||||
|
||||
// Get CRC on packet
|
||||
unsigned crc = encryption->crc((const char*)mData.data() + 4, mData.size() - 4);
|
||||
|
||||
crc = htonl(crc); //It is here as corresponding DequeueUInt does ntohl
|
||||
memcpy(mData.mutableData(), &crc, 4);
|
||||
|
||||
// Encrypt
|
||||
encryption->encrypt(mData.mutableData(), mData.size());
|
||||
}
|
||||
|
||||
void ReliableTransport::Packet::setType(Type packetType)
|
||||
{
|
||||
mType = packetType;
|
||||
}
|
||||
|
||||
ReliableTransport::Packet::Type ReliableTransport::Packet::type()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void ReliableTransport::Packet::setSeqno(unsigned short seqno)
|
||||
{
|
||||
mSeqno = seqno;
|
||||
}
|
||||
|
||||
unsigned short ReliableTransport::Packet::seqno()
|
||||
{
|
||||
return mSeqno;
|
||||
}
|
||||
|
||||
void ReliableTransport::Packet::setAppSeqno(unsigned short seqno)
|
||||
{
|
||||
mAppSeqno = seqno;
|
||||
}
|
||||
|
||||
unsigned short ReliableTransport::Packet::appSeqno()
|
||||
{
|
||||
return mAppSeqno;
|
||||
}
|
||||
|
||||
ICEByteBuffer& ReliableTransport::Packet::data()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
//-------------------- ReliableTransport --------------------
|
||||
|
||||
ReliableTransport::ReliableTransport()
|
||||
{
|
||||
mEncryption = NULL;
|
||||
mSeqno = 0;
|
||||
}
|
||||
|
||||
ReliableTransport::~ReliableTransport()
|
||||
{
|
||||
}
|
||||
|
||||
void ReliableTransport::setMaxDatagram(int size)
|
||||
{
|
||||
mMaxDatagramSize = size;
|
||||
}
|
||||
|
||||
|
||||
int ReliableTransport::maxDatagram()
|
||||
{
|
||||
return mMaxDatagramSize;
|
||||
}
|
||||
|
||||
bool ReliableTransport::processIncoming(const void* dataptr, int datasize)
|
||||
{
|
||||
Packet* p = new Packet();
|
||||
if (p->parse(dataptr, datasize, mEncryption))
|
||||
{
|
||||
switch (p->type())
|
||||
{
|
||||
case Packet::AppData:
|
||||
processAppData(p);
|
||||
break;
|
||||
|
||||
case Packet::Confirmation:
|
||||
processConfirmation(p);
|
||||
break;
|
||||
|
||||
case Packet::Ack:
|
||||
processAck(p);
|
||||
break;
|
||||
|
||||
case Packet::Request:
|
||||
processRequest(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::queueOutgoing(const void *dataPtr, int dataSize)
|
||||
{
|
||||
// Split enqueued data to datagrams using mMaxDatagramSize value.
|
||||
// Do not forget about service bytes - seqno, appseqno, CRC, signature...
|
||||
int payloadsize = this->mMaxDatagramSize - (2 /*CRC*/ + 1 /* signature */ + 2 /* type and size */);
|
||||
|
||||
// Find packet count
|
||||
int packetcount = dataSize / payloadsize;
|
||||
if (dataSize % payloadsize)
|
||||
packetcount++;
|
||||
|
||||
// Case input pointer
|
||||
const char* dataIn = (const char*)dataPtr;
|
||||
|
||||
// Split data to packets
|
||||
for (int i=0; i<packetcount; i++)
|
||||
{
|
||||
Packet *p = new Packet();
|
||||
p->setSeqno(mSeqno++);
|
||||
p->setAppSeqno(i);
|
||||
if (i == packetcount-1 && dataSize % payloadsize)
|
||||
p->build(dataIn + i * payloadsize, dataSize % payloadsize, mEncryption);
|
||||
else
|
||||
p->build(dataIn + i * payloadsize, payloadsize, mEncryption);
|
||||
|
||||
mOutgoingData.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::processAck(Packet* p)
|
||||
{
|
||||
// Ack received for confirmation
|
||||
int count = p->data().dequeueUShort();
|
||||
for (int i=0; i<count; i++)
|
||||
{
|
||||
// Extract Confirmation packet seqno
|
||||
int seqno = p->data().dequeueUShort();
|
||||
|
||||
// Find corresponding confirmation packet and remove it
|
||||
removePacket(seqno);
|
||||
}
|
||||
|
||||
delete p;
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::processConfirmation(Packet* p)
|
||||
{
|
||||
int count = p->data().dequeueUShort();
|
||||
for (int i=0; i<count; i++)
|
||||
{
|
||||
// Extract AppData packet seqno
|
||||
int seqno = p->data().dequeueUShort();
|
||||
|
||||
// Find corresponding AppData packet and remove it
|
||||
removePacket(seqno);
|
||||
}
|
||||
|
||||
// Create Ack packet
|
||||
mOutgoingData.push_back(makeAckPacket(p->seqno()));
|
||||
|
||||
delete p;
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::processRequest(Packet* p)
|
||||
{
|
||||
int count = p->data().dequeueUShort();
|
||||
for (int i=0; i<count; i++)
|
||||
{
|
||||
// Extract AppData packet seqno
|
||||
int seqno = p->data().dequeueUShort();
|
||||
|
||||
// Find specified by seqno packet and move to top of list
|
||||
prioritizePacket(seqno);
|
||||
}
|
||||
|
||||
delete p;
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::processAppData(Packet* p)
|
||||
{
|
||||
// 1) Add seqno to confirmation list
|
||||
mConfirmationData.push_back(p->seqno());
|
||||
|
||||
// 2) Check if confirmation list if big enough to transmit confirmation packet
|
||||
if (mConfirmationData.size() >= (unsigned)MaxConfirmationQueue)
|
||||
{
|
||||
mOutgoingData.push_back(makeConfirmationPacket(mConfirmationData));
|
||||
mConfirmationData.clear();
|
||||
}
|
||||
|
||||
// 3) Move packet to mIncomingAppData with optional packet assembling
|
||||
mIncomingAppData.push_back(p);
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::removePacket(Packet::Seqno seqno)
|
||||
{
|
||||
PacketList::iterator pit = mOutgoingData.begin();
|
||||
while (pit != mOutgoingData.end())
|
||||
{
|
||||
Packet* p = *pit;
|
||||
|
||||
if (p->seqno() == seqno)
|
||||
{
|
||||
pit = mOutgoingData.erase(pit);
|
||||
delete p;
|
||||
}
|
||||
else
|
||||
pit++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::prioritizePacket(Packet::Seqno seqno)
|
||||
{
|
||||
PacketList::iterator pit = mOutgoingData.begin();
|
||||
while (pit != mOutgoingData.end())
|
||||
{
|
||||
Packet* p = *pit;
|
||||
|
||||
if (p->seqno() == seqno)
|
||||
{
|
||||
// Remove pointer from old index
|
||||
pit = mOutgoingData.erase(pit);
|
||||
|
||||
// Insert at beginning of queue
|
||||
mOutgoingData.insert(mOutgoingData.begin(), p);
|
||||
|
||||
// Exit from loop
|
||||
break;
|
||||
}
|
||||
else
|
||||
pit++;
|
||||
}
|
||||
}
|
||||
|
||||
ReliableTransport::Packet*
|
||||
ReliableTransport::makeAckPacket(Packet::Seqno seqno)
|
||||
{
|
||||
// Create packet
|
||||
Packet* p = new Packet();
|
||||
|
||||
// Set type
|
||||
p->setType(Packet::Ack);
|
||||
|
||||
// Convert seqno number to network byte order
|
||||
unsigned short value = htons(seqno);
|
||||
|
||||
// Build packet
|
||||
p->build(&value, sizeof(value), mEncryption);
|
||||
|
||||
// Return packet
|
||||
return p;
|
||||
}
|
||||
|
||||
ReliableTransport::Packet*
|
||||
ReliableTransport::makeConfirmationPacket(std::vector<Packet::Seqno> seqnovector)
|
||||
{
|
||||
// Convert seqno values to network byte order
|
||||
std::vector<Packet::Seqno> value;
|
||||
for (unsigned i=0; i<seqnovector.size(); i++)
|
||||
value.push_back(htons(seqnovector[i]));
|
||||
|
||||
// Create packet
|
||||
Packet* p = new Packet();
|
||||
|
||||
// Set type
|
||||
p->setType(Packet::Ack);
|
||||
|
||||
// Build packet
|
||||
p->build(&value[0], value.size() * sizeof(Packet::Seqno), mEncryption);
|
||||
|
||||
// Return packet
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ReliableTransport::hasAppData()
|
||||
{
|
||||
return !mIncomingAppData.empty();
|
||||
}
|
||||
|
||||
unsigned ReliableTransport::appData(void* ptr)
|
||||
{
|
||||
if (mIncomingAppData.empty())
|
||||
return 0;
|
||||
|
||||
Packet& p = *mIncomingAppData.front();
|
||||
unsigned length = p.data().size();
|
||||
if (!ptr)
|
||||
return length;
|
||||
|
||||
memcpy(ptr, p.data().data(), length);
|
||||
mIncomingAppData.erase(mIncomingAppData.begin());
|
||||
return length;
|
||||
}
|
||||
|
||||
bool
|
||||
ReliableTransport::hasPacketToSend()
|
||||
{
|
||||
return !mOutgoingData.empty();
|
||||
}
|
||||
|
||||
void
|
||||
ReliableTransport::getPacketToSend(void* outputptr, int& outputsize)
|
||||
{
|
||||
if (mOutgoingData.empty())
|
||||
{
|
||||
outputsize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!outputptr)
|
||||
{
|
||||
outputsize = mOutgoingData.front()->data().size();
|
||||
}
|
||||
else
|
||||
{
|
||||
Packet& p = *mOutgoingData.front();
|
||||
|
||||
unsigned tocopy = MINVALUE((int)outputsize, (int)p.data().size());
|
||||
memcpy(outputptr, p.data().data(), p.data().size());
|
||||
outputsize = tocopy;
|
||||
|
||||
mOutgoingData.erase(mOutgoingData.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReliableTransport::setEncryption(ICEImpl::ReliableTransport::Encryption *encryption)
|
||||
{
|
||||
mEncryption = encryption;
|
||||
}
|
||||
168
src/libs/ice/ICEReliableTransport.h
Normal file
168
src/libs/ice/ICEReliableTransport.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __RELIABLE_TRANSPORT_H
|
||||
#define __RELIABLE_TRANSPORT_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "ICEByteBuffer.h"
|
||||
|
||||
|
||||
namespace ICEImpl {
|
||||
|
||||
// ReliableTransport is protocol stack to provide reliable transport over UDP protocol. It remains packet based protocol, not stream.
|
||||
// But it guarantees integrity and order of packets.
|
||||
class ReliableTransport
|
||||
{
|
||||
public:
|
||||
// ReliableTransport encryption interface
|
||||
class Encryption
|
||||
{
|
||||
public:
|
||||
// Returns block size for encryption algorythm
|
||||
virtual int blockSize() = 0;
|
||||
|
||||
// Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
|
||||
virtual void encrypt(void* dataPtr, int dataSize) = 0;
|
||||
|
||||
// Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
|
||||
virtual void decrypt(void* dataPtr, int dataSize) = 0;
|
||||
|
||||
// Calculates CRC
|
||||
virtual unsigned crc(const void* dataptr, int datasize) = 0;
|
||||
};
|
||||
|
||||
// Signature byte value
|
||||
static const int RTSignature = 123;
|
||||
|
||||
// Maximal count of confirmation items
|
||||
static const int MaxConfirmationQueue = 50;
|
||||
|
||||
ReliableTransport();
|
||||
~ReliableTransport();
|
||||
|
||||
// Sets maximal datagram size. This value must be odd to Encryption::GetBlockSize() returned value.
|
||||
void setMaxDatagram(int size);
|
||||
|
||||
// Returns maximal datagram size
|
||||
int maxDatagram();
|
||||
|
||||
// Sets encryption interface
|
||||
void setEncryption(Encryption* encryption);
|
||||
|
||||
// Returns current encryption interface. Default is NULL.
|
||||
Encryption* encryption();
|
||||
|
||||
// Process incoming UDP packet. Returns true if packet is recognized. Otherwise it returns false.
|
||||
bool processIncoming(const void* dataPtr, int dataSize);
|
||||
|
||||
// Enqueue outgoing packet
|
||||
void queueOutgoing(const void* dataPtr, int dataSize);
|
||||
|
||||
// Checks if there are incoming application data
|
||||
bool hasAppData();
|
||||
|
||||
// Returns incoming application data. ptr may be NULL - in this case method will return packet size.
|
||||
unsigned appData(void* ptr);
|
||||
|
||||
// Checks if there are raw packet(s) to send
|
||||
bool hasPacketToSend();
|
||||
|
||||
// Returns raw packet data to send.
|
||||
void getPacketToSend(void* outputPtr, int& outputSize);
|
||||
|
||||
protected:
|
||||
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Request = 0,
|
||||
Confirmation = 1,
|
||||
Ack = 2,
|
||||
AppData = 3
|
||||
};
|
||||
|
||||
typedef unsigned short Seqno;
|
||||
typedef unsigned short AppSeqno;
|
||||
|
||||
Packet();
|
||||
~Packet();
|
||||
|
||||
bool parse(const void* dataptr, int datasize, Encryption* encryption);
|
||||
void build(const void* dataptr, int datasize, Encryption* encryption);
|
||||
void setType(Type packetType);
|
||||
Type type();
|
||||
void setSeqno(Seqno seqno);
|
||||
Seqno seqno();
|
||||
void setAppSeqno(AppSeqno seqno);
|
||||
AppSeqno appSeqno();
|
||||
ByteBuffer& data();
|
||||
|
||||
protected:
|
||||
Type mType;
|
||||
Seqno mSeqno;
|
||||
AppSeqno mAppSeqno;
|
||||
ByteBuffer mData;
|
||||
};
|
||||
|
||||
// List of UDP packets
|
||||
typedef std::vector<Packet*> PacketList;
|
||||
|
||||
// Incoming UDP packets
|
||||
PacketList mIncomingData;
|
||||
|
||||
// Outgoing UDP packets
|
||||
PacketList mOutgoingData;
|
||||
|
||||
// Used encryption provider
|
||||
Encryption* mEncryption;
|
||||
|
||||
// Maximal datagram size
|
||||
int mMaxDatagramSize;
|
||||
|
||||
// Vector of packet numbers to confirm
|
||||
std::vector<Packet::Seqno> mConfirmationData;
|
||||
|
||||
// Vector of packet numbers to ack
|
||||
std::vector<Packet::Seqno> mAckData;
|
||||
|
||||
// Incoming decrypted application data packets
|
||||
PacketList mIncomingAppData;
|
||||
|
||||
// Seqno generator
|
||||
Packet::Seqno mSeqno;
|
||||
|
||||
// Process incoming Ack packets
|
||||
void processAck(Packet* p);
|
||||
|
||||
// Process confirmation packets
|
||||
void processConfirmation(Packet* p);
|
||||
|
||||
// Process requests packets
|
||||
void processRequest(Packet* p);
|
||||
|
||||
// Process app. data
|
||||
void processAppData(Packet* p);
|
||||
|
||||
// Remove packet from outgoing queue
|
||||
void removePacket(Packet::Seqno seqno);
|
||||
|
||||
// Prioritizes packet with specified seqno
|
||||
void prioritizePacket(Packet::Seqno seqno);
|
||||
|
||||
// Creates Ack packet for specified seqno index
|
||||
Packet* makeAckPacket(Packet::Seqno seqno);
|
||||
|
||||
// Creates Confirm packet for specified seqno indexes
|
||||
Packet* makeConfirmationPacket(std::vector<unsigned short> seqnovector);
|
||||
};
|
||||
} // end of namespace ICEImpl
|
||||
|
||||
#endif
|
||||
31
src/libs/ice/ICESHA1.cpp
Normal file
31
src/libs/ice/ICESHA1.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICESHA1.h"
|
||||
|
||||
#ifdef USE_CRYPTOPP
|
||||
|
||||
#include "../CryptoPP/hmac.h"
|
||||
#include "../CryptoPP/sha.h"
|
||||
|
||||
void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize)
|
||||
{
|
||||
CryptoPP::HMAC<CryptoPP::SHA1> mac((const byte*)key, keySize);
|
||||
|
||||
mac.Update((const byte*)inputData, inputSize);
|
||||
mac.Final((byte*)outputData);
|
||||
}
|
||||
|
||||
#elif defined(USE_OPENSSL)
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize)
|
||||
{
|
||||
unsigned outputSize = 0;
|
||||
HMAC(EVP_sha1(), key, keySize, (const unsigned char*)inputData, inputSize, (unsigned char*)outputData, &outputSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
13
src/libs/ice/ICESHA1.h
Normal file
13
src/libs/ice/ICESHA1.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_SHA1_H
|
||||
#define __ICE_SHA1_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize);
|
||||
|
||||
#endif
|
||||
893
src/libs/ice/ICESession.cpp
Normal file
893
src/libs/ice/ICESession.cpp
Normal file
@@ -0,0 +1,893 @@
|
||||
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICESession.h"
|
||||
#include "ICENetworkHelper.h"
|
||||
#include "ICEAction.h"
|
||||
#include "ICESmartPtr.h"
|
||||
#include "ICEBinding.h"
|
||||
#include "ICERelaying.h"
|
||||
#include "ICEAddress.h"
|
||||
#include "ICEStream.h"
|
||||
#include "ICELog.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#ifdef TARGET_WIN
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace ice;
|
||||
|
||||
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
|
||||
Session::Session()
|
||||
{
|
||||
//No activity yet
|
||||
mState = None;
|
||||
|
||||
//start interval for STUN messages
|
||||
mStartInterval = 20;
|
||||
|
||||
mLocalPortNumber = 0;
|
||||
refreshPwdUfrag();
|
||||
|
||||
//default role is Controlled
|
||||
mRole = RoleControlled;
|
||||
|
||||
mTieBreaker = " ";
|
||||
for (size_t i=0; i<8; i++)
|
||||
mTieBreaker[i] = rand() & 0xFF;
|
||||
|
||||
mFoundationGenerator = 0xFFFFFFFF;
|
||||
mMustRestart = false;
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
}
|
||||
|
||||
void Session::setup(StackConfig& config)
|
||||
{
|
||||
if (!config.mUseSTUN && !config.mUseTURN)
|
||||
throw std::logic_error("ICE is configured to not use STUN and not use TURN.");
|
||||
if (config.mUseSTUN && config.mUseTURN)
|
||||
throw std::logic_error("ICE is configured to use both STUN and TURN.");
|
||||
|
||||
// Save the configuration
|
||||
mConfig = config;
|
||||
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->setConfig(config);
|
||||
}
|
||||
|
||||
int Session::addStream()
|
||||
{
|
||||
Lock lock(mGuard);
|
||||
|
||||
ICEStreamPtr s(new Stream());
|
||||
s->setAgentRole(mRole);
|
||||
s->setConfig(mConfig);
|
||||
s->mTieBreaker = mTieBreaker;
|
||||
s->setLocalPwd(mLocalPwd);
|
||||
s->setLocalUfrag(mLocalUfrag);
|
||||
s->mId = mStreamMap.size();
|
||||
mStreamMap[s->mId] = s;
|
||||
|
||||
ICELogInfo(<< "New stream " << s->mId << " is add.");
|
||||
|
||||
return s->mId;
|
||||
}
|
||||
|
||||
int Session::addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6)
|
||||
{
|
||||
Lock lock(mGuard);
|
||||
|
||||
if (mStreamMap.find(streamID) == mStreamMap.end())
|
||||
{
|
||||
ICELogCritical(<< "Cannot find stream " << streamID << " to add new component.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get reference to stream
|
||||
Stream& stream = *mStreamMap[streamID];
|
||||
|
||||
// Assign new ID to component
|
||||
int componentID = stream.addComponent(tag, port4, port6);
|
||||
|
||||
ICELogInfo( << "New component " << componentID << " is add to stream " << streamID << ".");
|
||||
|
||||
return componentID;
|
||||
}
|
||||
|
||||
void Session::removeStream(int streamID)
|
||||
{
|
||||
Lock lock(mGuard);
|
||||
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
mStreamMap.erase(streamIter);
|
||||
}
|
||||
|
||||
bool Session::findStreamAndComponent(int family, unsigned short port, int* stream, int* component)
|
||||
{
|
||||
Lock lock(mGuard);
|
||||
|
||||
// Iterate streams
|
||||
ICEStreamMap::iterator sit;
|
||||
for (sit = mStreamMap.begin(); sit != mStreamMap.end(); ++sit)
|
||||
{
|
||||
if (sit->second->hasPortNumber(family, port, component))
|
||||
{
|
||||
*stream = sit->first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::hasStream(int streamId)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
return mStreamMap.find(streamId) != mStreamMap.end();
|
||||
}
|
||||
|
||||
bool Session::hasComponent(int streamId, int componentId)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId);
|
||||
if (streamIter == mStreamMap.end())
|
||||
return false;
|
||||
if (!streamIter->second)
|
||||
return false;
|
||||
|
||||
return streamIter->second->mComponentMap.find(componentId) != streamIter->second->mComponentMap.end();
|
||||
}
|
||||
|
||||
void Session::setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
if (hasComponent(streamId, componentId))
|
||||
{
|
||||
mStreamMap[streamId]->mComponentMap[componentId].mPort4 = port4;
|
||||
mStreamMap[streamId]->mComponentMap[componentId].mPort6 = port6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Session::gatherCandidates()
|
||||
{
|
||||
//protect instance
|
||||
Lock lock(mGuard);
|
||||
|
||||
//parse the STUN/TURN server IP address
|
||||
//mConfig.mSTUNServerAddr.GetSockaddr((sockaddr&)mSTUNServerAddr);
|
||||
//mConfig.mTURNServerAddr.GetSockaddr((sockaddr&)mTURNServerAddr);
|
||||
|
||||
//as RFC says...
|
||||
//if (mConfig.mUseTURN)
|
||||
// mSTUNServerAddr = mTURNServerAddr;
|
||||
|
||||
// Define the list of used IP interfaces
|
||||
std::vector<NetworkAddress> hostip;
|
||||
|
||||
// Get list of IP interfaces
|
||||
// std::vector<NetworkAddress>& ipList = NetworkHelper::Instance().GetInterfaceList();
|
||||
|
||||
// Iterate all streams and instructs them to gather candidates
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter;
|
||||
int finished = 0;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
{
|
||||
streamIter->second->gatherCandidates();
|
||||
if (streamIter->second->mState > CandidateGathering)
|
||||
finished++;
|
||||
}
|
||||
|
||||
// Set session state as "candidate gathering" or "creating sdp" - depending on stream state
|
||||
if ((size_t)finished == mStreamMap.size())
|
||||
mState = CreatingSDP;
|
||||
else
|
||||
mState = CandidateGathering;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Session::processData(ByteBuffer& buffer, int streamID, int component)
|
||||
{
|
||||
Lock lock(mGuard);
|
||||
|
||||
// Attempt to parse
|
||||
StunMessage msg;
|
||||
if (!msg.parsePacket(buffer))
|
||||
return false;
|
||||
|
||||
ICELogDebug( << "Received STUN packet from " << buffer.remoteAddress().toStdString().c_str() << ". Data: " << buffer.hexstring());
|
||||
|
||||
// Old&new states
|
||||
int oldstate = None, newstate = None;
|
||||
|
||||
// Find stream responsible for this buffer
|
||||
if (mStreamMap.find(streamID) == mStreamMap.end())
|
||||
return false;
|
||||
|
||||
// Get pointer to stream
|
||||
ICEStreamPtr streamPtr = mStreamMap[streamID];
|
||||
if (!streamPtr)
|
||||
return false;
|
||||
|
||||
Stream& stream = *streamPtr;
|
||||
oldstate = stream.mState;
|
||||
/*bool result = */stream.processData(msg, buffer, component);
|
||||
newstate = stream.mState;
|
||||
|
||||
if (newstate != oldstate)
|
||||
{
|
||||
// State is changed. Maybe full session state is changed too?
|
||||
int failedcount = 0, successcount = 0;
|
||||
|
||||
switch (newstate)
|
||||
{
|
||||
case CreatingSDP:
|
||||
|
||||
// Check if all streams gathered candidates or failed
|
||||
for (ICEStreamMap::iterator si=mStreamMap.begin(); si != mStreamMap.end(); ++si)
|
||||
{
|
||||
if (!si->second)
|
||||
continue;
|
||||
|
||||
Stream& stream = *si->second;
|
||||
if (stream.mState == CreatingSDP)
|
||||
successcount++;
|
||||
else
|
||||
if (stream.mState == Failed)
|
||||
failedcount++;
|
||||
}
|
||||
|
||||
if (failedcount == (int)mStreamMap.size())
|
||||
mState = Failed;
|
||||
else
|
||||
mState = CreatingSDP;
|
||||
|
||||
break;
|
||||
|
||||
case Success:
|
||||
case Failed:
|
||||
// Check if all streams a success or failed
|
||||
for (ICEStreamMap::iterator si=mStreamMap.begin(); si != mStreamMap.end(); ++si)
|
||||
{
|
||||
if (!si->second)
|
||||
continue;
|
||||
|
||||
Stream& stream = *si->second;
|
||||
if (stream.mState == Success)
|
||||
successcount++;
|
||||
else
|
||||
if (stream.mState == Failed)
|
||||
failedcount++;
|
||||
}
|
||||
|
||||
if (failedcount == (int)mStreamMap.size())
|
||||
mState = Failed;
|
||||
else
|
||||
mState = Success;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PByteBuffer Session::getDataToSend(bool& response, int& stream, int& component, void*&tag)
|
||||
{
|
||||
// Protect instance
|
||||
Lock lock(mGuard);
|
||||
|
||||
PByteBuffer result;
|
||||
|
||||
// Iterate streams to update their states (maybe timeout occured since last call of getDataToSend())
|
||||
ICEStreamMap::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
if (streamIter->second)
|
||||
streamIter->second->isTimeout();
|
||||
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
{
|
||||
if (streamIter->second)
|
||||
result = streamIter->second->getDataToSend(response, component, tag);
|
||||
if (result)
|
||||
{
|
||||
stream = streamIter->first;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Session::active()
|
||||
{
|
||||
//protect instance
|
||||
Lock lock(mGuard);
|
||||
|
||||
return (mState != None);
|
||||
}
|
||||
|
||||
void Session::createSdp(std::vector<std::string>& common)
|
||||
{
|
||||
common.push_back("a=ice-full");
|
||||
common.push_back("a=ice-pwd:" + localPwd());
|
||||
common.push_back("a=ice-ufrag:" + localUfrag());
|
||||
}
|
||||
|
||||
void Session::createSdp(int streamID, std::vector<std::string>& defaultIP,
|
||||
std::vector<unsigned short>& defaultPort, std::vector<std::string>& candidateList)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
streamIter->second->createOfferSdp(defaultIP, defaultPort, candidateList);
|
||||
}
|
||||
|
||||
|
||||
bool Session::findCandidate(std::vector<Candidate>&cv, Candidate::Type _type,
|
||||
const std::string& baseIP, int componentID, Candidate& result)
|
||||
{
|
||||
for (unsigned int i=0; i<cv.size(); i++)
|
||||
{
|
||||
Candidate& c = cv[i];
|
||||
if (c.mType == _type && c.mComponentId == componentID && c.mLocalAddr.ip()/*mBase*/ == baseIP)
|
||||
{
|
||||
result = c;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RunningState Session::state()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
std::string Session::createUfrag()
|
||||
{
|
||||
std::string result;
|
||||
result.resize(4);
|
||||
|
||||
for (size_t i=0; i<4; i++)
|
||||
{
|
||||
int r = rand();
|
||||
char c = 'a' + int((float)r / ((float)RAND_MAX / 26.0));
|
||||
|
||||
result[i] = c;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Session::createPassword()
|
||||
{
|
||||
std::string result;
|
||||
result.resize(22);
|
||||
|
||||
for (size_t i=0; i<22; i++)
|
||||
{
|
||||
int r = rand();
|
||||
char c = 'a' + int((float)r / ((float)RAND_MAX / 26.0));
|
||||
|
||||
result[i] = c;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Session::localUfrag()
|
||||
{
|
||||
return mLocalUfrag;
|
||||
}
|
||||
|
||||
std::string Session::localPwd()
|
||||
{
|
||||
return mLocalPwd;
|
||||
}
|
||||
|
||||
void Session::setRemotePassword(const std::string& pwd, int streamId)
|
||||
{
|
||||
mMustRestart |= pwd != mRemotePwd;
|
||||
mRemotePwd = pwd;
|
||||
for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++)
|
||||
{
|
||||
ICEStreamPtr s = streamIter->second;
|
||||
if (s)
|
||||
{
|
||||
if (streamId == -1 || streamIter->first == streamId)
|
||||
s->setRemotePwd(pwd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string Session::remotePassword(int streamId) const
|
||||
{
|
||||
if (streamId == -1)
|
||||
return mRemotePwd;
|
||||
ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId);
|
||||
if (streamIter == mStreamMap.end())
|
||||
return std::string();
|
||||
if (!streamIter->second)
|
||||
return std::string();
|
||||
|
||||
return streamIter->second->mRemotePwd;
|
||||
}
|
||||
|
||||
void Session::setRemoteUfrag(const std::string& ufrag, int streamId)
|
||||
{
|
||||
mMustRestart |= ufrag != mRemoteUfrag;
|
||||
mRemoteUfrag = ufrag;
|
||||
|
||||
// Set it to streams
|
||||
for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++)
|
||||
{
|
||||
ICEStreamPtr s = streamIter->second;
|
||||
if (s)
|
||||
{
|
||||
if (streamId == -1 || streamIter->first == streamId)
|
||||
s->setRemoteUfrag(ufrag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Session::remoteUfrag(int streamId) const
|
||||
{
|
||||
if (streamId == -1)
|
||||
return mRemoteUfrag;
|
||||
ICEStreamMap::const_iterator streamIter = mStreamMap.find(streamId);
|
||||
if (streamIter == mStreamMap.end())
|
||||
return std::string();
|
||||
if (!streamIter->second)
|
||||
return std::string();
|
||||
|
||||
return streamIter->second->mRemoteUfrag;
|
||||
}
|
||||
|
||||
bool Session::processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
|
||||
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamIndex);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->processSdpOffer(candidateList, defaultIP, defaultPort, deleteRelayed);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkAddress Session::getRemoteRelayedCandidate(int stream, int component)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(stream);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->remoteRelayedAddress(component);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
NetworkAddress Session::getRemoteReflexiveCandidate(int stream, int component)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(stream);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->remoteReflexiveAddress(component);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
NetworkAddress Session::defaultAddress(int streamID, int componentID)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->defaultAddress(componentID);
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
void Session::fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
streamIter->second->candidateList(componentID, candidateList);
|
||||
}
|
||||
|
||||
void Session::checkConnectivity()
|
||||
{
|
||||
ICELogInfo( << "Starting connectivity checks.");
|
||||
|
||||
// Check current session state to ensure is did not run connectivity checks already
|
||||
if (mState == ConnCheck || mState == Success)
|
||||
return;
|
||||
|
||||
// Make current state "connection checking now"
|
||||
mState = ConnCheck;
|
||||
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); streamIter++)
|
||||
{
|
||||
streamIter->second->setRemotePwd(mRemotePwd);
|
||||
streamIter->second->setRemoteUfrag(mRemoteUfrag);
|
||||
streamIter->second->startChecks();
|
||||
}
|
||||
|
||||
// Set session state to "connection checks"
|
||||
mState = ConnCheck;
|
||||
|
||||
/*
|
||||
Checks are generated only by full implementations. Lite
|
||||
implementations MUST skip the steps described in this section.
|
||||
|
||||
An agent performs ordinary checks and triggered checks. The
|
||||
generation of both checks is governed by a timer which fires
|
||||
periodically for each media stream. The agent maintains a FIFO
|
||||
queue, called the triggered check queue, which contains candidate
|
||||
pairs for which checks are to be sent at the next available
|
||||
|
||||
opportunity. When the timer fires, the agent removes the top pair
|
||||
from triggered check queue, performs a connectivity check on that
|
||||
pair, and sets the state of the candidate pair to In-Progress. If
|
||||
there are no pairs in the triggered check queue, an ordinary check is
|
||||
sent.
|
||||
|
||||
Once the agent has computed the check lists as described in
|
||||
Section 5.7, it sets a timer for each active check list. The timer
|
||||
fires every Ta*N seconds, where N is the number of active check lists
|
||||
(initially, there is only one active check list). Implementations
|
||||
MAY set the timer to fire less frequently than this. Implementations
|
||||
SHOULD take care to spread out these timers so that they do not fire
|
||||
at the same time for each media stream. Ta and the retransmit timer
|
||||
RTO are computed as described in Section 16. Multiplying by N allows
|
||||
this aggregate check throughput to be split between all active check
|
||||
lists. The first timer fires immediately, so that the agent performs
|
||||
a connectivity check the moment the offer/answer exchange has been
|
||||
done, followed by the next check Ta seconds later (since there is
|
||||
only one active check list).
|
||||
|
||||
When the timer fires, and there is no triggered check to be sent, the
|
||||
agent MUST choose an ordinary check as follows:
|
||||
|
||||
o Find the highest priority pair in that check list that is in the
|
||||
Waiting state.
|
||||
|
||||
o If there is such a pair:
|
||||
|
||||
* Send a STUN check from the local candidate of that pair to the
|
||||
remote candidate of that pair. The procedures for forming the
|
||||
STUN request for this purpose are described in Section 7.1.1.
|
||||
|
||||
* Set the state of the candidate pair to In-Progress.
|
||||
|
||||
o If there is no such pair:
|
||||
|
||||
* Find the highest priority pair in that check list that is in
|
||||
the Frozen state.
|
||||
|
||||
* If there is such a pair:
|
||||
|
||||
+ Unfreeze the pair.
|
||||
|
||||
+ Perform a check for that pair, causing its state to
|
||||
transition to In-Progress.
|
||||
|
||||
* If there is no such pair:
|
||||
|
||||
+ Terminate the timer for that check list.
|
||||
|
||||
To compute the message integrity for the check, the agent uses the
|
||||
remote username fragment and password learned from the SDP from its
|
||||
peer. The local username fragment is known directly by the agent for
|
||||
its own candidate.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void Session::setRole(AgentRole role)
|
||||
{
|
||||
mRole = role;
|
||||
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->setAgentRole(role);
|
||||
}
|
||||
|
||||
AgentRole Session::role()
|
||||
{
|
||||
return mRole;
|
||||
}
|
||||
|
||||
|
||||
void Session::clear()
|
||||
{
|
||||
refreshPwdUfrag();
|
||||
mState = None;
|
||||
std::map<int, ICEStreamPtr>::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->clear();
|
||||
mTurnPrefixMap.clear();
|
||||
}
|
||||
|
||||
void Session::clearForRestart(bool localNetworkChanged)
|
||||
{
|
||||
refreshPwdUfrag();
|
||||
mState = ice::None;
|
||||
ICEStreamMap::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->clearForRestart(localNetworkChanged);
|
||||
}
|
||||
|
||||
void Session::stopChecks()
|
||||
{
|
||||
ICELogInfo(<< "Stop connectivity checks");
|
||||
|
||||
ICEStreamMap::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->stopChecks();
|
||||
|
||||
if (mState < Failed)
|
||||
mState = Failed;
|
||||
}
|
||||
|
||||
void Session::cancelAllocations()
|
||||
{
|
||||
for (auto stream: mStreamMap)
|
||||
stream.second->cancelAllocations();
|
||||
}
|
||||
|
||||
bool Session::finished()
|
||||
{
|
||||
return (mState == Failed || mState == Success);
|
||||
}
|
||||
|
||||
NetworkAddress Session::remoteAddress(int streamID, int componentID)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->remoteAddress(componentID);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
NetworkAddress Session::localAddress(int streamID, int componentID)
|
||||
{
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->localAddress(componentID);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
NetworkAddress Session::reflexiveAddress(int streamID, int componentID)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->reflexiveAddress(componentID);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
NetworkAddress Session::relayedAddress(int streamID, int componentID)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(streamID);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->relayedAddress(componentID);
|
||||
|
||||
return NetworkAddress();
|
||||
}
|
||||
|
||||
bool Session::hasTurnPrefix(TurnPrefix prefix)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
TurnPrefixMap::iterator mit = mTurnPrefixMap.find(prefix);
|
||||
return mit != mTurnPrefixMap.end();
|
||||
}
|
||||
|
||||
void Session::chooseDefaults()
|
||||
{
|
||||
Lock l(mGuard);
|
||||
|
||||
ICEStreamMap::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->Handle_CD();
|
||||
}
|
||||
|
||||
void Session::dump(std::ostream& output)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
|
||||
ICEStreamMap::iterator streamIter;
|
||||
for (streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
streamIter->second->dump(output);
|
||||
}
|
||||
|
||||
bool Session::findConcludePair(int stream, Candidate& local, Candidate& remote)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(stream);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->findConcludePair(local, remote);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::mustRestart() const
|
||||
{
|
||||
return mMustRestart;
|
||||
}
|
||||
|
||||
void Session::refreshPwdUfrag()
|
||||
{
|
||||
mLocalPwd = Session::createPassword();
|
||||
mLocalUfrag = Session::createUfrag();
|
||||
|
||||
// Update all streams
|
||||
for (ICEStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
|
||||
{
|
||||
if (streamIter->second)
|
||||
{
|
||||
streamIter->second->setLocalPwd(mLocalPwd);
|
||||
streamIter->second->setLocalUfrag(mLocalUfrag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Session::freeAllocation(int stream, int component, DeleteAllocationCallback* cb)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(stream);
|
||||
if (streamIter != mStreamMap.end())
|
||||
streamIter->second->freeAllocation(component, cb);
|
||||
}
|
||||
|
||||
bool Session::hasAllocations()
|
||||
{
|
||||
int allocated = 0;
|
||||
Lock l(mGuard);
|
||||
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.begin();
|
||||
for (;streamIter != mStreamMap.end(); ++streamIter)
|
||||
if (streamIter->second)
|
||||
allocated += streamIter->second->mTurnAllocated;
|
||||
|
||||
return allocated > 0;
|
||||
}
|
||||
|
||||
bool Session::isDataIndication(ByteBuffer& source, ByteBuffer* plain)
|
||||
{
|
||||
StunMessage msg;
|
||||
if (!msg.parsePacket(source))
|
||||
return false;
|
||||
|
||||
if (msg.hasAttribute(StunAttribute::Data) && msg.hasAttribute(StunAttribute::XorPeerAddress))
|
||||
{
|
||||
// It is Data indication packet
|
||||
DataAttribute& d = dynamic_cast<DataAttribute&>(msg.attribute(StunAttribute::Data));
|
||||
XorPeerAddress& xpa = dynamic_cast<XorPeerAddress&>(msg.attribute(StunAttribute::XorPeerAddress));
|
||||
|
||||
if (plain)
|
||||
{
|
||||
*plain = d.data();
|
||||
NetworkAddress remoteAddress = xpa.address();
|
||||
remoteAddress.setRelayed(true);
|
||||
plain->setRemoteAddress(remoteAddress);
|
||||
plain->setRelayed(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::isStun(ByteBuffer& source)
|
||||
{
|
||||
if (source.size() < 8)
|
||||
return false;
|
||||
|
||||
const unsigned* magic = (const unsigned*)source.data();
|
||||
return (ntohl(magic[1]) == 0x2112A442);
|
||||
}
|
||||
|
||||
|
||||
int Session::errorCode()
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICEStreamMap::const_iterator streamIter = mStreamMap.begin();
|
||||
for (;streamIter != mStreamMap.end(); ++streamIter)
|
||||
if (streamIter->second->mState == /*RunningState::*/Failed)
|
||||
return streamIter->second->mErrorCode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TurnPrefix Session::bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICELogInfo(<< "Bind channel " << stream << "/" << component << " to " << target.toStdString());
|
||||
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.find(stream);
|
||||
if (streamIter != mStreamMap.end())
|
||||
return streamIter->second->bindChannel(target, component, cb);
|
||||
|
||||
return 0; // Channel numbers are in range [0x4000...0x7FFF]
|
||||
}
|
||||
|
||||
bool Session::isChannelBindingFailed(int stream, int component, TurnPrefix prefix)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.begin();
|
||||
if (streamIter != mStreamMap.end())
|
||||
if (streamIter->second)
|
||||
return streamIter->second->isChannelBindingFailed(component, prefix);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Session::installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb)
|
||||
{
|
||||
Lock l(mGuard);
|
||||
ICELogInfo(<< "Install permissions " << stream << "/" << component << " for " << address.toStdString());
|
||||
|
||||
ICEStreamMap::iterator streamIter = mStreamMap.begin();
|
||||
if (streamIter != mStreamMap.end())
|
||||
streamIter->second->installPermissions(component, address, cb);
|
||||
}
|
||||
|
||||
bool Session::isRtp(ByteBuffer& source)
|
||||
{
|
||||
if (!source.size())
|
||||
return false;
|
||||
unsigned char b = *(const unsigned char*)source.data();
|
||||
return (b & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
bool Session::isChannelData(ByteBuffer& source, TurnPrefix prefix)
|
||||
{
|
||||
if (source.size() < 4)
|
||||
return false;
|
||||
|
||||
if (!prefix)
|
||||
{
|
||||
unsigned char b = *(const unsigned char*)source.data();
|
||||
return (b & 0xC0) == 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short pp = ntohs(*(const unsigned short*)source.data());
|
||||
return pp == prefix;
|
||||
}
|
||||
}
|
||||
|
||||
Stream::CandidateVector* Session::remoteCandidates(int stream)
|
||||
{
|
||||
ICEStreamMap::iterator iter = mStreamMap.find(stream);
|
||||
if (iter != mStreamMap.end())
|
||||
return &iter->second->mRemoteCandidate;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetworkAddress Session::activeStunServer(int stream) const
|
||||
{
|
||||
ICEStreamMap::const_iterator iter = mStreamMap.find(stream);
|
||||
if (iter != mStreamMap.end())
|
||||
return iter->second->mConfig.mServerAddr4;
|
||||
else
|
||||
return NetworkAddress();
|
||||
}
|
||||
221
src/libs/ice/ICESession.h
Normal file
221
src/libs/ice/ICESession.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_SESSION_H
|
||||
#define __ICE_SESSION_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "ICEStunConfig.h"
|
||||
#include "ICECandidate.h"
|
||||
#include "ICEStunMessage.h"
|
||||
#include "ICEBinding.h"
|
||||
#include "ICERelaying.h"
|
||||
#include "ICESync.h"
|
||||
#include "ICECheckList.h"
|
||||
#include "ICETime.h"
|
||||
#include "ICESmartPtr.h"
|
||||
#include "ICEStream.h"
|
||||
|
||||
namespace ice {
|
||||
|
||||
// ICE session context
|
||||
struct Session
|
||||
{
|
||||
public:
|
||||
Mutex mGuard; // Mutex to protect this instance
|
||||
typedef std::map<int, ICEStreamPtr> ICEStreamMap;
|
||||
ICEStreamMap mStreamMap; // Streams
|
||||
RunningState mState; // State of session
|
||||
StackConfig mConfig; // Configuration
|
||||
|
||||
size_t mStartInterval; /// Start interval
|
||||
unsigned short mLocalPortNumber; /// Local port number
|
||||
std::string mLocalPwd,
|
||||
mLocalUfrag,
|
||||
mRemotePwd,
|
||||
mRemoteUfrag;
|
||||
|
||||
NetworkAddress mRemoteDefaultAddr; /// Remote default address
|
||||
AgentRole mRole; /// Marks if agent is Controlled or Controlling
|
||||
std::string mTieBreaker; /// Tie breaker
|
||||
unsigned int mFoundationGenerator; /// Foundation value generator. Used when foundation of remote candidate is not available.
|
||||
bool mCanTransmit; /// Marks if transmission can start
|
||||
bool mMustReInvite; /// Must reINVITE
|
||||
TurnPrefixMap mTurnPrefixMap; /// Map of established relays
|
||||
bool mMustRestart; /// Marks if session has to restart
|
||||
|
||||
/*! Default constructor. */
|
||||
Session();
|
||||
|
||||
/*! Destructor. */
|
||||
~Session();
|
||||
|
||||
/*! Adjusts session to work with specified component number and specified local port number. */
|
||||
void setup(StackConfig& config);
|
||||
|
||||
/*! Checks if ICE session is started. */
|
||||
bool active();
|
||||
|
||||
/*! Initiates candidate gathering. Setup() must be called before. */
|
||||
void gatherCandidates();
|
||||
|
||||
/*! Processing incoming data.
|
||||
* @return True if data were processed, false otherwise (too old response or not STUN data at all). */
|
||||
bool processData(ByteBuffer& buffer, int stream, int component);
|
||||
|
||||
/*! Checks if there is any data to send.
|
||||
* @return True if more data to send are available, false if all available data are returned in current call. */
|
||||
PByteBuffer getDataToSend(bool& response, int& stream, int& component, void*&tag);
|
||||
|
||||
|
||||
/*! Handles incoming data in gathering candidate stage.
|
||||
* @return True if data was handled, false otherwise (too old response or not STUN data at all. */
|
||||
bool Handle_CG_In(StunMessage& msg, NetworkAddress& address);
|
||||
|
||||
/*! Handle eliminate redudand stage. */
|
||||
void Handle_ER();
|
||||
|
||||
// Compute foundations
|
||||
void Handle_CF();
|
||||
|
||||
// Starting keep alive timers
|
||||
void Handle_SKA();
|
||||
|
||||
// Prioritize candidates
|
||||
void Handle_PC();
|
||||
|
||||
// Choosing default candidate
|
||||
void chooseDefaults();
|
||||
|
||||
// Creation of common SDP strings
|
||||
void createSdp(std::vector<std::string>& common);
|
||||
|
||||
// Creation of component SDP strings
|
||||
void createSdp(int streamID, std::vector<std::string>& defaultIP,
|
||||
std::vector<unsigned short>& defaultPort, std::vector<std::string>& candidateList);
|
||||
|
||||
bool findCandidate(std::vector<Candidate>&cv, Candidate::Type _type,
|
||||
const std::string& baseIP, int componentID, Candidate& result);
|
||||
|
||||
RunningState state();
|
||||
|
||||
std::string localUfrag();
|
||||
std::string localPwd();
|
||||
|
||||
/*! Process ICE offer text. It does not mean SIP offer. No, this method applies to initial ICE candidate list and other information in both SIP offer and answer packets. */
|
||||
bool processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
|
||||
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed);
|
||||
NetworkAddress getRemoteRelayedCandidate(int stream, int component);
|
||||
NetworkAddress getRemoteReflexiveCandidate(int stream, int component);
|
||||
|
||||
NetworkAddress defaultAddress(int streamID, int componentID);
|
||||
void fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList);
|
||||
|
||||
/*! Seeks in candidate list for candidate with specified IP and port. */
|
||||
bool candidateListContains(std::string remoteIP, unsigned short remotePort);
|
||||
|
||||
/*! Marks agent as Controlled or Controlling role. */
|
||||
void setRole(AgentRole role);
|
||||
|
||||
/*! Gets current role. */
|
||||
AgentRole role();
|
||||
|
||||
/*! Binds channel to prefix */
|
||||
TurnPrefix bindChannel(int stream, int component, const NetworkAddress& target, ChannelBoundCallback* cb);
|
||||
bool isChannelBindingFailed(int stream, int component, TurnPrefix prefix);
|
||||
|
||||
void installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb);
|
||||
|
||||
/*! Enqueues CreatePermisssion transaction with zero lifetime - it removes permission. */
|
||||
void deletePermission(int stream, int component, DeletePermissionsCallback* cb);
|
||||
|
||||
// Enqueues ClientAllocate with zero lifetime
|
||||
void freeAllocation(int stream, int component, DeleteAllocationCallback* cb);
|
||||
|
||||
// Returns if there were any TURN allocations from this stack
|
||||
bool hasAllocations();
|
||||
|
||||
static bool isDataIndication(ByteBuffer& source, ByteBuffer* plain);
|
||||
static bool isStun(ByteBuffer& source);
|
||||
static bool isRtp(ByteBuffer& source);
|
||||
static bool isChannelData(ByteBuffer& source, TurnPrefix prefix);
|
||||
|
||||
/*! Starts connectivity checks. */
|
||||
void checkConnectivity();
|
||||
|
||||
// Clears state of session and streams; does not delete streams or components. Stops all connectivity checks. Candidates must be gathered again.
|
||||
void clear();
|
||||
|
||||
void clearForRestart(bool localNetworkChanged);
|
||||
|
||||
// Returns true if state of session is Success or Failed
|
||||
bool finished();
|
||||
|
||||
// Stop connectivity checks and gathering requests.
|
||||
void stopChecks();
|
||||
|
||||
// Cancel allocation requests. Called when timeout is detected and allocation should be cancelled.
|
||||
// Allocation transaction and session can have different timeout values - so this method is neccessary
|
||||
void cancelAllocations();
|
||||
|
||||
/*! Returns concluding addresses . */
|
||||
NetworkAddress remoteAddress(int streamID, int componentID);
|
||||
NetworkAddress localAddress(int streamID, int componentID);
|
||||
|
||||
/*! Searches for local server reflexive candidate with specified component ID and returns its external address. */
|
||||
NetworkAddress reflexiveAddress(int streamID, int componentID);
|
||||
|
||||
/*! Searches for local server relayed candidate with specified component ID and returns its external address. */
|
||||
NetworkAddress relayedAddress(int streamID, int componentID);
|
||||
|
||||
/*! Checks if argument is used TURN prefix in one of the TURN bound channels. */
|
||||
bool hasTurnPrefix(TurnPrefix prefix);
|
||||
|
||||
/*! Adds stream to session. Returns stream index. */
|
||||
int addStream();
|
||||
|
||||
/*! Adds component to stream.
|
||||
* @param streamIndex Stream index.
|
||||
* @param tag Tag associated with component.
|
||||
* @return Created component record index. */
|
||||
int addComponent(int streamID, void *tag, unsigned short port4, unsigned short port6);
|
||||
|
||||
/* Removes stream with specified ID. All stream's components are removed too. */
|
||||
void removeStream(int streamID);
|
||||
|
||||
/* Searches the stream&component ID basing on socket family (AF_INET or AF_INET6) and local port number. */
|
||||
bool findStreamAndComponent(int family, unsigned short port, int* stream, int* component);
|
||||
|
||||
bool hasStream(int streamId);
|
||||
bool hasComponent(int streamId, int componentId);
|
||||
void setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6);
|
||||
|
||||
/*! Generates new ICE ufrag string. */
|
||||
static std::string createUfrag();
|
||||
|
||||
/*! Generates new ICE pwd string. */
|
||||
static std::string createPassword();
|
||||
|
||||
void setRemotePassword(const std::string& pwd, int streamId = -1);
|
||||
std::string remotePassword(int streamId = -1) const;
|
||||
void setRemoteUfrag(const std::string& ufrag, int streamId = -1);
|
||||
std::string remoteUfrag(int streamId = -1) const;
|
||||
|
||||
void refreshPwdUfrag();
|
||||
|
||||
void dump(std::ostream& output);
|
||||
bool mustRestart() const;
|
||||
bool findConcludePair(int stream, Candidate& local, Candidate& remote);
|
||||
int errorCode();
|
||||
Stream::CandidateVector* remoteCandidates(int stream);
|
||||
|
||||
NetworkAddress activeStunServer(int stream) const;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
396
src/libs/ice/ICESmartCount.h
Normal file
396
src/libs/ice/ICESmartCount.h
Normal file
@@ -0,0 +1,396 @@
|
||||
// Based on resiprocate's implementation of smart pointer, which is based on boost implementation
|
||||
// Its license is smth close to BSD
|
||||
|
||||
#ifndef __ICE_SMART_COUNT_H
|
||||
#define __ICE_SMART_COUNT_H
|
||||
|
||||
// Note: This implementation is a modified version of shared_count from
|
||||
// Boost.org
|
||||
//
|
||||
|
||||
#include <memory> // std::auto_ptr, std::allocator
|
||||
#include <functional> // std::less
|
||||
#include <exception> // std::exception
|
||||
#include <new> // std::bad_alloc
|
||||
#include <typeinfo> // std::type_info in get_deleter
|
||||
#include <cstddef> // std::size_t
|
||||
#include "ICESync.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn -8026 // Functions with excep. spec. are not expanded inline
|
||||
# pragma warn -8027 // Functions containing try are not expanded inline
|
||||
#endif
|
||||
|
||||
// verify that types are complete for increased safety
|
||||
template<class T> inline void checked_delete(T * x)
|
||||
{
|
||||
// intentionally complex - simplification causes regressions
|
||||
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
|
||||
(void) sizeof(type_must_be_complete);
|
||||
delete x;
|
||||
};
|
||||
|
||||
template<class T> struct checked_deleter
|
||||
{
|
||||
typedef void result_type;
|
||||
typedef T * argument_type;
|
||||
|
||||
void operator()(T * x) const
|
||||
{
|
||||
// resip:: disables ADL
|
||||
checked_delete(x);
|
||||
}
|
||||
};
|
||||
|
||||
// The standard library that comes with Borland C++ 5.5.1
|
||||
// defines std::exception and its members as having C calling
|
||||
// convention (-pc). When the definition of bad_weak_ptr
|
||||
// is compiled with -ps, the compiler issues an error.
|
||||
// Hence, the temporary #pragma option -pc below. The version
|
||||
// check is deliberately conservative.
|
||||
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551
|
||||
# pragma option push -pc
|
||||
#endif
|
||||
|
||||
class bad_weak_ptr: public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
virtual char const * what() const throw()
|
||||
{
|
||||
return "resip::bad_weak_ptr";
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__BORLANDC__) && __BORLANDC__ == 0x551
|
||||
# pragma option pop
|
||||
#endif
|
||||
|
||||
class sp_counted_base
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
sp_counted_base(): use_count_(1), weak_count_(1)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~sp_counted_base() // nothrow
|
||||
{
|
||||
}
|
||||
|
||||
// dispose() is called when use_count_ drops to zero, to release
|
||||
// the resources managed by *this.
|
||||
virtual void dispose() = 0; // nothrow
|
||||
|
||||
// destruct() is called when weak_count_ drops to zero.
|
||||
virtual void destruct() // nothrow
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
virtual void * get_deleter(std::type_info const & ti) = 0;
|
||||
|
||||
void add_ref_copy()
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
++use_count_;
|
||||
//GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::add_ref_copy: " << use_count_);
|
||||
}
|
||||
|
||||
void add_ref_lock()
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
// if(use_count_ == 0) throw(resip::bad_weak_ptr());
|
||||
if (use_count_ == 0) throw bad_weak_ptr();
|
||||
++use_count_;
|
||||
//GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::add_ref_lock: " << use_count_);
|
||||
}
|
||||
|
||||
void release() // nothrow
|
||||
{
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
long new_use_count = --use_count_;
|
||||
//GenericLog(Subsystem::SIP, resip::Log::Info, << "********* SharedCount::release: " << use_count_);
|
||||
|
||||
if(new_use_count != 0) return;
|
||||
}
|
||||
|
||||
dispose();
|
||||
weak_release();
|
||||
}
|
||||
|
||||
void weak_add_ref() // nothrow
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
++weak_count_;
|
||||
}
|
||||
|
||||
void weak_release() // nothrow
|
||||
{
|
||||
long new_weak_count;
|
||||
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
new_weak_count = --weak_count_;
|
||||
}
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
destruct();
|
||||
}
|
||||
}
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
Lock lock(mMutex); (void)lock;
|
||||
return use_count_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
sp_counted_base(sp_counted_base const &);
|
||||
sp_counted_base & operator= (sp_counted_base const &);
|
||||
|
||||
long use_count_; // #shared
|
||||
long weak_count_; // #weak + (#shared != 0)
|
||||
|
||||
mutable Mutex mMutex;
|
||||
};
|
||||
|
||||
//
|
||||
// Borland's Codeguard trips up over the -Vx- option here:
|
||||
//
|
||||
#ifdef __CODEGUARD__
|
||||
# pragma option push -Vx-
|
||||
#endif
|
||||
|
||||
template<class P, class D> class sp_counted_base_impl: public sp_counted_base
|
||||
{
|
||||
private:
|
||||
|
||||
P ptr; // copy constructor must not throw
|
||||
D del; // copy constructor must not throw
|
||||
|
||||
sp_counted_base_impl(sp_counted_base_impl const &);
|
||||
sp_counted_base_impl & operator= (sp_counted_base_impl const &);
|
||||
|
||||
typedef sp_counted_base_impl<P, D> this_type;
|
||||
|
||||
public:
|
||||
|
||||
// pre: initial_use_count <= initial_weak_count, d(p) must not throw
|
||||
sp_counted_base_impl(P p, D d): ptr(p), del(d)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void dispose() // nothrow
|
||||
{
|
||||
del(ptr);
|
||||
}
|
||||
|
||||
virtual void * get_deleter(std::type_info const & ti)
|
||||
{
|
||||
return ti == typeid(D)? &del: 0;
|
||||
}
|
||||
|
||||
void * operator new(size_t)
|
||||
{
|
||||
return std::allocator<this_type>().allocate(1, static_cast<this_type *>(0));
|
||||
}
|
||||
|
||||
void operator delete(void * p)
|
||||
{
|
||||
std::allocator<this_type>().deallocate(static_cast<this_type *>(p), 1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class shared_count
|
||||
{
|
||||
private:
|
||||
|
||||
sp_counted_base * pi_;
|
||||
|
||||
public:
|
||||
|
||||
shared_count(): pi_(0) // nothrow
|
||||
{
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P p, D d): pi_(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
pi_ = new sp_counted_base_impl<P, D>(p, d);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
d(p); // delete p
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// auto_ptr<Y> is special cased to provide the strong guarantee
|
||||
template<class Y>
|
||||
explicit shared_count(std::auto_ptr<Y> & r): pi_(new sp_counted_base_impl< Y *, checked_deleter<Y> >(r.get(), checked_deleter<Y>()))
|
||||
{
|
||||
r.release();
|
||||
}
|
||||
|
||||
~shared_count() // nothrow
|
||||
{
|
||||
if(pi_ != 0) pi_->release();
|
||||
}
|
||||
|
||||
shared_count(shared_count const & r): pi_(r.pi_) // nothrow
|
||||
{
|
||||
if(pi_ != 0) pi_->add_ref_copy();
|
||||
}
|
||||
|
||||
shared_count & operator= (shared_count const & r) // nothrow
|
||||
{
|
||||
sp_counted_base * tmp = r.pi_;
|
||||
if(tmp != 0) tmp->add_ref_copy();
|
||||
if(pi_ != 0) pi_->release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(shared_count & r) // nothrow
|
||||
{
|
||||
sp_counted_base * tmp = r.pi_;
|
||||
r.pi_ = pi_;
|
||||
pi_ = tmp;
|
||||
}
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
return pi_ != 0? pi_->use_count(): 0;
|
||||
}
|
||||
|
||||
bool unique() const // nothrow
|
||||
{
|
||||
return use_count() == 1;
|
||||
}
|
||||
|
||||
friend inline bool operator==(shared_count const & a, shared_count const & b)
|
||||
{
|
||||
return a.pi_ == b.pi_;
|
||||
}
|
||||
|
||||
friend inline bool operator<(shared_count const & a, shared_count const & b)
|
||||
{
|
||||
return std::less<sp_counted_base *>()(a.pi_, b.pi_);
|
||||
}
|
||||
|
||||
void * get_deleter(std::type_info const & ti) const
|
||||
{
|
||||
return pi_? pi_->get_deleter(ti): 0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __CODEGUARD__
|
||||
# pragma option pop
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
# pragma warn .8027 // Functions containing try are not expanded inline
|
||||
# pragma warn .8026 // Functions with excep. spec. are not expanded inline
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Note: This implementation is a modified version of shared_count from
|
||||
// Boost.org
|
||||
//
|
||||
|
||||
/* ====================================================================
|
||||
*
|
||||
* Boost Software License - Version 1.0 - August 17th, 2003
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* The Vovida Software License, Version 1.0
|
||||
*
|
||||
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
|
||||
* and "Vovida Open Communication Application Library (VOCAL)" must
|
||||
* not be used to endorse or promote products derived from this
|
||||
* software without prior written permission. For written
|
||||
* permission, please contact vocal@vovida.org.
|
||||
*
|
||||
* 4. Products derived from this software may not be called "VOCAL", nor
|
||||
* may "VOCAL" appear in their name, without prior written
|
||||
* permission of Vovida Networks, Inc.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
|
||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
|
||||
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
|
||||
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by Vovida
|
||||
* Networks, Inc. and many individuals on behalf of Vovida Networks,
|
||||
* Inc. For more information on Vovida Networks, Inc., please see
|
||||
* <http://www.vovida.org/>.
|
||||
*
|
||||
*/
|
||||
382
src/libs/ice/ICESmartPtr.h
Normal file
382
src/libs/ice/ICESmartPtr.h
Normal file
@@ -0,0 +1,382 @@
|
||||
// Based on resiprocate's implementation of smart pointer, which is based on boost implementation
|
||||
// Its license is smth close to BSD
|
||||
|
||||
#ifndef __ICE_SMART_PTR_H
|
||||
#define __ICE_SMART_PTR_H
|
||||
|
||||
#ifndef USE_NATIVE_SMARTPTR
|
||||
|
||||
#include "ICESmartCount.h"
|
||||
#include <memory> // for std::auto_ptr
|
||||
#include <algorithm> // for std::swap
|
||||
#include <functional> // for std::less
|
||||
#include <typeinfo> // for std::bad_cast
|
||||
#include <iosfwd> // for std::basic_ostream
|
||||
#include <cassert>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
|
||||
|
||||
template<class T> class enable_shared_from_this;
|
||||
|
||||
struct static_cast_tag {};
|
||||
struct const_cast_tag {};
|
||||
struct dynamic_cast_tag {};
|
||||
struct polymorphic_cast_tag {};
|
||||
|
||||
template<class T> struct SmartPtr_traits
|
||||
{
|
||||
typedef T & reference;
|
||||
};
|
||||
|
||||
template<> struct SmartPtr_traits<void>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
template<> struct SmartPtr_traits<void const>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
template<> struct SmartPtr_traits<void volatile>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
template<> struct SmartPtr_traits<void const volatile>
|
||||
{
|
||||
typedef void reference;
|
||||
};
|
||||
|
||||
// enable_shared_from_this support
|
||||
|
||||
template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, enable_shared_from_this<T> const * pe, Y const * px )
|
||||
{
|
||||
if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
|
||||
}
|
||||
|
||||
inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... )
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// SmartPtr
|
||||
//
|
||||
// Reference counted copy semantics.
|
||||
// The object pointed to is deleted when the last SmartPtr pointing to it
|
||||
// is destroyed or reset.
|
||||
//
|
||||
|
||||
template<class T> class SmartPtr
|
||||
{
|
||||
private:
|
||||
|
||||
// Borland 5.5.1 specific workaround
|
||||
typedef SmartPtr<T> this_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
typedef T value_type;
|
||||
typedef T * pointer;
|
||||
typedef typename SmartPtr_traits<T>::reference reference;
|
||||
|
||||
SmartPtr(): px(0), pn() // never throws in 1.30+
|
||||
{
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
explicit SmartPtr(Y * p): px(p), pn(p, checked_deleter<Y>()) // Y must be complete
|
||||
{
|
||||
sp_enable_shared_from_this( pn, p, p );
|
||||
}
|
||||
|
||||
//
|
||||
// Requirements: D's copy constructor must not throw
|
||||
//
|
||||
// SmartPtr will release p by calling d(p)
|
||||
//
|
||||
|
||||
template<class Y, class D> SmartPtr(Y * p, D d): px(p), pn(p, d)
|
||||
{
|
||||
sp_enable_shared_from_this( pn, p, p );
|
||||
}
|
||||
|
||||
// generated copy constructor, assignment, destructor are fine...
|
||||
|
||||
// except that Borland C++ has a bug, and g++ with -Wsynth warns
|
||||
#if defined(__BORLANDC__) || defined(__GNUC__)
|
||||
SmartPtr & operator=(SmartPtr const & r) // never throws
|
||||
{
|
||||
px = r.px;
|
||||
pn = r.pn; // shared_count::op= doesn't throw
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class Y>
|
||||
SmartPtr(SmartPtr<Y> const & r): px(r.px), pn(r.pn) // never throws
|
||||
{
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr(SmartPtr<Y> const & r, static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr(SmartPtr<Y> const & r, const_cast_tag): px(const_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr(SmartPtr<Y> const & r, dynamic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
if(px == 0) // need to allocate new counter -- the cast failed
|
||||
{
|
||||
pn = /*resip::*/shared_count();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr(SmartPtr<Y> const & r, polymorphic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
|
||||
{
|
||||
if(px == 0)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
explicit SmartPtr(std::auto_ptr<Y> & r): px(r.get()), pn()
|
||||
{
|
||||
Y * tmp = r.get();
|
||||
pn = shared_count(r);
|
||||
sp_enable_shared_from_this( pn, tmp, tmp );
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr & operator=(SmartPtr<Y> const & r) // never throws
|
||||
{
|
||||
px = r.px;
|
||||
pn = r.pn; // shared_count::op= doesn't throw
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Y>
|
||||
SmartPtr & operator=(std::auto_ptr<Y> & r)
|
||||
{
|
||||
this_type(r).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() // never throws in 1.30+
|
||||
{
|
||||
this_type().swap(*this);
|
||||
}
|
||||
|
||||
template<class Y> void reset(Y * p) // Y must be complete
|
||||
{
|
||||
assert(p == 0 || p != px); // catch self-reset errors
|
||||
this_type(p).swap(*this);
|
||||
}
|
||||
|
||||
template<class Y, class D> void reset(Y * p, D d)
|
||||
{
|
||||
this_type(p, d).swap(*this);
|
||||
}
|
||||
|
||||
reference operator* () const // never throws
|
||||
{
|
||||
assert(px != 0);
|
||||
return *px;
|
||||
}
|
||||
|
||||
T * operator-> () const // never throws
|
||||
{
|
||||
//assert(px != 0);
|
||||
return px;
|
||||
}
|
||||
|
||||
T * get() const // never throws
|
||||
{
|
||||
return px;
|
||||
}
|
||||
|
||||
// implicit conversion to "bool"
|
||||
#if defined(__SUNPRO_CC) // BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530)
|
||||
operator bool () const
|
||||
{
|
||||
return px != 0;
|
||||
}
|
||||
#elif defined(__MWERKS__) // BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
|
||||
typedef T * (this_type::*unspecified_bool_type)() const;
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return px == 0? 0: &this_type::get;
|
||||
}
|
||||
#else
|
||||
typedef T * this_type::*unspecified_bool_type;
|
||||
operator unspecified_bool_type() const // never throws
|
||||
{
|
||||
return px == 0? 0: &this_type::px;
|
||||
}
|
||||
#endif
|
||||
|
||||
// operator! is redundant, but some compilers need it
|
||||
bool operator! () const // never throws
|
||||
{
|
||||
return px == 0;
|
||||
}
|
||||
|
||||
bool unique() const // never throws
|
||||
{
|
||||
return pn.unique();
|
||||
}
|
||||
|
||||
long use_count() const // never throws
|
||||
{
|
||||
return pn.use_count();
|
||||
}
|
||||
|
||||
void swap(SmartPtr<T> & other) // never throws
|
||||
{
|
||||
std::swap(px, other.px);
|
||||
pn.swap(other.pn);
|
||||
}
|
||||
|
||||
template<class Y> bool _internal_less(SmartPtr<Y> const & rhs) const
|
||||
{
|
||||
return pn < rhs.pn;
|
||||
}
|
||||
|
||||
void * _internal_get_deleter(std::type_info const & ti) const
|
||||
{
|
||||
return pn.get_deleter(ti);
|
||||
}
|
||||
|
||||
// Tasteless as this may seem, making all members public allows member templates
|
||||
// to work in the absence of member template friends. (Matthew Langston)
|
||||
|
||||
private:
|
||||
|
||||
template<class Y> friend class SmartPtr;
|
||||
|
||||
T * px; // contained pointer
|
||||
shared_count pn; // reference counter
|
||||
|
||||
}; // SmartPtr
|
||||
|
||||
template<class T, class U> inline bool operator==(SmartPtr<T> const & a, SmartPtr<U> const & b)
|
||||
{
|
||||
return a.get() == b.get();
|
||||
}
|
||||
|
||||
template<class T, class U> inline bool operator!=(SmartPtr<T> const & a, SmartPtr<U> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
|
||||
|
||||
// Resolve the ambiguity between our op!= and the one in rel_ops
|
||||
|
||||
template<class T> inline bool operator!=(SmartPtr<T> const & a, SmartPtr<T> const & b)
|
||||
{
|
||||
return a.get() != b.get();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class T, class U> inline bool operator<(SmartPtr<T> const & a, SmartPtr<U> const & b)
|
||||
{
|
||||
return a._internal_less(b);
|
||||
}
|
||||
|
||||
template<class T> inline void swap(SmartPtr<T> & a, SmartPtr<T> & b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> static_pointer_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, static_cast_tag());
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> const_pointer_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, const_cast_tag());
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> dynamic_pointer_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, dynamic_cast_tag());
|
||||
}
|
||||
|
||||
// shared_*_cast names are deprecated. Use *_pointer_cast instead.
|
||||
|
||||
template<class T, class U> SmartPtr<T> shared_static_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, static_cast_tag());
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> shared_dynamic_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, dynamic_cast_tag());
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> shared_polymorphic_cast(SmartPtr<U> const & r)
|
||||
{
|
||||
return SmartPtr<T>(r, polymorphic_cast_tag());
|
||||
}
|
||||
|
||||
template<class T, class U> SmartPtr<T> shared_polymorphic_downcast(SmartPtr<U> const & r)
|
||||
{
|
||||
assert(dynamic_cast<T *>(r.get()) == r.get());
|
||||
return shared_static_cast<T>(r);
|
||||
}
|
||||
|
||||
template<class T> inline T * get_pointer(SmartPtr<T> const & p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
// operator<<
|
||||
#if defined(__GNUC__) && (__GNUC__ < 3)
|
||||
template<class Y> std::ostream & operator<< (std::ostream & os, SmartPtr<Y> const & p)
|
||||
{
|
||||
os << p.get();
|
||||
return os;
|
||||
}
|
||||
#else
|
||||
template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, SmartPtr<Y> const & p)
|
||||
{
|
||||
os << p.get();
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
// get_deleter (experimental)
|
||||
#if (defined(__GNUC__) && (__GNUC__ < 3)) || (defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238))
|
||||
// g++ 2.9x doesn't allow static_cast<X const *>(void *)
|
||||
// apparently EDG 2.38 also doesn't accept it
|
||||
template<class D, class T> D * get_deleter(SmartPtr<T> const & p)
|
||||
{
|
||||
void const * q = p._internal_get_deleter(typeid(D));
|
||||
return const_cast<D *>(static_cast<D const *>(q));
|
||||
}
|
||||
#else
|
||||
template<class D, class T> D * get_deleter(SmartPtr<T> const & p)
|
||||
{
|
||||
return static_cast<D *>(p._internal_get_deleter(typeid(D)));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
32
src/libs/ice/ICESocket.h
Normal file
32
src/libs/ice/ICESocket.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_SOCKET_H
|
||||
#define __ICE_SOCKET_H
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICETypes.h"
|
||||
#include <string>
|
||||
|
||||
namespace ice {
|
||||
|
||||
struct ICESocket
|
||||
{
|
||||
std::string mHostIP;
|
||||
unsigned short mPort;
|
||||
SOCKET mHandle;
|
||||
unsigned int mPriority;
|
||||
|
||||
ICESocket()
|
||||
:mPort(0), mHandle(INVALID_SOCKET), mPriority(0)
|
||||
{}
|
||||
|
||||
~ICESocket()
|
||||
{}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
2895
src/libs/ice/ICEStream.cpp
Normal file
2895
src/libs/ice/ICEStream.cpp
Normal file
File diff suppressed because it is too large
Load Diff
367
src/libs/ice/ICEStream.h
Normal file
367
src/libs/ice/ICEStream.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_STREAM_H
|
||||
#define __ICE_STREAM_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ICEBox.h"
|
||||
#include "ICECandidate.h"
|
||||
#include "ICEStunConfig.h"
|
||||
#include "ICEAction.h"
|
||||
#include "ICEStunTransaction.h"
|
||||
#include "ICECheckList.h"
|
||||
#include "ICEBinding.h"
|
||||
#include "ICETime.h"
|
||||
#include "ICETransactionList.h"
|
||||
#include "ICERelaying.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
enum Failover
|
||||
{
|
||||
FailoverOn = 1,
|
||||
FailoverOff = 2
|
||||
};
|
||||
|
||||
// Session state
|
||||
enum RunningState
|
||||
{
|
||||
None = 0,
|
||||
CandidateGathering,
|
||||
EliminateRedudand,
|
||||
ComputingFoundations,
|
||||
StartingKeepAlives,
|
||||
PrioritizingCandidates,
|
||||
ChoosingDefault,
|
||||
CreatingSDP,
|
||||
ConnCheck,
|
||||
Failed,
|
||||
Success
|
||||
};
|
||||
|
||||
extern const char* RunningStateToString(RunningState state);
|
||||
|
||||
// Smart pointer to ICE stream type
|
||||
typedef SmartPtr<Stream> ICEStreamPtr;
|
||||
|
||||
|
||||
// Map of used channel TURN prefixes as key and corresponding address as value
|
||||
typedef std::map<TurnPrefix, NetworkAddress> TurnPrefixMap;
|
||||
|
||||
struct Component
|
||||
{
|
||||
void* mTag;
|
||||
unsigned short mPort4;
|
||||
unsigned short mPort6;
|
||||
unsigned mNominationWaitIntervalStartTime;
|
||||
Component()
|
||||
:mTag(NULL), mPort4(0), mPort6(0), mNominationWaitIntervalStartTime(0)
|
||||
{}
|
||||
|
||||
~Component()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<int, Component> ComponentMap;
|
||||
|
||||
// Represents single ICE stream with single or multiple components (sockets)
|
||||
struct Stream
|
||||
{
|
||||
// Stream id
|
||||
int mId;
|
||||
|
||||
// Stack ID. Used for debugging purposes.
|
||||
int mStackId;
|
||||
|
||||
// Map of component ID -> user tag
|
||||
ComponentMap mComponentMap;
|
||||
|
||||
// List of local candidates and list of remote candidates
|
||||
typedef std::vector<Candidate> CandidateVector;
|
||||
CandidateVector mLocalCandidate, mRemoteCandidate, mRemoteRelayedCandidate;
|
||||
|
||||
// Check list
|
||||
CheckList mCheckList;
|
||||
|
||||
// Logger
|
||||
Logger* mLogger;
|
||||
|
||||
// Foundation generator value to provide foundation value for peer reflexive candidates
|
||||
unsigned int mFoundationGenerator;
|
||||
|
||||
// Active STUN transactions. This vector includes connectivity check transactions and gather candidates transactions.
|
||||
// Keepalive transactions are stored in mKeepAliveList
|
||||
TransactionList mActiveChecks;
|
||||
|
||||
// ICE agent role
|
||||
AgentRole mAgentRole;
|
||||
|
||||
// Map of established relay channels
|
||||
TurnPrefixMap mTurnPrefixMap;
|
||||
|
||||
// Current state of media stream
|
||||
RunningState mState;
|
||||
|
||||
// Used configuration
|
||||
StackConfig mConfig;
|
||||
|
||||
// Helper vector used to prioritize candidates
|
||||
std::vector<unsigned> mComponentLimit;
|
||||
|
||||
// Default candidate list - one per each component
|
||||
std::map<int, Candidate> mDefaultCandidate;
|
||||
|
||||
// Local password/ufrag
|
||||
std::string mLocalPwd;
|
||||
std::string mLocalUfrag;
|
||||
|
||||
// Remote password/ufrag
|
||||
std::string mRemotePwd;
|
||||
std::string mRemoteUfrag;
|
||||
|
||||
// Marks if selected during connectivity checks default IP list differs from used to generate offer
|
||||
bool mDefaultIPChanged;
|
||||
|
||||
// Marks if checks was ok for this stream and each component has valid nominated pair
|
||||
bool mCanTransmit;
|
||||
|
||||
std::vector<ByteBuffer*> mResponseQueue;
|
||||
// Tie breaker
|
||||
std::string mTieBreaker;
|
||||
|
||||
// Timer to schedule connection checks (CC)
|
||||
ICEScheduleTimer mScheduleTimer;
|
||||
|
||||
// Counter of TURN allocations
|
||||
int mTurnAllocated;
|
||||
|
||||
// Last error code during gathering/checks
|
||||
int mErrorCode;
|
||||
|
||||
// Cached realm and nonce for used TURN server
|
||||
std::string mCachedRealm, mCachedNonce;
|
||||
|
||||
// Timestamp of nomination waiting timer. Used to accumulate valid pairs and chose the "best" of them.
|
||||
unsigned mNominationWaitStartTime;
|
||||
|
||||
// Number of finished failover gathering requests
|
||||
int mFailoverRequestsFinished;
|
||||
|
||||
// Failover ID generator. Failover transactions which share the same goal share the same ID.
|
||||
int mFailoverIdGenerator;
|
||||
|
||||
struct BoundChannel
|
||||
{
|
||||
int mComponentId;
|
||||
TurnPrefix mPrefix;
|
||||
NetworkAddress mPeerAddress;
|
||||
int mResultCode;
|
||||
};
|
||||
typedef std::vector<BoundChannel> BoundChannelList;
|
||||
BoundChannelList mBoundChannelList;
|
||||
|
||||
// Create Allocate transaction and associate with passed action
|
||||
struct AllocateOptions
|
||||
{
|
||||
NetworkAddress mServerAddress;
|
||||
PAction mActionOnFinish;
|
||||
int mComponent = 0;
|
||||
Failover mFailoverOption = FailoverOn;
|
||||
int mWireFamily = AF_INET;
|
||||
int mAllocFamily = AF_INET;
|
||||
int mFailoverId = 0;
|
||||
};
|
||||
void allocate(const AllocateOptions& options);
|
||||
|
||||
// Create Bind transaction and associate with passed action
|
||||
void bind(const NetworkAddress& addr, PAction action, bool auth, int component, Failover failover);
|
||||
|
||||
// Searches for local candidate with specified address
|
||||
unsigned findLocalCandidate(const NetworkAddress& addr);
|
||||
|
||||
// Cancels found transaction.
|
||||
void cancelCheck(CandidatePair& p);
|
||||
|
||||
// Cancels allocations
|
||||
void cancelAllocations();
|
||||
|
||||
// Searches for remote candidate with specified remote address and corresponding to local port number
|
||||
unsigned findRemoteCandidate(const NetworkAddress& addr, int componentID);
|
||||
|
||||
// Process incoming binding request
|
||||
void handleBindingRequest(ServerBinding& binding, ByteBuffer& buffer, int component);
|
||||
|
||||
// Handles incoming data in gathering candidate stage.
|
||||
bool handleCgIn(StunMessage& msg, NetworkAddress& address);
|
||||
|
||||
// Handle eliminate redudand stage
|
||||
void Handle_ER();
|
||||
|
||||
// Compute foundations
|
||||
void Handle_CF();
|
||||
|
||||
// Starting keep alive timers
|
||||
void Handle_SKA();
|
||||
|
||||
// Prioritize candidates
|
||||
void Handle_PC();
|
||||
|
||||
// Choosing default candidate
|
||||
void Handle_CD();
|
||||
|
||||
// Handles keepalive messages
|
||||
//bool handleKeepAlivesIn(StunMessage& msg, NetworkAddress& address);
|
||||
|
||||
// Handles incoming messages in connectivity checks stage
|
||||
// This method uses Handle_KA_In to perform keepalive handling
|
||||
bool handleConnChecksIn(StunMessage& msg, NetworkAddress& address);
|
||||
|
||||
// Handle incoming Bind request
|
||||
void handleIncomingRequest(StunMessage& msg, ByteBuffer& buffer, int component);
|
||||
|
||||
// Chooses default candidate for specified component ID
|
||||
Candidate findDefaultCandidate(int componentID);
|
||||
|
||||
//Performs 8.1.2. Updating States
|
||||
void checkNominated(int componentID);
|
||||
void checkNominated();
|
||||
bool handleRoleConflict(ServerBinding& binding);
|
||||
|
||||
//Checks active transactions (keepalive and ordinary) for timeouts
|
||||
void isTimeout();
|
||||
|
||||
// Checks for next byte buffer for sending
|
||||
ByteBuffer* handleConnChecksOut();
|
||||
|
||||
// Creates connectivity check request for specified pair.
|
||||
Transaction* createCheckRequest(PCandidatePair& p);
|
||||
|
||||
// Checks for TURN channel prefix by specified peer's address.
|
||||
// Returns zero prefix if it is not found.
|
||||
TurnPrefix findTurnPrefixByAddress(NetworkAddress& peerAddress);
|
||||
|
||||
// Create candidate pair in check list.
|
||||
void createCheckList();
|
||||
|
||||
// Starts connectivity checks - calls Create_CheckList to create check list + starts retransmission timer
|
||||
void startChecks();
|
||||
|
||||
// Stops connectivity checks and gathering requests
|
||||
void stopChecks();
|
||||
|
||||
// Initiates ChannelBind transaction to TURN server.
|
||||
TurnPrefix bindChannel(const NetworkAddress& peerAddress, int component, ChannelBoundCallback* cb = NULL);
|
||||
bool isChannelBindingFailed(int component, TurnPrefix prefix);
|
||||
void removeBindingResult(int component);
|
||||
|
||||
// Attempts to free allocation.
|
||||
void freeAllocation(int component, DeleteAllocationCallback* cb = NULL);
|
||||
|
||||
// Searches for local server reflexive candidate with specified component ID and returns its external address.
|
||||
NetworkAddress reflexiveAddress(int componentID);
|
||||
|
||||
/*! Searches for local server relayed candidate with specified component ID and returns its external address. */
|
||||
NetworkAddress relayedAddress(int componentID);
|
||||
|
||||
// Searches for remote server relayed candidate with specified component
|
||||
NetworkAddress remoteRelayedAddress(int component);
|
||||
|
||||
// Searches for remote server reflexive candidate with specified component
|
||||
NetworkAddress remoteReflexiveAddress(int component);
|
||||
|
||||
|
||||
Stream();
|
||||
~Stream();
|
||||
|
||||
// Sets config
|
||||
void setConfig(StackConfig& config);
|
||||
|
||||
// Sets ICE agent role - Controlled or Controlling
|
||||
void setAgentRole(AgentRole role);
|
||||
|
||||
// Sets local password
|
||||
void setLocalPwd(const std::string& pwd);
|
||||
|
||||
// Sets local ufrag
|
||||
void setLocalUfrag(const std::string& ufrag);
|
||||
|
||||
// Sets remote password
|
||||
void setRemotePwd(const std::string& pwd);
|
||||
|
||||
// Sets remote ufrag
|
||||
void setRemoteUfrag(const std::string& ufrag);
|
||||
|
||||
// Sets tie breaker
|
||||
void setTieBreaker(const std::string& tieBreaker);
|
||||
|
||||
// Adds new component to stream
|
||||
int addComponent(void* tag, unsigned short port4, unsigned short port6);
|
||||
|
||||
// Gathers candidates for stream
|
||||
void gatherCandidates();
|
||||
|
||||
// Returns reference to check list
|
||||
CheckList& checkList();
|
||||
|
||||
// Check is stream owns specified port number
|
||||
bool hasPortNumber(int family, unsigned short portNumber, int* component = NULL);
|
||||
|
||||
// Processes incoming data
|
||||
bool processData(StunMessage& msg, ByteBuffer& buffer, int component);
|
||||
|
||||
void createOfferSdp(std::vector<std::string>& defaultIP, std::vector<unsigned short>& defaultPort,
|
||||
std::vector<std::string>& candidateList);
|
||||
|
||||
NetworkAddress defaultAddress(int componentID);
|
||||
void candidateList(int componentID, std::vector<std::string>& candidateList);
|
||||
|
||||
PByteBuffer getDataToSend(bool& response, int& component, void*&tag);
|
||||
|
||||
// Constructs new keepalive transaction and adds to mKeepAlives
|
||||
void addKeepAliveCheck(CandidatePair& p);
|
||||
|
||||
// Processes SDP offer, adding remote candidates from it
|
||||
bool processSdpOffer(std::vector<std::string>& candidateList, std::string defaultIP, unsigned short defaultPort, bool deleteRelayed);
|
||||
|
||||
// Checks if remote candidate list contains specified address
|
||||
bool candidateListContains(const std::string& remoteIP, unsigned short remotePort);
|
||||
|
||||
// Restarts stream's connectivity checks
|
||||
void restart();
|
||||
|
||||
// Clears the stack; resets state to None. The free allocation requests are left in the queue
|
||||
void clear();
|
||||
|
||||
// Deletes existing connectivity checks and resets turn allocation counters
|
||||
void clearForRestart(bool localNetworkChanged);
|
||||
|
||||
// Returns resolved address of remote party identified by its componmentID
|
||||
NetworkAddress remoteAddress(int component);
|
||||
NetworkAddress localAddress(int component);
|
||||
|
||||
void installPermissions(int component = -1, const NetworkAddress& addr = NetworkAddress(), InstallPermissionsCallback* cb = NULL);
|
||||
void dump(std::ostream& output);
|
||||
bool findConcludePair(Candidate& local, Candidate& remote);
|
||||
int findComponentIdByPort(unsigned short port, int family);
|
||||
Transaction* runCheckList(CandidatePair::Role role, CandidatePair::State state);
|
||||
void deleteTransactionAt(unsigned index);
|
||||
void clearChecks();
|
||||
|
||||
void dumpLocalCandidateList();
|
||||
void processStateChain();
|
||||
|
||||
// Disables (removes) active transactions responsible for gathering candidates - binding & allocating
|
||||
void removeGatherRequests(int component, int failoverId, Transaction* validOne);
|
||||
void unfreeze(const char* foundation);
|
||||
void nominatePair(PCandidatePair& p);
|
||||
bool ressurectAllocation(int component);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
956
src/libs/ice/ICEStunAttributes.cpp
Normal file
956
src/libs/ice/ICEStunAttributes.cpp
Normal file
@@ -0,0 +1,956 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICENetworkHelper.h"
|
||||
#include <stdexcept>
|
||||
using namespace ice;
|
||||
|
||||
|
||||
|
||||
// --- MappedAddress ---
|
||||
MappedAddress::MappedAddress()
|
||||
{
|
||||
}
|
||||
|
||||
MappedAddress::~MappedAddress()
|
||||
{
|
||||
}
|
||||
|
||||
int MappedAddress::type() const
|
||||
{
|
||||
return StunAttribute::MappedAddress;
|
||||
}
|
||||
|
||||
NetworkAddress& MappedAddress::address()
|
||||
{
|
||||
return mAddress;
|
||||
}
|
||||
|
||||
void MappedAddress::buildPacket(BufferWriter& writer)
|
||||
{
|
||||
writer.writeUChar(0);
|
||||
writer.writeUChar(mAddress.stunType());
|
||||
writer.writeUShort(mAddress.port());
|
||||
|
||||
switch (mAddress.stunType())
|
||||
{
|
||||
case IPv4:
|
||||
writer.writeBuffer(&mAddress.sockaddr4()->sin_addr, 4);
|
||||
break;
|
||||
|
||||
case IPv6:
|
||||
writer.writeBuffer(&mAddress.sockaddr6()->sin6_addr, 16);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool MappedAddress::parsePacket(BufferReader& reader)
|
||||
{
|
||||
// Dequeue zero byte and ignore it
|
||||
/*uint8_t zeroByte = */reader.readUChar();
|
||||
|
||||
// Dequeue family
|
||||
mAddress.setStunType(reader.readUChar());
|
||||
|
||||
// Dequeue port
|
||||
mAddress.setPort(reader.readUShort());
|
||||
|
||||
// Deqeueue IP
|
||||
mAddress.setIp(reader.readIp(mAddress.stunType() == IPv4 ? AF_INET : AF_INET6));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MappedAddress::dump(std::ostream& output)
|
||||
{
|
||||
output << "MappedAddress " << mAddress.toStdString();
|
||||
}
|
||||
|
||||
|
||||
//----------- XorMappedAddress ---------------
|
||||
XorMappedAddress::XorMappedAddress()
|
||||
{}
|
||||
|
||||
XorMappedAddress::~XorMappedAddress()
|
||||
{}
|
||||
|
||||
int XorMappedAddress::type() const
|
||||
{
|
||||
return StunAttribute::XorMappedAddress;
|
||||
}
|
||||
|
||||
|
||||
void XorMappedAddress::buildPacket(BufferWriter& writer)
|
||||
{
|
||||
// Queue zero byte
|
||||
writer.writeUChar(0);
|
||||
|
||||
// Queue family
|
||||
writer.writeUChar(mAddress.stunType());
|
||||
|
||||
// Xor&queue port
|
||||
uint16_t port = mAddress.port() ^ 0x2112;
|
||||
writer.writeUShort(port);
|
||||
|
||||
// Xor&queue ip
|
||||
unsigned int ip4 = 0;
|
||||
uint32_t ip6[4];
|
||||
switch (mAddress.stunType())
|
||||
{
|
||||
case IPv4:
|
||||
ip4 = mAddress.sockaddr4()->sin_addr.s_addr; //this gets ip in network byte order
|
||||
ip4 = ntohl(ip4); // get host byte order
|
||||
ip4 ^= 0x2112A442;
|
||||
writer.writeUInt(ip4); // It will convert again to network byte order
|
||||
break;
|
||||
|
||||
case IPv6:
|
||||
// Get copy of address in network byte order
|
||||
memcpy(&ip6, &mAddress.sockaddr6()->sin6_addr, 16);
|
||||
|
||||
for (int i=0; i<3; i++)
|
||||
ip6[i] ^= htonl(0x2112A442);
|
||||
|
||||
writer.writeBuffer(ip6, 16);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool XorMappedAddress::parsePacket(BufferReader& reader)
|
||||
{
|
||||
// Dequeue zero byte and ignore it
|
||||
reader.readUChar();
|
||||
|
||||
// Dequeue family
|
||||
mAddress.setStunType(reader.readUChar());
|
||||
|
||||
// Dequeue port
|
||||
mAddress.setPort(reader.readUShort() ^ 0x2112);
|
||||
|
||||
// Deqeueue IP
|
||||
unsigned int ip4;
|
||||
union
|
||||
{
|
||||
uint32_t ip6[4];
|
||||
in6_addr addr6;
|
||||
} v6;
|
||||
|
||||
switch (mAddress.stunType())
|
||||
{
|
||||
case IPv4:
|
||||
ip4 = htonl(reader.readUInt() ^ 0x2112A442);
|
||||
mAddress.setIp(ip4);
|
||||
break;
|
||||
|
||||
case IPv6:
|
||||
reader.readBuffer(v6.ip6, 16);
|
||||
// XOR buffer
|
||||
for (int i=0; i<3; i++)
|
||||
v6.ip6[i] ^= htonl(0x2112A442);
|
||||
mAddress.setIp(v6.addr6);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XorMappedAddress::dump(std::ostream &output)
|
||||
{
|
||||
output << "XorMappedAddress " << mAddress.toStdString();
|
||||
}
|
||||
|
||||
//------------ StringAttr -----------------------
|
||||
StringAttr::StringAttr()
|
||||
{
|
||||
}
|
||||
StringAttr::~StringAttr()
|
||||
{
|
||||
}
|
||||
|
||||
int StringAttr::type() const
|
||||
{
|
||||
return StunAttribute::UnknownAttributes;
|
||||
}
|
||||
|
||||
std::string StringAttr::value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void StringAttr::setValue(const std::string& value)
|
||||
{
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
void StringAttr::buildPacket(BufferWriter& writer)
|
||||
{
|
||||
if (!mValue.empty())
|
||||
writer.writeBuffer(mValue.c_str(), mValue.length());
|
||||
}
|
||||
|
||||
bool StringAttr::parsePacket(BufferReader& reader)
|
||||
{
|
||||
char temp[1024]; memset(temp, 0, sizeof temp);
|
||||
reader.readBuffer(temp, sizeof temp);
|
||||
mValue = temp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringAttr::dump(std::ostream& output)
|
||||
{
|
||||
output << "StringAttr " << mValue;
|
||||
}
|
||||
|
||||
//----------- Username ---------------------------------
|
||||
Username::Username()
|
||||
{}
|
||||
|
||||
Username::~Username()
|
||||
{}
|
||||
|
||||
int Username::type() const
|
||||
{
|
||||
return StunAttribute::Username;
|
||||
}
|
||||
|
||||
void Username::dump(std::ostream &output)
|
||||
{
|
||||
output << "Username " << value();
|
||||
}
|
||||
|
||||
//----------- MessageIntegrity -------------------------
|
||||
MessageIntegrity::MessageIntegrity()
|
||||
{
|
||||
memset(mValue, 0, sizeof(mValue));
|
||||
}
|
||||
MessageIntegrity::~MessageIntegrity()
|
||||
{
|
||||
}
|
||||
|
||||
int MessageIntegrity::type() const
|
||||
{
|
||||
return StunAttribute::MessageIntegrity;
|
||||
}
|
||||
|
||||
void MessageIntegrity::setValue(const void* data)
|
||||
{
|
||||
if (data)
|
||||
memcpy(mValue, data, 20);
|
||||
}
|
||||
|
||||
const void* MessageIntegrity::value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void MessageIntegrity::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeBuffer(mValue, 20);
|
||||
}
|
||||
|
||||
bool MessageIntegrity::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.readBuffer(mValue, 20);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessageIntegrity::dump(std::ostream &output)
|
||||
{
|
||||
ByteBuffer buffer(mValue, 20);
|
||||
output << "MessageIntegrity " << buffer.hexstring();
|
||||
}
|
||||
|
||||
//--------------- Fingerprint ----------------
|
||||
Fingerprint::Fingerprint()
|
||||
{
|
||||
mCRC32 = 0;
|
||||
}
|
||||
|
||||
Fingerprint::~Fingerprint()
|
||||
{
|
||||
}
|
||||
|
||||
int Fingerprint::type() const
|
||||
{
|
||||
return StunAttribute::Fingerprint;
|
||||
}
|
||||
|
||||
void Fingerprint::setCrc32(unsigned int crc)
|
||||
{
|
||||
mCRC32 = crc;
|
||||
}
|
||||
|
||||
unsigned int Fingerprint::crc32() const
|
||||
{
|
||||
return mCRC32;
|
||||
}
|
||||
|
||||
void Fingerprint::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUInt(mCRC32);
|
||||
}
|
||||
|
||||
bool Fingerprint::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mCRC32 = stream.readUInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Fingerprint::dump(std::ostream &output)
|
||||
{
|
||||
output << "Fingerprint " << mCRC32;
|
||||
}
|
||||
|
||||
//---------------- ErrorCode ---------------
|
||||
ErrorCode::ErrorCode()
|
||||
{
|
||||
mErrorCode = 0;
|
||||
}
|
||||
|
||||
ErrorCode::~ErrorCode()
|
||||
{
|
||||
}
|
||||
|
||||
int ErrorCode::type() const
|
||||
{
|
||||
return StunAttribute::ErrorCode;
|
||||
}
|
||||
|
||||
void ErrorCode::setErrorCode(int errorCode)
|
||||
{
|
||||
mErrorCode = errorCode;
|
||||
}
|
||||
|
||||
int ErrorCode::errorCode() const
|
||||
{
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
void ErrorCode::setErrorPhrase(const std::string& phrase)
|
||||
{
|
||||
mErrorPhrase = phrase;
|
||||
}
|
||||
|
||||
std::string ErrorCode::errorPhrase() const
|
||||
{
|
||||
return mErrorPhrase;
|
||||
}
|
||||
|
||||
void ErrorCode::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUShort(0);
|
||||
|
||||
uint8_t b = 0;
|
||||
// Get hundreds digit
|
||||
int digit = mErrorCode / 100;
|
||||
b = (digit & 4 ? 1 : 0) << 2;
|
||||
b |= (digit & 2 ? 1 : 0) << 1;
|
||||
b |= (digit & 1 ? 1 : 0);
|
||||
stream.writeUChar(b);
|
||||
|
||||
stream.writeUChar(mErrorCode % 100);
|
||||
|
||||
if (!mErrorPhrase.empty())
|
||||
stream.writeBuffer(mErrorPhrase.c_str(), mErrorPhrase.length());
|
||||
}
|
||||
|
||||
bool ErrorCode::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.readUShort();
|
||||
unsigned char _class = stream.readUChar();
|
||||
unsigned char _number = stream.readUChar();
|
||||
|
||||
mErrorCode = _class * 100 + _number;
|
||||
char temp[1024]; memset(temp, 0, sizeof temp);
|
||||
stream.readBuffer(temp, sizeof temp);
|
||||
mErrorPhrase = std::string(temp);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ErrorCode::dump(std::ostream &output)
|
||||
{
|
||||
output << "ErrorCode " << mErrorCode << " " << mErrorPhrase;
|
||||
}
|
||||
|
||||
//----------------- Realm ------------------------
|
||||
Realm::Realm()
|
||||
{}
|
||||
|
||||
Realm::~Realm()
|
||||
{}
|
||||
|
||||
int Realm::type() const
|
||||
{
|
||||
return StunAttribute::Realm;
|
||||
}
|
||||
|
||||
void Realm::dump(std::ostream &output)
|
||||
{
|
||||
output << "Realm " << value();
|
||||
}
|
||||
|
||||
//----------------- Nonce ------------------------
|
||||
Nonce::Nonce()
|
||||
{}
|
||||
|
||||
Nonce::~Nonce()
|
||||
{}
|
||||
|
||||
int Nonce::type() const
|
||||
{
|
||||
return StunAttribute::Nonce;
|
||||
}
|
||||
|
||||
void Nonce::dump(std::ostream &output)
|
||||
{
|
||||
output << "Nonce " << value();
|
||||
}
|
||||
|
||||
//----------------- Server -----------------------
|
||||
Server::Server()
|
||||
{}
|
||||
|
||||
Server::~Server()
|
||||
{}
|
||||
|
||||
int Server::type() const
|
||||
{
|
||||
return StunAttribute::Server;
|
||||
}
|
||||
|
||||
void Server::dump(std::ostream &output)
|
||||
{
|
||||
output << "Server " << value();
|
||||
}
|
||||
|
||||
//----------------- AlternateServer --------------
|
||||
AlternateServer::AlternateServer()
|
||||
{}
|
||||
|
||||
AlternateServer::~AlternateServer()
|
||||
{}
|
||||
|
||||
int AlternateServer::type() const
|
||||
{
|
||||
return StunAttribute::AlternateServer;
|
||||
}
|
||||
|
||||
void AlternateServer::dump(std::ostream &output)
|
||||
{
|
||||
output << "AlternateServer " << address().toStdString();
|
||||
}
|
||||
|
||||
//----------------- UnknownAttributes ------------
|
||||
UnknownAttributes::UnknownAttributes()
|
||||
{
|
||||
}
|
||||
|
||||
UnknownAttributes::~UnknownAttributes()
|
||||
{
|
||||
}
|
||||
|
||||
int UnknownAttributes::type() const
|
||||
{
|
||||
return StunAttribute::UnknownAttributes;
|
||||
}
|
||||
|
||||
void UnknownAttributes::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
char zeroBytes[8]; memset(zeroBytes, 0, sizeof(zeroBytes));
|
||||
stream.writeBuffer(zeroBytes, sizeof(zeroBytes));
|
||||
}
|
||||
|
||||
bool UnknownAttributes::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
char zeroBytes[8]; memset(zeroBytes, 0, sizeof(zeroBytes));
|
||||
stream.readBuffer(zeroBytes, sizeof(zeroBytes));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnknownAttributes::dump(std::ostream &output)
|
||||
{
|
||||
output << "UnknownAttributes";
|
||||
}
|
||||
|
||||
//---------------- ChannelNumber ----------------
|
||||
ChannelNumber::ChannelNumber()
|
||||
:mChannelNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
ChannelNumber::~ChannelNumber()
|
||||
{
|
||||
}
|
||||
|
||||
int ChannelNumber::type() const
|
||||
{
|
||||
return StunAttribute::ChannelNumber;
|
||||
}
|
||||
|
||||
void ChannelNumber::setChannelNumber(unsigned short value)
|
||||
{
|
||||
mChannelNumber = value;
|
||||
}
|
||||
|
||||
unsigned short ChannelNumber::channelNumber() const
|
||||
{
|
||||
return mChannelNumber;
|
||||
}
|
||||
|
||||
void ChannelNumber::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUShort(mChannelNumber);
|
||||
stream.writeUChar(0);
|
||||
stream.writeUChar(0);
|
||||
}
|
||||
|
||||
bool ChannelNumber::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mChannelNumber = stream.readUShort();
|
||||
stream.readUChar();
|
||||
stream.readUChar();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChannelNumber::dump(std::ostream &output)
|
||||
{
|
||||
output << "ChannelNumber " << mChannelNumber;
|
||||
}
|
||||
|
||||
//--------------------------------- Lifetime -----------------------
|
||||
Lifetime::Lifetime()
|
||||
:mLifetime(0)
|
||||
{
|
||||
}
|
||||
|
||||
Lifetime::~Lifetime()
|
||||
{
|
||||
}
|
||||
|
||||
int Lifetime::type() const
|
||||
{
|
||||
return StunAttribute::Lifetime;
|
||||
}
|
||||
|
||||
void Lifetime::setLifetime(unsigned int value)
|
||||
{
|
||||
mLifetime = value;
|
||||
}
|
||||
|
||||
unsigned int Lifetime::lifetime() const
|
||||
{
|
||||
return mLifetime;
|
||||
}
|
||||
|
||||
void Lifetime::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUInt(mLifetime);
|
||||
}
|
||||
|
||||
bool Lifetime::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mLifetime = stream.readUInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Lifetime::dump(std::ostream &output)
|
||||
{
|
||||
output << "Lifetime " << mLifetime;
|
||||
}
|
||||
|
||||
//----------------------- DataAttribute ----------------------
|
||||
|
||||
DataAttribute::DataAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
DataAttribute::~DataAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
int DataAttribute::type() const
|
||||
{
|
||||
return StunAttribute::Data;
|
||||
}
|
||||
|
||||
void DataAttribute::setData(ByteBuffer& buffer)
|
||||
{
|
||||
mData = buffer;
|
||||
}
|
||||
|
||||
ByteBuffer DataAttribute::data() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
void DataAttribute::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeBuffer(mData.data(), mData.size());
|
||||
}
|
||||
|
||||
bool DataAttribute::parsePacket(BufferReader& stream)
|
||||
{
|
||||
mData.resize(1024);
|
||||
mData.resize(stream.readBuffer(mData.mutableData(), mData.size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataAttribute::dump(std::ostream &output)
|
||||
{
|
||||
output << "DataAttribute " << mData.hexstring();
|
||||
}
|
||||
|
||||
//---------------------- XorRelayedTransport -------------------------
|
||||
XorRelayedAddress::XorRelayedAddress()
|
||||
{}
|
||||
|
||||
XorRelayedAddress::~XorRelayedAddress()
|
||||
{}
|
||||
|
||||
int XorRelayedAddress::type() const
|
||||
{
|
||||
return StunAttribute::XorRelayedAddress;
|
||||
}
|
||||
|
||||
void XorRelayedAddress::dump(std::ostream &output)
|
||||
{
|
||||
output << "XorRelayedAddress " << address().toStdString();
|
||||
}
|
||||
|
||||
//---------------------- RequestedTransport ---------------------------
|
||||
RequestedTransport::RequestedTransport()
|
||||
:mRequestedTransport(UDP)
|
||||
{
|
||||
}
|
||||
|
||||
RequestedTransport::~RequestedTransport()
|
||||
{
|
||||
}
|
||||
|
||||
int RequestedTransport::type() const
|
||||
{
|
||||
return StunAttribute::RequestedTransport;
|
||||
}
|
||||
|
||||
void RequestedTransport::setRequestedTransport(RequestedTransport::TransportType value)
|
||||
{
|
||||
mRequestedTransport = value;
|
||||
}
|
||||
|
||||
unsigned char RequestedTransport::requestedTransport() const
|
||||
{
|
||||
return mRequestedTransport;
|
||||
}
|
||||
|
||||
void RequestedTransport::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUChar(mRequestedTransport);
|
||||
stream.writeUChar(0);
|
||||
stream.writeUChar(0);
|
||||
stream.writeUChar(0);
|
||||
}
|
||||
|
||||
bool RequestedTransport::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mRequestedTransport = stream.readUChar();
|
||||
stream.readUChar();
|
||||
stream.readUChar();
|
||||
stream.readUChar();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RequestedTransport::dump(std::ostream &output)
|
||||
{
|
||||
output << "RequestedTransport " << mRequestedTransport;
|
||||
}
|
||||
|
||||
//--------------------------------- Controlled -----------------------
|
||||
ControlledAttr::ControlledAttr()
|
||||
{
|
||||
}
|
||||
|
||||
ControlledAttr::~ControlledAttr()
|
||||
{
|
||||
}
|
||||
|
||||
int ControlledAttr::type() const
|
||||
{
|
||||
return StunAttribute::ControlledAttr;
|
||||
}
|
||||
|
||||
std::string ControlledAttr::tieBreaker() const
|
||||
{
|
||||
return std::string((const char*)mTieBreaker, 8);
|
||||
}
|
||||
|
||||
void ControlledAttr::setTieBreaker(const std::string& tieBreaker)
|
||||
{
|
||||
assert(tieBreaker.length() == 8);
|
||||
|
||||
memcpy(mTieBreaker, tieBreaker.c_str(), 8);
|
||||
}
|
||||
|
||||
void ControlledAttr::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeBuffer(mTieBreaker, 8);
|
||||
}
|
||||
|
||||
bool ControlledAttr::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.readBuffer(mTieBreaker, 8);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControlledAttr::dump(std::ostream &output)
|
||||
{
|
||||
ByteBuffer b(mTieBreaker, 8);
|
||||
output << "ControlledAttr " << b.hexstring();
|
||||
}
|
||||
|
||||
//------------------- ControllingAttr --------------
|
||||
ControllingAttr::ControllingAttr()
|
||||
{
|
||||
memset(mTieBreaker, 0, sizeof(mTieBreaker));
|
||||
}
|
||||
|
||||
ControllingAttr::~ControllingAttr()
|
||||
{
|
||||
}
|
||||
|
||||
int ControllingAttr::type() const
|
||||
{
|
||||
return StunAttribute::ControllingAttr;
|
||||
}
|
||||
|
||||
std::string ControllingAttr::tieBreaker() const
|
||||
{
|
||||
return std::string((const char*)mTieBreaker, 8);
|
||||
}
|
||||
|
||||
void ControllingAttr::setTieBreaker(const std::string& tieBreaker)
|
||||
{
|
||||
memcpy(mTieBreaker, tieBreaker.c_str(), 8);
|
||||
}
|
||||
|
||||
void ControllingAttr::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeBuffer(mTieBreaker, 8);
|
||||
}
|
||||
|
||||
bool ControllingAttr::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.readBuffer(mTieBreaker, 8);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ControllingAttr::dump(std::ostream &output)
|
||||
{
|
||||
ByteBuffer b(mTieBreaker, 8);
|
||||
output << "ControllingAttr " << b.hexstring();
|
||||
}
|
||||
|
||||
//----------- ICEPriority ---------------
|
||||
ICEPriority::ICEPriority()
|
||||
{
|
||||
mPriority = 0;
|
||||
}
|
||||
|
||||
ICEPriority::~ICEPriority()
|
||||
{
|
||||
}
|
||||
|
||||
int ICEPriority::type() const
|
||||
{
|
||||
return StunAttribute::ICEPriority;
|
||||
}
|
||||
|
||||
unsigned int ICEPriority::priority() const
|
||||
{
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
void ICEPriority::setPriority(unsigned int priority)
|
||||
{
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
void ICEPriority::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUInt(mPriority);
|
||||
}
|
||||
|
||||
bool ICEPriority::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mPriority = stream.readUInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ICEPriority::dump(std::ostream &output)
|
||||
{
|
||||
output << "ICEPriority " << mPriority;
|
||||
}
|
||||
|
||||
//------------------ USE-CANDIDATE -----------------------
|
||||
ICEUseCandidate::ICEUseCandidate()
|
||||
{
|
||||
}
|
||||
|
||||
ICEUseCandidate::~ICEUseCandidate()
|
||||
{
|
||||
}
|
||||
|
||||
int ICEUseCandidate::type() const
|
||||
{
|
||||
return StunAttribute::ICEUseCandidate;
|
||||
}
|
||||
|
||||
void ICEUseCandidate::buildPacket(BufferWriter& /*buffer*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool ICEUseCandidate::parsePacket(BufferReader& /*buffer*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ICEUseCandidate::dump(std::ostream &output)
|
||||
{
|
||||
output << "ICEUseCandidate";
|
||||
}
|
||||
// ------------- REQUESTED-ADDRESS-FAMILY -------------
|
||||
RequestedAddressFamily::RequestedAddressFamily()
|
||||
:mAddressFamily(IPv4)
|
||||
{}
|
||||
|
||||
RequestedAddressFamily::RequestedAddressFamily(AddressFamily family)
|
||||
:mAddressFamily(family)
|
||||
{}
|
||||
|
||||
RequestedAddressFamily::~RequestedAddressFamily()
|
||||
{}
|
||||
|
||||
int RequestedAddressFamily::type() const
|
||||
{
|
||||
return StunAttribute::RequestedAddressFamily;
|
||||
}
|
||||
|
||||
AddressFamily RequestedAddressFamily::family() const
|
||||
{
|
||||
return mAddressFamily;
|
||||
}
|
||||
|
||||
void RequestedAddressFamily::buildPacket(BufferWriter& stream)
|
||||
{
|
||||
stream.writeUChar(mAddressFamily);
|
||||
stream.writeUChar(0); stream.writeUChar(0); stream.writeUChar(0);
|
||||
}
|
||||
|
||||
bool RequestedAddressFamily::parsePacket(BufferReader& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
mAddressFamily = (AddressFamily)stream.readUChar();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RequestedAddressFamily::dump(std::ostream &output)
|
||||
{
|
||||
output << "RequestedAddressFamily " << (mAddressFamily == IPv4 ? "IPv4" : "IPv6");
|
||||
}
|
||||
363
src/libs/ice/ICEStunAttributes.h
Normal file
363
src/libs/ice/ICEStunAttributes.h
Normal file
@@ -0,0 +1,363 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_STUN_ATTRIBUTES_H
|
||||
#define __ICE_STUN_ATTRIBUTES_H
|
||||
|
||||
#include "ICEStunMessage.h"
|
||||
#include <string>
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class MappedAddress: public StunAttribute
|
||||
{
|
||||
public:
|
||||
MappedAddress();
|
||||
virtual ~MappedAddress();
|
||||
|
||||
virtual int type() const override;
|
||||
NetworkAddress& address();
|
||||
virtual void buildPacket(BufferWriter& buffer) override;
|
||||
virtual bool parsePacket(BufferReader& buffer) override;
|
||||
virtual void dump(std::ostream& output) override;
|
||||
|
||||
protected:
|
||||
NetworkAddress mAddress;
|
||||
};
|
||||
|
||||
class XorMappedAddress: public MappedAddress
|
||||
{
|
||||
public:
|
||||
XorMappedAddress();
|
||||
virtual ~XorMappedAddress();
|
||||
virtual int type() const override;
|
||||
|
||||
virtual void buildPacket(BufferWriter& writer) override;
|
||||
virtual bool parsePacket(BufferReader& reader) override;
|
||||
virtual void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class StringAttr: public StunAttribute
|
||||
{
|
||||
public:
|
||||
StringAttr();
|
||||
virtual ~StringAttr();
|
||||
|
||||
virtual int type() const override;
|
||||
std::string value() const;
|
||||
void setValue(const std::string& value);
|
||||
|
||||
virtual void buildPacket(BufferWriter& writer) override;
|
||||
virtual bool parsePacket(BufferReader& reader) override;
|
||||
virtual void dump(std::ostream& output) override;
|
||||
|
||||
protected:
|
||||
std::string mValue;
|
||||
};
|
||||
|
||||
class Username: public StringAttr
|
||||
{
|
||||
public:
|
||||
Username();
|
||||
~Username();
|
||||
int type() const;
|
||||
void dump(std::ostream& output);
|
||||
};
|
||||
|
||||
class MessageIntegrity: public StunAttribute
|
||||
{
|
||||
public:
|
||||
MessageIntegrity();
|
||||
~MessageIntegrity();
|
||||
|
||||
int type() const override;
|
||||
void setValue(const void* data);
|
||||
const void* value() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
|
||||
protected:
|
||||
unsigned char mValue[20];
|
||||
};
|
||||
|
||||
class Fingerprint: public StunAttribute
|
||||
{
|
||||
public:
|
||||
Fingerprint();
|
||||
~Fingerprint();
|
||||
|
||||
int type() const override;
|
||||
void setCrc32(unsigned int crc);
|
||||
unsigned int crc32() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
|
||||
protected:
|
||||
unsigned int mCRC32;
|
||||
};
|
||||
|
||||
class ErrorCode: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ErrorCode();
|
||||
~ErrorCode();
|
||||
|
||||
virtual int type() const override;
|
||||
void setErrorCode(int errorCode);
|
||||
int errorCode() const;
|
||||
|
||||
void setErrorPhrase(const std::string& phrase);
|
||||
std::string errorPhrase() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
|
||||
protected:
|
||||
int mErrorCode;
|
||||
std::string mErrorPhrase;
|
||||
};
|
||||
|
||||
class Realm: public StringAttr
|
||||
{
|
||||
public:
|
||||
Realm();
|
||||
~Realm();
|
||||
int type() const override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class Nonce: public StringAttr
|
||||
{
|
||||
public:
|
||||
Nonce();
|
||||
~Nonce();
|
||||
|
||||
int type() const override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class UnknownAttributes: public StunAttribute
|
||||
{
|
||||
public:
|
||||
UnknownAttributes();
|
||||
~UnknownAttributes();
|
||||
|
||||
int type() const override;
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class Server: public StringAttr
|
||||
{
|
||||
public:
|
||||
Server();
|
||||
~Server();
|
||||
int type() const override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class AlternateServer: public MappedAddress
|
||||
{
|
||||
public:
|
||||
AlternateServer();
|
||||
~AlternateServer();
|
||||
int type() const override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
|
||||
class ChannelNumber: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ChannelNumber();
|
||||
~ChannelNumber();
|
||||
|
||||
int type() const override;
|
||||
void setChannelNumber(unsigned short value);
|
||||
unsigned short channelNumber() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned short mChannelNumber;
|
||||
};
|
||||
|
||||
class Lifetime: public StunAttribute
|
||||
{
|
||||
public:
|
||||
Lifetime();
|
||||
~Lifetime();
|
||||
|
||||
int type() const override;
|
||||
void setLifetime(unsigned int value);
|
||||
unsigned int lifetime() const;
|
||||
|
||||
void buildPacket(BufferWriter& writer) override;
|
||||
bool parsePacket(BufferReader& reader) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned int mLifetime;
|
||||
};
|
||||
|
||||
class XorPeerAddress: public XorMappedAddress
|
||||
{
|
||||
public:
|
||||
int type() const override
|
||||
{
|
||||
return StunAttribute::XorPeerAddress;
|
||||
}
|
||||
};
|
||||
|
||||
class DataAttribute: public StunAttribute
|
||||
{
|
||||
public:
|
||||
DataAttribute();
|
||||
virtual ~DataAttribute();
|
||||
|
||||
int type() const override;
|
||||
void setData(ByteBuffer& buffer);
|
||||
ByteBuffer data() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream &output) override;
|
||||
|
||||
protected:
|
||||
ByteBuffer mData;
|
||||
};
|
||||
|
||||
class XorRelayedAddress: public XorMappedAddress
|
||||
{
|
||||
public:
|
||||
XorRelayedAddress();
|
||||
~XorRelayedAddress();
|
||||
int type() const override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class RequestedTransport: public StunAttribute
|
||||
{
|
||||
public:
|
||||
RequestedTransport();
|
||||
virtual ~RequestedTransport();
|
||||
|
||||
enum TransportType
|
||||
{
|
||||
UDP = 17
|
||||
};
|
||||
|
||||
int type() const override;
|
||||
void setRequestedTransport(TransportType value);
|
||||
unsigned char requestedTransport() const;
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned char mRequestedTransport; //always 17!
|
||||
};
|
||||
|
||||
class ReservedToken: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ReservedToken();
|
||||
~ReservedToken();
|
||||
|
||||
int type() const override;
|
||||
void setToken(const std::string& token);
|
||||
std::string token() const;
|
||||
|
||||
void buildPacket(BufferWriter& buffer) override;
|
||||
bool parsePacket(BufferReader& buffer) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
std::string mToken;
|
||||
};
|
||||
|
||||
class ControlledAttr: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ControlledAttr();
|
||||
~ControlledAttr();
|
||||
|
||||
int type() const override;
|
||||
|
||||
std::string tieBreaker() const;
|
||||
void setTieBreaker(const std::string& tieBreaker);
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned char mTieBreaker[8];
|
||||
};
|
||||
|
||||
class ControllingAttr: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ControllingAttr();
|
||||
~ControllingAttr();
|
||||
|
||||
int type() const override;
|
||||
std::string tieBreaker() const;
|
||||
void setTieBreaker(const std::string& tieBreaker);
|
||||
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned char mTieBreaker[8];
|
||||
};
|
||||
|
||||
class ICEPriority: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ICEPriority();
|
||||
~ICEPriority();
|
||||
|
||||
int type() const override;
|
||||
unsigned int priority() const;
|
||||
void setPriority(unsigned int priority);
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
unsigned int mPriority;
|
||||
};
|
||||
|
||||
class ICEUseCandidate: public StunAttribute
|
||||
{
|
||||
public:
|
||||
ICEUseCandidate();
|
||||
virtual ~ICEUseCandidate();
|
||||
int type() const override;
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
};
|
||||
|
||||
class RequestedAddressFamily: public StunAttribute
|
||||
{
|
||||
public:
|
||||
RequestedAddressFamily();
|
||||
RequestedAddressFamily(AddressFamily family);
|
||||
~RequestedAddressFamily();
|
||||
|
||||
int type() const override;
|
||||
AddressFamily family() const;
|
||||
void buildPacket(BufferWriter& stream) override;
|
||||
bool parsePacket(BufferReader& stream) override;
|
||||
void dump(std::ostream& output) override;
|
||||
protected:
|
||||
AddressFamily mAddressFamily;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
50
src/libs/ice/ICEStunConfig.cpp
Normal file
50
src/libs/ice/ICEStunConfig.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEStunConfig.h"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
std::string StackConfig::mDefaultIpTarget = ICE_FALLBACK_IP_ADDR;
|
||||
|
||||
StackConfig::StackConfig()
|
||||
:mUseTURN(false), mTimeout(DEFAULT_STUN_FINISH_TIMEOUT), mPeriod(DEFAULT_STUN_RETRANSMIT_TIMEOUT),
|
||||
mUseSTUN(true), mUseIPv4(true), mUseIPv6(true)
|
||||
{
|
||||
#ifdef ICE_AGGRESSIVE
|
||||
mAggressiveNomination = true;
|
||||
mTreatRequestAsConfirmation = false;
|
||||
#endif
|
||||
|
||||
#ifdef ICE_VERYAGGRESSIVE
|
||||
mAggressiveNomination = true;
|
||||
mTreatRequestAsConfirmation = true;
|
||||
#else
|
||||
mAggressiveNomination = false;
|
||||
mTreatRequestAsConfirmation = false;
|
||||
#endif
|
||||
mInitialRTO = 100;
|
||||
mKeepAliveInterval = 5000;
|
||||
mServerAddr4.setPort( 3478 );
|
||||
mServerAddr6.setPort( 3478 );
|
||||
mTurnLifetime = 300;
|
||||
mUseProtocolRelay = true;// false;
|
||||
|
||||
#ifdef TEST_RELAYING
|
||||
mTypePreferenceList[Candidate::Host] = 0;
|
||||
mTypePreferenceList[Candidate::ServerReflexive] = 110;
|
||||
mTypePreferenceList[Candidate::PeerReflexive] = 100;
|
||||
mTypePreferenceList[Candidate::ServerRelayed] = 126;
|
||||
#else
|
||||
mTypePreferenceList[Candidate::Host] = 126;
|
||||
mTypePreferenceList[Candidate::ServerReflexive] = 100;
|
||||
mTypePreferenceList[Candidate::PeerReflexive] = 110;
|
||||
mTypePreferenceList[Candidate::ServerRelayed] = 0;
|
||||
#endif
|
||||
mTargetIP = mDefaultIpTarget;
|
||||
}
|
||||
|
||||
StackConfig::~StackConfig()
|
||||
{}
|
||||
86
src/libs/ice/ICEStunConfig.h
Normal file
86
src/libs/ice/ICEStunConfig.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_STUN_CONFIG_H
|
||||
#define __ICE_STUN_CONFIG_H
|
||||
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICECandidate.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ice {
|
||||
|
||||
#define DEFAULT_STUN_RETRANSMIT_TIMEOUT 790000
|
||||
#define DEFAULT_STUN_FINISH_TIMEOUT 790000
|
||||
#define ICE_FALLBACK_IP_ADDR "8.8.8.8"
|
||||
// #define TEST_RELAYING
|
||||
|
||||
struct StackConfig
|
||||
{
|
||||
// The IP of STUN server
|
||||
std::vector<NetworkAddress> mServerList4,
|
||||
mServerList6;
|
||||
NetworkAddress mServerAddr4,
|
||||
mServerAddr6;
|
||||
|
||||
// Use IPv4 when gathering candidates
|
||||
bool mUseIPv4;
|
||||
|
||||
// Use IPv6 when gathering candidates
|
||||
bool mUseIPv6;
|
||||
|
||||
// Should we use relying (TURN)?
|
||||
bool mUseTURN;
|
||||
|
||||
// Should we use IPv4 <--> IPv6 bypassing via relaying ?
|
||||
bool mUseProtocolRelay;
|
||||
|
||||
// The timeout for STUN transaction
|
||||
unsigned int mTimeout;
|
||||
|
||||
// The RTO
|
||||
unsigned int mPeriod;
|
||||
|
||||
// Marks if STUN use is disalbed
|
||||
bool mUseSTUN;
|
||||
|
||||
// Sets the possible peer IP for ICE session
|
||||
std::string mTargetIP;
|
||||
|
||||
// The type preference list for ICE session
|
||||
int mTypePreferenceList[4];
|
||||
|
||||
// The initial RTO value
|
||||
int mInitialRTO;
|
||||
|
||||
// Interval for keepalive checks
|
||||
int mKeepAliveInterval;
|
||||
|
||||
std::string mTurnUsername,
|
||||
mTurnPassword;
|
||||
|
||||
// TURN lifetime
|
||||
int mTurnLifetime;
|
||||
|
||||
// Enable/disable aggressive nomination
|
||||
bool mAggressiveNomination;
|
||||
|
||||
// Treats requests as confirmation for connectivity checks sent in reverse direction if the corresponding pair already exists
|
||||
// It violates RFC. It can be needed in poor networks.
|
||||
bool mTreatRequestAsConfirmation;
|
||||
|
||||
// Default IP target if mTargetIP is not set
|
||||
static std::string mDefaultIpTarget;
|
||||
|
||||
StackConfig();
|
||||
~StackConfig();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
852
src/libs/ice/ICEStunMessage.cpp
Normal file
852
src/libs/ice/ICEStunMessage.cpp
Normal file
@@ -0,0 +1,852 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEStunMessage.h"
|
||||
#include "ICECRC32.h"
|
||||
#include "ICESHA1.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICEError.h"
|
||||
#include "ICELog.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <arpa/inet.h>
|
||||
# include <alloca.h>
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
|
||||
#define STUN_HEADER_SIZE 20
|
||||
#define HMAC_DIGEST_SIZE 20
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
using namespace ice;
|
||||
|
||||
bool StunMessage::TransactionID::operator == (const StunMessage::TransactionID& rhs)
|
||||
{
|
||||
return memcmp(mValue, rhs.mValue, 12) == 0;
|
||||
}
|
||||
|
||||
bool StunMessage::TransactionID::operator != (const TransactionID& rhs)
|
||||
{
|
||||
return memcmp(mValue, rhs.mValue, 12) != 0;
|
||||
}
|
||||
|
||||
StunMessage::TransactionID::TransactionID()
|
||||
{
|
||||
for (int i=0; i<12; i++)
|
||||
mValue[i] = rand() & 0xFF;
|
||||
|
||||
//memset(mValue, 0, 12);
|
||||
}
|
||||
|
||||
std::string StunMessage::TransactionID::toStdString()
|
||||
{
|
||||
char hex[3];
|
||||
std::string result;
|
||||
for (size_t i=0; i<12; i++)
|
||||
{
|
||||
sprintf(hex, "%2x", mValue[i]);
|
||||
result += hex;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StunMessage::TransactionID StunMessage::TransactionID::generateNew()
|
||||
{
|
||||
TransactionID result;
|
||||
for (size_t i=0; i<12; i++)
|
||||
result.mValue[i] = (unsigned char)rand();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------- StunAttribute ----------------------
|
||||
StunAttribute::StunAttribute()
|
||||
{
|
||||
mLength = 0;
|
||||
mType = 0;
|
||||
mDataOffset = 0;
|
||||
}
|
||||
|
||||
StunAttribute::~StunAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
void StunAttribute::setDataOffset(size_t offset)
|
||||
{
|
||||
mDataOffset = offset;
|
||||
}
|
||||
|
||||
size_t StunAttribute::dataOffset() const
|
||||
{
|
||||
return mDataOffset;
|
||||
}
|
||||
|
||||
//---------------------------- StunMessage -----------------------
|
||||
StunMessage::StunMessage()
|
||||
:mMagicCookie(0x2112A442)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
StunMessage::~StunMessage()
|
||||
{
|
||||
// Iterate map to delete all attributes
|
||||
for (AttributeMap::iterator ait=mAttrMap.begin(); ait != mAttrMap.end(); ++ait)
|
||||
delete ait->second;
|
||||
}
|
||||
|
||||
std::string StunMessage::comment()
|
||||
{
|
||||
return mComment;
|
||||
}
|
||||
|
||||
void StunMessage::setComment(std::string comment)
|
||||
{
|
||||
mComment = comment;
|
||||
}
|
||||
|
||||
|
||||
void StunMessage::setMessageType(Type type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
|
||||
StunMessage::Type StunMessage::messageType()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void StunMessage::setMessageClass(Class value)
|
||||
{
|
||||
mClass = value;
|
||||
}
|
||||
|
||||
StunMessage::Class StunMessage::messageClass()
|
||||
{
|
||||
return mClass;
|
||||
}
|
||||
|
||||
unsigned int StunMessage::magicCookie()
|
||||
{
|
||||
return mMagicCookie;
|
||||
}
|
||||
|
||||
bool StunMessage::isMagicCookieValid()
|
||||
{
|
||||
return mMagicCookie == 0x2112A442;
|
||||
}
|
||||
|
||||
void StunMessage::setTransactionId(TransactionID id)
|
||||
{
|
||||
mTransactionID = id;
|
||||
}
|
||||
|
||||
StunMessage::TransactionID StunMessage::transactionId()
|
||||
{
|
||||
return mTransactionID;
|
||||
}
|
||||
|
||||
static void EmbedAttrBuffer(StunAttribute& attr, BufferWriter& writer)
|
||||
{
|
||||
ByteBuffer attrBuffer; attrBuffer.resize(512);
|
||||
BufferWriter attrWriter(attrBuffer);
|
||||
attr.buildPacket(attrWriter);
|
||||
attrBuffer.resize(attrWriter.offset());
|
||||
|
||||
// Enqueue attribute type
|
||||
writer.writeUShort(attr.type());
|
||||
|
||||
// Enqueue length
|
||||
writer.writeUShort(attrBuffer.size());
|
||||
|
||||
// Save data offset in generated buffer
|
||||
attr.setDataOffset(writer.offset() + 2); // 2 is for first 16 bits written by bitstream
|
||||
|
||||
// Enqueue attribute's value
|
||||
if (attrBuffer.size() > 0)
|
||||
writer.writeBuffer(attrBuffer.data(), attrBuffer.size());
|
||||
|
||||
if (attrBuffer.size() & 0x3)
|
||||
{
|
||||
size_t paddingLength = 4 - (attrBuffer.size() & 0x3);
|
||||
char paddingBytes[4] = { 0, 0, 0, 0 };
|
||||
writer.writeBuffer(paddingBytes, paddingLength);
|
||||
}
|
||||
}
|
||||
|
||||
void StunMessage::buildPacket(ByteBuffer& buffer, const std::string& password)
|
||||
{
|
||||
// Make enough space for packet
|
||||
buffer.resize(1024);
|
||||
|
||||
// Write bits
|
||||
BitWriter bitstream(buffer);
|
||||
|
||||
bitstream.writeBit(0)
|
||||
.writeBit(0);
|
||||
|
||||
unsigned int msgtype = mType & 0xFFF;
|
||||
unsigned int msgclass = mClass & 0x3;
|
||||
|
||||
// Enqueue last 5 bits of mtype
|
||||
for (size_t i=0; i<5; i++)
|
||||
bitstream.writeBit(bit(msgtype, 11 - i));
|
||||
|
||||
// Enqueue last bit of msgclass
|
||||
bitstream.writeBit(bit(msgclass, 1));
|
||||
|
||||
// Enqueue 3 bits of msgtype
|
||||
for (size_t i=0; i<3; i++)
|
||||
bitstream.writeBit(bit(msgtype, 6 - i));
|
||||
|
||||
// Enqueue first bit of msgclass
|
||||
bitstream.writeBit(bit(msgclass, 0));
|
||||
|
||||
// Enqueue 4 bits of msgtype
|
||||
for (size_t i=0; i<4; i++)
|
||||
bitstream.writeBit(bit(msgtype, 3-i));
|
||||
|
||||
// Enqueue 2 bytes of length - now it is zero
|
||||
BufferWriter stream(buffer.mutableData() + bitstream.count() / 8);
|
||||
stream.writeUShort(0);
|
||||
|
||||
// Enqueue magic cookie value
|
||||
unsigned int cookie = htonl(mMagicCookie);
|
||||
stream.writeBuffer(&cookie, 4);
|
||||
|
||||
// Enqueue transaction ID
|
||||
//memset(mTransactionID.mValue, 0, sizeof(mTransactionID.mValue)); // For debugging only
|
||||
stream.writeBuffer(mTransactionID.mValue, 12);
|
||||
|
||||
// Iterate attributes
|
||||
AttributeMap::iterator attrIter;
|
||||
for (attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); ++attrIter)
|
||||
{
|
||||
StunAttribute& attr = *attrIter->second;
|
||||
|
||||
// Check if it is MessageIntegrity or Fingerprint - they comes last and skip them for now
|
||||
if (attr.type() == StunAttribute::MessageIntegrity || attr.type() == StunAttribute::Fingerprint)
|
||||
continue;
|
||||
|
||||
EmbedAttrBuffer(attr, stream);
|
||||
}
|
||||
|
||||
// Append MessageIntegrity attribute if exists
|
||||
AttributeMap::iterator miIter = mAttrMap.find(StunAttribute::MessageIntegrity);
|
||||
if ( miIter != mAttrMap.end())
|
||||
{
|
||||
EmbedAttrBuffer(*miIter->second, stream);
|
||||
}
|
||||
|
||||
int lengthWithoutFingerprint = stream.offset() + 2;
|
||||
|
||||
// Append Fingerprint attribute if exists
|
||||
AttributeMap::iterator fpIter = mAttrMap.find(StunAttribute::Fingerprint);
|
||||
if (fpIter != mAttrMap.end())
|
||||
{
|
||||
EmbedAttrBuffer(*fpIter->second, stream);
|
||||
}
|
||||
|
||||
// Check for message integrity attribute
|
||||
miIter = mAttrMap.find(StunAttribute::MessageIntegrity);
|
||||
if (miIter != mAttrMap.end())
|
||||
{
|
||||
// Update length in header
|
||||
*((unsigned short*)buffer.mutableData() + 1) = htons(lengthWithoutFingerprint - STUN_HEADER_SIZE);
|
||||
|
||||
// Prepare HMAC digest buffer
|
||||
unsigned char digest[HMAC_DIGEST_SIZE];
|
||||
|
||||
// Get data offset for output digest
|
||||
size_t dataOffset = miIter->second->dataOffset();
|
||||
|
||||
// Get digest
|
||||
hmacSha1Digest(buffer.data(), dataOffset - 4, digest, password.c_str(), password.length());
|
||||
|
||||
// Copy digest to proper place
|
||||
memcpy((unsigned char*)buffer.data() + dataOffset, digest, HMAC_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
// Resize resulting buffer
|
||||
buffer.resize(stream.offset() + 2);
|
||||
|
||||
// Put length in header
|
||||
*((unsigned short*)buffer.mutableData() + 1) = htons(buffer.size() - STUN_HEADER_SIZE);
|
||||
|
||||
// Check for fingerprint attribute
|
||||
fpIter = mAttrMap.find(StunAttribute::Fingerprint);
|
||||
if (fpIter != mAttrMap.end())
|
||||
{
|
||||
// Get data offset for fingeprint attribute
|
||||
size_t dataOffset = fpIter->second->dataOffset();
|
||||
|
||||
// Find CRC32
|
||||
CRC32 crc32;
|
||||
unsigned int crc = crc32.fullCrc((unsigned char*)buffer.data(), dataOffset - 4);
|
||||
|
||||
// Update attribute value with CRC32 value
|
||||
memcpy((unsigned char*)buffer.data() + dataOffset, &crc, 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "ICEStunAttributes.h"
|
||||
|
||||
bool StunMessage::parsePacket(ByteBuffer& buffer)
|
||||
{
|
||||
// Save incoming packet
|
||||
mPacket2Parse = buffer;
|
||||
|
||||
// Clear attribute list
|
||||
mAttrMap.clear();
|
||||
|
||||
BufferReader stream(buffer);
|
||||
|
||||
uint8_t firstByte = stream.readUChar();
|
||||
uint8_t secondByte = stream.readUChar();
|
||||
|
||||
if (firstByte & ~0x3F)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int c1 = firstByte & 0x1;
|
||||
int m11 = firstByte & 0x20 ? 1 : 0;
|
||||
int m10 = firstByte & 0x10 ? 1 : 0;
|
||||
int m9 = firstByte & 0x8 ? 1 : 0;
|
||||
int m8 = firstByte & 0x4 ? 1 : 0;
|
||||
int m7 = firstByte & 0x2 ? 1 : 0;
|
||||
|
||||
int m6 = secondByte & 0x80 ? 1 : 0;
|
||||
int m5 = secondByte & 0x40 ? 1 : 0;
|
||||
int m4 = secondByte & 0x20 ? 1 : 0;
|
||||
int c0 = secondByte & 0x10 ? 1 : 0;
|
||||
int m3 = secondByte & 0x8 ? 1 : 0;
|
||||
int m2 = secondByte & 0x4 ? 1 : 0;
|
||||
int m1 = secondByte & 0x2 ? 1 : 0;
|
||||
int m0 = secondByte & 0x1 ? 1 : 0;
|
||||
|
||||
mType = (StunMessage::Type)((m11 << 11) + (m10 << 10) + (m9 << 9) + (m8 << 8) + (m7 << 7) + (m6 << 6) + (m5 << 5) + (m4 << 4) + (m3 << 3) + (m2 << 2) + (m1 << 1) + m0);
|
||||
mClass = (StunMessage::Class) ((c1 << 1) + c0);
|
||||
|
||||
unsigned short length = stream.readUShort();
|
||||
if (length & 0x3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dequeue magic cookie
|
||||
mMagicCookie = stream.readUInt();
|
||||
if (!isMagicCookieValid())
|
||||
return false;
|
||||
|
||||
// Dequeue transaction id
|
||||
char id[12];
|
||||
stream.readBuffer(id, 12);
|
||||
|
||||
memcpy(mTransactionID.mValue, id, 12);
|
||||
|
||||
// Dequeue attributes
|
||||
while (stream.count() < buffer.size())
|
||||
{
|
||||
int attrType = stream.readUShort();
|
||||
StunAttribute* attr = NULL;
|
||||
switch (attrType)
|
||||
{
|
||||
case StunAttribute::Data:
|
||||
attr = new DataAttribute();
|
||||
break;
|
||||
|
||||
case StunAttribute::MappedAddress:
|
||||
attr = new MappedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::XorMappedAddress:
|
||||
attr = new XorMappedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::ErrorCode:
|
||||
attr = new ErrorCode();
|
||||
break;
|
||||
|
||||
case StunAttribute::AlternateServer:
|
||||
attr = new AlternateServer();
|
||||
break;
|
||||
|
||||
case StunAttribute::UnknownAttributes:
|
||||
attr = new UnknownAttributes();
|
||||
break;
|
||||
|
||||
case StunAttribute::Fingerprint:
|
||||
attr = new Fingerprint();
|
||||
break;
|
||||
|
||||
case StunAttribute::MessageIntegrity:
|
||||
attr = new MessageIntegrity();
|
||||
break;
|
||||
|
||||
case StunAttribute::Nonce:
|
||||
attr = new Nonce();
|
||||
break;
|
||||
|
||||
case StunAttribute::Realm:
|
||||
attr = new Realm();
|
||||
break;
|
||||
|
||||
case StunAttribute::Server:
|
||||
attr = new Server();
|
||||
break;
|
||||
|
||||
case StunAttribute::Username:
|
||||
attr = new Username();
|
||||
break;
|
||||
|
||||
case StunAttribute::ICEPriority:
|
||||
attr = new ICEPriority();
|
||||
break;
|
||||
|
||||
case StunAttribute::ControlledAttr:
|
||||
attr = new ControlledAttr();
|
||||
break;
|
||||
|
||||
case StunAttribute::ControllingAttr:
|
||||
attr = new ControllingAttr();
|
||||
break;
|
||||
|
||||
case StunAttribute::ICEUseCandidate:
|
||||
attr = new ICEUseCandidate();
|
||||
break;
|
||||
|
||||
case StunAttribute::XorRelayedAddress:
|
||||
attr = new XorRelayedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::XorPeerAddress:
|
||||
attr = new XorPeerAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::Lifetime:
|
||||
attr = new Lifetime();
|
||||
break;
|
||||
|
||||
case StunAttribute::RequestedTransport:
|
||||
attr = new RequestedTransport();
|
||||
break;
|
||||
|
||||
case StunAttribute::RequestedAddressFamily:
|
||||
attr = new RequestedAddressFamily();
|
||||
break;
|
||||
|
||||
default:
|
||||
attr = NULL;
|
||||
}
|
||||
|
||||
// Get attribute value length
|
||||
int attrLen = stream.readUShort();
|
||||
|
||||
unsigned int dataOffset = stream.count();
|
||||
|
||||
// Get attribute buffer
|
||||
ByteBuffer attrBuffer;
|
||||
if (attrLen > 0)
|
||||
{
|
||||
attrBuffer.resize(attrLen);
|
||||
stream.readBuffer(attrBuffer.mutableData(), attrLen);
|
||||
}
|
||||
|
||||
// Skip padding bytes
|
||||
if (attrLen & 0x3)
|
||||
{
|
||||
size_t paddingLength = 4 - (attrLen & 0x3);
|
||||
char paddingBytes[4];
|
||||
stream.readBuffer(paddingBytes, paddingLength);
|
||||
}
|
||||
|
||||
// Parse attribute value
|
||||
if (attr)
|
||||
{
|
||||
// Parse attribute
|
||||
BufferReader attrReader(attrBuffer);
|
||||
if (!attr->parsePacket(attrReader))
|
||||
return false;
|
||||
|
||||
// Set data offset
|
||||
attr->setDataOffset(dataOffset);
|
||||
|
||||
// Add attribute
|
||||
addAttribute(attr);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StunMessage::validatePacket(std::string key)
|
||||
{
|
||||
// Iterate attributes
|
||||
if (hasAttribute(StunAttribute::MessageIntegrity))
|
||||
{
|
||||
// Get HMAC digest
|
||||
MessageIntegrity& mi = dynamic_cast<MessageIntegrity&>(attribute(StunAttribute::MessageIntegrity));
|
||||
|
||||
unsigned char digest[HMAC_DIGEST_SIZE];
|
||||
|
||||
// Reset length to length of packet without Fingerprint
|
||||
unsigned short* lengthPtr = ((unsigned short*)mPacket2Parse.mutableData() + 1);
|
||||
|
||||
// Save old value - it is for backup purposes only. So there is no call to ntohs().
|
||||
unsigned short len = *lengthPtr;
|
||||
|
||||
// Set fake length including MessageIntegrity attribute but excluding any attributes behind of it and excluding STUN header size
|
||||
*lengthPtr = htons(mi.dataOffset() + HMAC_DIGEST_SIZE - STUN_HEADER_SIZE);
|
||||
|
||||
// Find HMAC-SHA1 again
|
||||
hmacSha1Digest(mPacket2Parse.data(), mi.dataOffset() - 4, digest, key.c_str(), key.size());
|
||||
|
||||
// And restore old value
|
||||
*lengthPtr = len;
|
||||
|
||||
if (memcmp(mi.value(), digest, HMAC_DIGEST_SIZE) != 0)
|
||||
{
|
||||
ICELogCritical(<< "Bad MessageIntegrity in STUN message");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (hasAttribute(StunAttribute::Fingerprint))
|
||||
{
|
||||
// Get fingerpring attribute
|
||||
Fingerprint& fp = dynamic_cast<Fingerprint&>(attribute(StunAttribute::Fingerprint));
|
||||
|
||||
// Find CRC32
|
||||
CRC32 crcObj;
|
||||
unsigned long crcValue = crcObj.fullCrc((const unsigned char*)mPacket2Parse.data(), fp.dataOffset() - 4);
|
||||
|
||||
// Compare with saved one
|
||||
if (crcValue != fp.crc32())
|
||||
{
|
||||
ICELogCritical(<< "Bad CRC32 value in STUN message");
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline char StunMessage::bit(unsigned int value, size_t index)
|
||||
{
|
||||
unsigned int mask = (1 << index);
|
||||
|
||||
return value & mask ? 1 : 0;
|
||||
}
|
||||
|
||||
inline void StunMessage::setBit(unsigned int& result, size_t index, char value)
|
||||
{
|
||||
unsigned int mask = (1 << index);
|
||||
if (value != 0)
|
||||
result |= mask;
|
||||
else
|
||||
result &= ~mask;
|
||||
}
|
||||
|
||||
void StunMessage::addAttribute(StunAttribute* attr)
|
||||
{
|
||||
assert(NULL != attr);
|
||||
mAttrMap.insert(std::pair<int, StunAttribute*>(attr->type(), attr));
|
||||
}
|
||||
|
||||
void StunMessage::setAttribute(StunAttribute *attr)
|
||||
{
|
||||
assert(NULL != attr);
|
||||
|
||||
AttributeMap::iterator attrIter = mAttrMap.find(attr->type());
|
||||
if (attrIter != mAttrMap.end())
|
||||
{
|
||||
delete attrIter->second;
|
||||
attrIter->second = attr;
|
||||
}
|
||||
else
|
||||
mAttrMap.insert(std::pair<int, StunAttribute*>(attr->type(), attr));
|
||||
}
|
||||
|
||||
bool StunMessage::hasAttribute(int attrType) const
|
||||
{
|
||||
return (mAttrMap.find(attrType) != mAttrMap.end());
|
||||
}
|
||||
|
||||
|
||||
StunAttribute& StunMessage::attribute(int attrType)
|
||||
{
|
||||
AttributeMap::iterator attrIter = mAttrMap.find(attrType);
|
||||
if (attrIter != mAttrMap.end())
|
||||
return *attrIter->second;
|
||||
|
||||
throw Exception(CANNOT_FIND_ATTRIBUTE, attrType);
|
||||
}
|
||||
|
||||
const StunAttribute&
|
||||
StunMessage::operator [] (int attribute) const
|
||||
{
|
||||
AttributeMap::iterator attrIter = mAttrMap.find(attribute);
|
||||
if (attrIter != mAttrMap.end())
|
||||
return *attrIter->second;
|
||||
|
||||
throw Exception(CANNOT_FIND_ATTRIBUTE, attribute);
|
||||
}
|
||||
|
||||
StunAttribute&
|
||||
StunMessage::operator[] (int attribute)
|
||||
{
|
||||
AttributeMap::iterator attrIter = mAttrMap.find(attribute);
|
||||
if (attrIter != mAttrMap.end())
|
||||
return *attrIter->second;
|
||||
|
||||
// Create attribute
|
||||
StunAttribute* attr = NULL;
|
||||
|
||||
switch (attribute)
|
||||
{
|
||||
case StunAttribute::MappedAddress:
|
||||
attr = new MappedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::XorMappedAddress:
|
||||
attr = new XorMappedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::ErrorCode:
|
||||
attr = new ErrorCode();
|
||||
break;
|
||||
|
||||
case StunAttribute::AlternateServer:
|
||||
attr = new AlternateServer();
|
||||
break;
|
||||
|
||||
case StunAttribute::UnknownAttributes:
|
||||
attr = new UnknownAttributes();
|
||||
break;
|
||||
|
||||
case StunAttribute::Fingerprint:
|
||||
attr = new Fingerprint();
|
||||
break;
|
||||
|
||||
case StunAttribute::MessageIntegrity:
|
||||
attr = new MessageIntegrity();
|
||||
break;
|
||||
|
||||
case StunAttribute::Nonce:
|
||||
attr = new Nonce();
|
||||
break;
|
||||
|
||||
case StunAttribute::Realm:
|
||||
attr = new Realm();
|
||||
break;
|
||||
|
||||
case StunAttribute::Server:
|
||||
attr = new Server();
|
||||
break;
|
||||
|
||||
case StunAttribute::Username:
|
||||
attr = new Username();
|
||||
break;
|
||||
|
||||
case StunAttribute::ICEPriority:
|
||||
attr = new ICEPriority();
|
||||
break;
|
||||
|
||||
case StunAttribute::ControlledAttr:
|
||||
attr = new ControlledAttr();
|
||||
break;
|
||||
|
||||
case StunAttribute::ControllingAttr:
|
||||
attr = new ControllingAttr();
|
||||
break;
|
||||
|
||||
case StunAttribute::ICEUseCandidate:
|
||||
attr = new ICEUseCandidate();
|
||||
break;
|
||||
|
||||
case StunAttribute::XorRelayedAddress:
|
||||
attr = new XorRelayedAddress();
|
||||
break;
|
||||
|
||||
case StunAttribute::Lifetime:
|
||||
attr = new Lifetime();
|
||||
break;
|
||||
|
||||
default:
|
||||
attr = NULL;
|
||||
}
|
||||
|
||||
if (!attr)
|
||||
throw Exception(UNKNOWN_ATTRIBUTE, attribute);
|
||||
|
||||
mAttrMap.insert(std::pair<int, StunAttribute*>(attribute, attr));
|
||||
return *attr;
|
||||
}
|
||||
|
||||
Username&
|
||||
StunMessage::usernameAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<Username&>(self[StunAttribute::Username]);
|
||||
}
|
||||
|
||||
Realm&
|
||||
StunMessage::realmAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<Realm&>(self[StunAttribute::Realm]);
|
||||
}
|
||||
|
||||
ErrorCode&
|
||||
StunMessage::errorCodeAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<ErrorCode&>(self[StunAttribute::ErrorCode]);
|
||||
}
|
||||
|
||||
Nonce&
|
||||
StunMessage::nonceAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<Nonce&>(self[StunAttribute::Nonce]);
|
||||
}
|
||||
|
||||
MessageIntegrity&
|
||||
StunMessage::messageIntegrityAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<MessageIntegrity&>(self[StunAttribute::MessageIntegrity]);
|
||||
}
|
||||
|
||||
MappedAddress&
|
||||
StunMessage::mappedAddressAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<MappedAddress&>(self[StunAttribute::MappedAddress]);
|
||||
}
|
||||
|
||||
XorMappedAddress&
|
||||
StunMessage::xorMappedAddressAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<XorMappedAddress&>(self[StunAttribute::XorMappedAddress]);
|
||||
}
|
||||
|
||||
ControlledAttr&
|
||||
StunMessage::iceControlledAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<ControlledAttr&>(self[StunAttribute::ControlledAttr]);
|
||||
}
|
||||
|
||||
ControllingAttr&
|
||||
StunMessage::iceControllingAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<ControllingAttr&>(self[StunAttribute::ControllingAttr]);
|
||||
}
|
||||
|
||||
ICEPriority&
|
||||
StunMessage::icePriorityAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<ICEPriority&>(self[StunAttribute::ICEPriority]);
|
||||
}
|
||||
|
||||
Lifetime&
|
||||
StunMessage::lifetimeAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<Lifetime&>(self[StunAttribute::Lifetime]);
|
||||
}
|
||||
|
||||
XorRelayedAddress&
|
||||
StunMessage::xorRelayedAddressAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
return dynamic_cast<XorRelayedAddress&>(self[StunAttribute::XorRelayedAddress]);
|
||||
}
|
||||
|
||||
ChannelNumber&
|
||||
StunMessage::channelNumberAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
if (!self.hasAttribute(StunAttribute::ChannelNumber))
|
||||
self.addAttribute(new ChannelNumber());
|
||||
|
||||
return dynamic_cast<ChannelNumber&>(self[StunAttribute::ChannelNumber]);
|
||||
}
|
||||
|
||||
XorPeerAddress&
|
||||
StunMessage::xorPeerAddressAttr()
|
||||
{
|
||||
StunMessage& self = *this;
|
||||
if (!self.hasAttribute(StunAttribute::XorPeerAddress))
|
||||
self.addAttribute(new XorPeerAddress());
|
||||
return dynamic_cast<XorPeerAddress&>(self[StunAttribute::XorPeerAddress]);
|
||||
}
|
||||
|
||||
class CompareAttributesByOffsetFunctor
|
||||
{
|
||||
public:
|
||||
bool operator () (const StunAttribute* attr1, const StunAttribute* attr2)
|
||||
{
|
||||
return attr1->dataOffset() < attr2->dataOffset();
|
||||
}
|
||||
};
|
||||
|
||||
void StunMessage::dump(std::ostream& output)
|
||||
{
|
||||
switch (messageClass())
|
||||
{
|
||||
case RequestClass: output << "Request"; break;
|
||||
case IndicationClass: output << "Indication"; break;
|
||||
case SuccessClass: output << "Success"; break;
|
||||
case ErrorClass: output << "Error"; break;
|
||||
default:
|
||||
output << "Invalid";
|
||||
break;
|
||||
}
|
||||
|
||||
output << " / ";
|
||||
switch (messageType())
|
||||
{
|
||||
case Binding: output << "Binding"; break;
|
||||
case Allocate: output << "Allocate"; break;
|
||||
case Refresh: output << "Refresh"; break;
|
||||
case Send: output << "Send"; break;
|
||||
case Data: output << "Data"; break;
|
||||
case CreatePermission: output << "CreatePermission"; break;
|
||||
case ChannelBind: output << "ChannelBind"; break;
|
||||
default:
|
||||
output << "Invalid";
|
||||
break;
|
||||
}
|
||||
|
||||
output << std::endl;
|
||||
|
||||
// Sort attribytes by data offset
|
||||
std::vector<StunAttribute*> attrList;
|
||||
for (AttributeMap::iterator attrIter = mAttrMap.begin(); attrIter != mAttrMap.end(); attrIter++)
|
||||
attrList.push_back(attrIter->second);
|
||||
|
||||
std::sort(attrList.begin(), attrList.end(), CompareAttributesByOffsetFunctor());
|
||||
|
||||
for (unsigned i=0; i<attrList.size(); i++)
|
||||
{
|
||||
output << "Offset " << attrList[i]->dataOffset() <<": ";
|
||||
attrList[i]->dump(output);
|
||||
output << std::endl;
|
||||
}
|
||||
}
|
||||
200
src/libs/ice/ICEStunMessage.h
Normal file
200
src/libs/ice/ICEStunMessage.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef __ICE_STUN_MESSAGE_H
|
||||
#define __ICE_STUN_MESSAGE_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "ICEByteBuffer.h"
|
||||
|
||||
namespace ice
|
||||
{
|
||||
class StunAttribute
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
NotExist = 0,
|
||||
MappedAddress = 1,
|
||||
Username = 6,
|
||||
MessageIntegrity = 8,
|
||||
ErrorCode = 9,
|
||||
UnknownAttributes = 10,
|
||||
Realm = 20,
|
||||
Nonce = 21,
|
||||
XorMappedAddress = 32,
|
||||
Server = 0x8022,
|
||||
AlternateServer = 0x8023,
|
||||
Fingerprint = 0x8028,
|
||||
|
||||
// TURN
|
||||
ChannelNumber = 0x0c,
|
||||
Lifetime = 0x0d,
|
||||
XorPeerAddress = 0x12,
|
||||
Data = 0x13,
|
||||
XorRelayedAddress = 0x16,
|
||||
RequestedAddressFamily = 0x17,
|
||||
RequestedTransport = 0x19,
|
||||
ReservedToken = 0x22,
|
||||
|
||||
// ICE
|
||||
ControlledAttr = 0x8029,
|
||||
ControllingAttr = 0x802a,
|
||||
ICEPriority = 0x0024,
|
||||
ICEUseCandidate = 0x0025
|
||||
};
|
||||
|
||||
StunAttribute();
|
||||
virtual ~StunAttribute();
|
||||
|
||||
virtual int type() const = 0;
|
||||
virtual void buildPacket(BufferWriter& writer) = 0;
|
||||
virtual bool parsePacket(BufferReader& reader) = 0;
|
||||
|
||||
void setDataOffset(size_t offset);
|
||||
size_t dataOffset() const;
|
||||
virtual void dump(std::ostream& output) = 0;
|
||||
|
||||
protected:
|
||||
int mType;
|
||||
int mLength;
|
||||
size_t mDataOffset;
|
||||
};
|
||||
|
||||
|
||||
class Username;
|
||||
class Realm;
|
||||
class Nonce;
|
||||
class ErrorCode;
|
||||
class MessageIntegrity;
|
||||
class MappedAddress;
|
||||
class XorMappedAddress;
|
||||
class ControlledAttr;
|
||||
class ControllingAttr;
|
||||
class ICEPriority;
|
||||
class Lifetime;
|
||||
class XorRelayedAddress;
|
||||
class ChannelNumber;
|
||||
class XorPeerAddress;
|
||||
|
||||
class StunMessage
|
||||
{
|
||||
public:
|
||||
struct TransactionID
|
||||
{
|
||||
unsigned char mValue[12];
|
||||
|
||||
bool operator == (const TransactionID& rhs);
|
||||
bool operator != (const TransactionID& rhs);
|
||||
|
||||
TransactionID();
|
||||
std::string toStdString();
|
||||
|
||||
static TransactionID generateNew();
|
||||
};
|
||||
|
||||
enum Class
|
||||
{
|
||||
RequestClass = 0, //0b00,
|
||||
IndicationClass = 1, //0b01,
|
||||
SuccessClass = 2, //0b10,
|
||||
ErrorClass = 3 //0b11
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Binding = 1,
|
||||
Allocate = 3,
|
||||
Refresh = 4,
|
||||
Send = 6,
|
||||
Data = 7,
|
||||
CreatePermission = 8,
|
||||
ChannelBind = 9
|
||||
};
|
||||
|
||||
StunMessage();
|
||||
virtual ~StunMessage();
|
||||
|
||||
std::string comment();
|
||||
void setComment(std::string comment);
|
||||
|
||||
void setMessageType(Type type);
|
||||
Type messageType();
|
||||
|
||||
void setMessageClass(Class value);
|
||||
Class messageClass();
|
||||
|
||||
unsigned int magicCookie();
|
||||
bool isMagicCookieValid();
|
||||
|
||||
void setTransactionId(TransactionID id);
|
||||
TransactionID transactionId();
|
||||
|
||||
// Builds STUN packet using specified password (if MessageIntegrity attribute is add before)
|
||||
void buildPacket(ByteBuffer& buffer, const std::string& password);
|
||||
|
||||
// Parses STUN packet but do not validates it
|
||||
bool parsePacket(ByteBuffer& buffer);
|
||||
|
||||
// Validate parsed packet. Must be called right after ParsePacket() method.
|
||||
// Returns true if validated ok, false otherwise.
|
||||
bool validatePacket(std::string key);
|
||||
|
||||
// Adds attribute to STUN message. If attribute of the same type exists - new one will be add.
|
||||
void addAttribute(StunAttribute* attr);
|
||||
|
||||
// Sets attribute to STUN message. If attribute of the same type exists - it will be overwritten.
|
||||
void setAttribute(StunAttribute* attr);
|
||||
|
||||
// Checks if there is specified attribute
|
||||
bool hasAttribute(int attrType) const;
|
||||
|
||||
// Gets reference to attribute object
|
||||
StunAttribute& attribute(int attrType);
|
||||
|
||||
const StunAttribute& operator [] (int attribute) const;
|
||||
StunAttribute& operator[] (int attribute);
|
||||
|
||||
Username& usernameAttr();
|
||||
Realm& realmAttr();
|
||||
ErrorCode& errorCodeAttr();
|
||||
Nonce& nonceAttr();
|
||||
MessageIntegrity& messageIntegrityAttr();
|
||||
MappedAddress& mappedAddressAttr();
|
||||
XorMappedAddress& xorMappedAddressAttr();
|
||||
ControlledAttr& iceControlledAttr();
|
||||
ControllingAttr& iceControllingAttr();
|
||||
ICEPriority& icePriorityAttr();
|
||||
Lifetime& lifetimeAttr();
|
||||
XorRelayedAddress& xorRelayedAddressAttr();
|
||||
ChannelNumber& channelNumberAttr();
|
||||
XorPeerAddress& xorPeerAddressAttr();
|
||||
|
||||
void dump(std::ostream& output);
|
||||
|
||||
protected:
|
||||
unsigned int mMagicCookie; // STUN magic cookie predefined value
|
||||
Type mType; // Type of STUN message
|
||||
Class mClass; // Class of STUN message
|
||||
TransactionID mTransactionID; // Transaction ID of STUN message
|
||||
|
||||
typedef std::multimap<int, StunAttribute*> AttributeMap;
|
||||
|
||||
mutable AttributeMap mAttrMap; // Attribute list
|
||||
ByteBuffer mPacket2Parse; // Incoming packet
|
||||
ByteBuffer mPacket2Send; // Outgoing packet
|
||||
|
||||
std::string mComment; // Comment for this message
|
||||
|
||||
//Helper method to get bit with specified index from 'value' parameter.
|
||||
inline char bit(unsigned int value, size_t index);
|
||||
|
||||
//Helper method to set bit in specified 'result' parameter
|
||||
inline void setBit(unsigned int& result, size_t index, char value);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
493
src/libs/ice/ICEStunTransaction.cpp
Normal file
493
src/libs/ice/ICEStunTransaction.cpp
Normal file
@@ -0,0 +1,493 @@
|
||||
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ICEPlatform.h"
|
||||
#include "ICEStunTransaction.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICELog.h"
|
||||
#include "ICEError.h"
|
||||
#include "ICEAction.h"
|
||||
#include "ICETime.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
|
||||
using namespace ice;
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
const char* Transaction::stateToString(State state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case Running: return "Running";
|
||||
case Failed: return "Failed";
|
||||
case Success: return "Success";
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
Transaction::Transaction()
|
||||
{
|
||||
mTransportType = IPv4;
|
||||
|
||||
// There is no default ICE stack
|
||||
mStackID = 0;
|
||||
|
||||
// There is no default logger
|
||||
mLog = NULL;
|
||||
|
||||
// Packet is not composed in constructor
|
||||
mComposed = false;
|
||||
|
||||
// Initial state of transaction - "Running"
|
||||
mState = Transaction::Running;
|
||||
|
||||
// Reset user data
|
||||
mTag = 0;
|
||||
|
||||
// Do not use message integrity attribute by default
|
||||
mMessageIntegrity = false;
|
||||
|
||||
// Do not use fingerprint attribute by default
|
||||
mFingerprint = false;
|
||||
|
||||
// Do not use long term credentials by default
|
||||
mLongTerm = false;
|
||||
|
||||
// Do not use short term credentials by default
|
||||
mShortTerm = false;
|
||||
|
||||
// Create new transaction ID
|
||||
generateId();
|
||||
|
||||
// CONTROLLING attribute is not used by default
|
||||
mEnableControlling = false;
|
||||
|
||||
// CONTROLLED attribute is not used by default
|
||||
mEnableControlled = false;
|
||||
|
||||
// PRIORITY attribute is not used by default
|
||||
mEnablePriority = false;
|
||||
mPriority = 0;
|
||||
|
||||
// Transaction is not cancelled
|
||||
mCancelled = false;
|
||||
|
||||
// Transaction is not relayed by default
|
||||
mRelayed = false;
|
||||
|
||||
// Component port is not set by default
|
||||
mComponent = 0;
|
||||
|
||||
mKeepalive = false;
|
||||
mInterval = 0;
|
||||
mUserObject = NULL;
|
||||
mType = None;
|
||||
mRemoved = false;
|
||||
mFailoverId = 0;
|
||||
}
|
||||
|
||||
Transaction::~Transaction()
|
||||
{
|
||||
}
|
||||
|
||||
void Transaction::generateId()
|
||||
{
|
||||
for (size_t i=0; i<12; i++)
|
||||
mTransactionID.mValue[i] = rand();
|
||||
}
|
||||
void Transaction::setStackId(int id)
|
||||
{
|
||||
mStackID = id;
|
||||
}
|
||||
|
||||
int Transaction::stackId()
|
||||
{
|
||||
return mStackID;
|
||||
}
|
||||
|
||||
void Transaction::setTransportType(int _type)
|
||||
{
|
||||
assert(_type == IPv4 || _type == IPv6);
|
||||
mTransportType = _type;
|
||||
}
|
||||
|
||||
int Transaction::transportType()
|
||||
{
|
||||
return mTransportType;
|
||||
}
|
||||
|
||||
std::string Transaction::toStdString()
|
||||
{
|
||||
std::ostringstream output;
|
||||
output << "State: " << Transaction::stateToString(mState) << ", ";
|
||||
output << "Transport: " << (mTransportType == IPv4 ? "IPv4" : "IPv6") << ", ";
|
||||
output << (mCancelled ? "Cancelled, " : "");
|
||||
output << "Destination: " << mDestination.toStdString().c_str() << ", ";
|
||||
output << "Comment: " << mComment.c_str();
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
void Transaction::setTag(unsigned int tag)
|
||||
{
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
unsigned Transaction::tag()
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
void Transaction::enqueueMessage(ice::StunMessage& msg)
|
||||
{
|
||||
// Clear outgoing buffer
|
||||
mOutgoingData.clear();
|
||||
|
||||
// Check if message should be secured by message integrity
|
||||
std::string password = mPassword;
|
||||
if (true == mMessageIntegrity)
|
||||
{
|
||||
// Ensure credentials are enabled
|
||||
assert(mLongTerm || mShortTerm);
|
||||
|
||||
// Create username attribute
|
||||
Username* attr = new Username();
|
||||
|
||||
// Set username value
|
||||
if (mLongTerm || mShortTerm)
|
||||
attr->setValue(mUsername);
|
||||
|
||||
// Add username attribute itself
|
||||
msg.setAttribute(attr);
|
||||
|
||||
// Add message integrity attribute
|
||||
msg.setAttribute(new MessageIntegrity());
|
||||
}
|
||||
|
||||
if (mFingerprint)
|
||||
msg.setAttribute(new Fingerprint());
|
||||
|
||||
// Add ICE-CONTROLLED attribute if needed
|
||||
if (mEnableControlled)
|
||||
{
|
||||
assert(mTieBreaker.length() == 8);
|
||||
|
||||
ControlledAttr* attr = new ControlledAttr();
|
||||
attr->setTieBreaker(mTieBreaker);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
// Add ICE-CONTROLLING attribute if needed
|
||||
if (mEnableControlling)
|
||||
{
|
||||
assert(mTieBreaker.length() == 8);
|
||||
|
||||
ControllingAttr* attr = new ControllingAttr();
|
||||
attr->setTieBreaker(mTieBreaker);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
// Add ICE-PRIORITY attribute if needed
|
||||
if (mEnablePriority)
|
||||
{
|
||||
ICEPriority* attr = new ICEPriority();
|
||||
attr->setPriority(mPriority);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
msg.buildPacket(mOutgoingData, password);
|
||||
}
|
||||
|
||||
ByteBuffer* Transaction::generateData(bool force)
|
||||
{
|
||||
if (mCancelled)
|
||||
return NULL;
|
||||
|
||||
// Check if there is any outgoing data
|
||||
if (mOutgoingData.size() == 0)
|
||||
return NULL;
|
||||
|
||||
// Check if there is timeout for next transmission attempt
|
||||
if (mRTOTimer.isTimeout() && !force)
|
||||
{
|
||||
ICELogCritical(<< "Transaction " << mComment << " timeouted.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if transmission was made too much times - client should not send billions of packets.
|
||||
if (mRTOTimer.isAttemptLimitReached() && !force)
|
||||
return NULL;
|
||||
|
||||
// Check if time to retransmit now
|
||||
if (mRTOTimer.isTimeToRetransmit() || force)
|
||||
{
|
||||
mRTOTimer.attemptMade();
|
||||
|
||||
// Copy outgoing data
|
||||
ByteBuffer* buffer = new ByteBuffer(mOutgoingData);
|
||||
|
||||
buffer->setComment(mComment);
|
||||
buffer->setRemoteAddress(destination());
|
||||
buffer->setComponent(component());
|
||||
buffer->setComment(comment());
|
||||
buffer->setTag(this);
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Transaction::restart()
|
||||
{
|
||||
mComposed = false;
|
||||
mState = Transaction::Running;
|
||||
mOutgoingData.clear();
|
||||
mRemoved = false;
|
||||
mRTOTimer.stop();
|
||||
mRTOTimer.start();
|
||||
}
|
||||
|
||||
bool Transaction::isTimeout()
|
||||
{
|
||||
if (mRTOTimer.isTimeout())
|
||||
{
|
||||
mState = Failed;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Transaction::addMessageIntegrity(bool enable)
|
||||
{
|
||||
mMessageIntegrity = enable;
|
||||
}
|
||||
|
||||
void Transaction::addFingerprint(bool enable)
|
||||
{
|
||||
mFingerprint = enable;
|
||||
}
|
||||
|
||||
void Transaction::addShortTermCredentials(bool enable)
|
||||
{
|
||||
this->mShortTerm = enable;
|
||||
}
|
||||
|
||||
void Transaction::addLongTermCredentials(bool enable)
|
||||
{
|
||||
this->mLongTerm = enable;
|
||||
}
|
||||
|
||||
void Transaction::addControllingRole(const std::string& tieBreaker)
|
||||
{
|
||||
mEnableControlling = true;
|
||||
mTieBreaker = tieBreaker;
|
||||
}
|
||||
|
||||
void Transaction::addControlledRole(const std::string& tieBreaker)
|
||||
{
|
||||
mEnableControlled = true;
|
||||
mTieBreaker = tieBreaker;
|
||||
}
|
||||
|
||||
void Transaction::addPriority(unsigned int priority)
|
||||
{
|
||||
mEnablePriority = true;
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
unsigned int Transaction::priorityValue()
|
||||
{
|
||||
if (!mEnablePriority)
|
||||
throw Exception(NO_PRIORITY_ATTRIBUTE);
|
||||
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
|
||||
void Transaction::setUsername(const std::string& username)
|
||||
{
|
||||
mUsername = username;
|
||||
}
|
||||
|
||||
void Transaction::setPassword(const std::string& password)
|
||||
{
|
||||
mPassword = password;
|
||||
}
|
||||
|
||||
Transaction::State Transaction::state() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Transaction::setAction(PAction action)
|
||||
{
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
PAction Transaction::action() const
|
||||
{
|
||||
return mAction;
|
||||
}
|
||||
|
||||
void Transaction::cancel()
|
||||
{
|
||||
mCancelled = true;
|
||||
}
|
||||
|
||||
bool Transaction::isCancelled() const
|
||||
{
|
||||
return mCancelled;
|
||||
}
|
||||
|
||||
void Transaction::setComment(const std::string& comment)
|
||||
{
|
||||
mComment = comment;
|
||||
}
|
||||
|
||||
std::string Transaction::comment() const
|
||||
{
|
||||
return mComment;
|
||||
}
|
||||
|
||||
void Transaction::setDestination(const NetworkAddress& addr)
|
||||
{
|
||||
mDestination = addr;
|
||||
}
|
||||
|
||||
void Transaction::setComponent(int component)
|
||||
{
|
||||
mComponent = component;
|
||||
}
|
||||
|
||||
int Transaction::component()
|
||||
{
|
||||
return mComponent;
|
||||
}
|
||||
|
||||
NetworkAddress& Transaction::destination()
|
||||
{
|
||||
return mDestination;
|
||||
}
|
||||
|
||||
bool Transaction::relayed()
|
||||
{
|
||||
return mRelayed;
|
||||
}
|
||||
|
||||
void Transaction::setRelayed(bool relayed)
|
||||
{
|
||||
mRelayed = relayed;
|
||||
}
|
||||
|
||||
bool Transaction::keepalive()
|
||||
{
|
||||
return mKeepalive;
|
||||
}
|
||||
|
||||
void Transaction::setKeepalive(bool keepalive)
|
||||
{
|
||||
mKeepalive = keepalive;
|
||||
}
|
||||
|
||||
unsigned Transaction::interval()
|
||||
{
|
||||
return mInterval;
|
||||
}
|
||||
|
||||
void Transaction::setInterval(unsigned interval)
|
||||
{
|
||||
mInterval = interval;
|
||||
}
|
||||
|
||||
void* Transaction::userObject()
|
||||
{
|
||||
return mUserObject;
|
||||
}
|
||||
|
||||
void Transaction::setUserObject(void* obj)
|
||||
{
|
||||
mUserObject = obj;
|
||||
}
|
||||
|
||||
Transaction::Type Transaction::type()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void Transaction::setType(Transaction::Type t)
|
||||
{
|
||||
mType = t;
|
||||
}
|
||||
|
||||
bool Transaction::removed()
|
||||
{
|
||||
return mRemoved;
|
||||
}
|
||||
|
||||
void Transaction::setRemoved(bool removed)
|
||||
{
|
||||
if (!mRemoved && removed)
|
||||
ICELogDebug(<< "Transaction " << mComment << " removed.");
|
||||
|
||||
mRemoved = removed;
|
||||
}
|
||||
|
||||
unsigned Transaction::timestamp()
|
||||
{
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
void Transaction::setTimestamp(unsigned timestamp)
|
||||
{
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
StunMessage::TransactionID Transaction::transactionId()
|
||||
{
|
||||
return mTransactionID;
|
||||
}
|
||||
|
||||
bool Transaction::hasToRunNow()
|
||||
{
|
||||
if (!mKeepalive)
|
||||
return true;
|
||||
|
||||
//bool cf = (mComment == "ClientRefresh");
|
||||
|
||||
unsigned current = ICETimeHelper::timestamp();
|
||||
/*if (cf)
|
||||
{
|
||||
ICELogDebug(<< "ClientRefresh interval: " << ICETimeHelper::findDelta(timestamp(), current) << ", interval " << interval()*1000);
|
||||
}*/
|
||||
|
||||
if (timestamp())
|
||||
{
|
||||
if (ICETimeHelper::findDelta(timestamp(), current) < interval() * 1000)
|
||||
return false;
|
||||
|
||||
setTimestamp(current);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimestamp(current);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Transaction::setFailoverId(int failoverId)
|
||||
{
|
||||
mFailoverId = failoverId;
|
||||
}
|
||||
|
||||
int Transaction::failoverId() const
|
||||
{
|
||||
return mFailoverId;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user