From 631fffee8a28b1bec5ed1f1d26a20e0135967f99 Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Mon, 17 Aug 2015 01:56:35 +0200 Subject: - --- tinyBFCP/AStyle.sh | 1 + tinyBFCP/Makefile.am | 22 + tinyBFCP/include/tinybfcp.h | 26 + tinyBFCP/include/tinybfcp/tbfcp_attr.h | 98 +++ tinyBFCP/include/tinybfcp/tbfcp_pkt.h | 107 +++ tinyBFCP/include/tinybfcp/tbfcp_session.h | 72 ++ tinyBFCP/include/tinybfcp/tbfcp_types.h | 207 ++++++ tinyBFCP/include/tinybfcp/tbfcp_utils.h | 43 ++ tinyBFCP/include/tinybfcp_config.h | 80 +++ tinyBFCP/src/tbfcp_attr.c | 674 +++++++++++++++++++ tinyBFCP/src/tbfcp_pkt.c | 585 ++++++++++++++++ tinyBFCP/src/tbfcp_session.c | 1041 +++++++++++++++++++++++++++++ tinyBFCP/src/tbfcp_utils.c | 191 ++++++ tinyBFCP/test/stdafx.c | 22 + tinyBFCP/test/stdafx.h | 31 + tinyBFCP/test/targetver.h | 36 + tinyBFCP/test/test.c | 82 +++ tinyBFCP/test/test.vcproj | 221 ++++++ tinyBFCP/test/test_parser.h | 215 ++++++ tinyBFCP/test/test_session.h | 62 ++ tinyBFCP/tinyBFCP.pc.in | 15 + tinyBFCP/tinyBFCP.sln | 68 ++ tinyBFCP/tinyBFCP.vcproj | 245 +++++++ tinyBFCP/version.rc | 102 +++ 24 files changed, 4246 insertions(+) create mode 100644 tinyBFCP/AStyle.sh create mode 100644 tinyBFCP/Makefile.am create mode 100644 tinyBFCP/include/tinybfcp.h create mode 100644 tinyBFCP/include/tinybfcp/tbfcp_attr.h create mode 100644 tinyBFCP/include/tinybfcp/tbfcp_pkt.h create mode 100644 tinyBFCP/include/tinybfcp/tbfcp_session.h create mode 100644 tinyBFCP/include/tinybfcp/tbfcp_types.h create mode 100644 tinyBFCP/include/tinybfcp/tbfcp_utils.h create mode 100644 tinyBFCP/include/tinybfcp_config.h create mode 100644 tinyBFCP/src/tbfcp_attr.c create mode 100644 tinyBFCP/src/tbfcp_pkt.c create mode 100644 tinyBFCP/src/tbfcp_session.c create mode 100644 tinyBFCP/src/tbfcp_utils.c create mode 100644 tinyBFCP/test/stdafx.c create mode 100644 tinyBFCP/test/stdafx.h create mode 100644 tinyBFCP/test/targetver.h create mode 100644 tinyBFCP/test/test.c create mode 100644 tinyBFCP/test/test.vcproj create mode 100644 tinyBFCP/test/test_parser.h create mode 100644 tinyBFCP/test/test_session.h create mode 100644 tinyBFCP/tinyBFCP.pc.in create mode 100644 tinyBFCP/tinyBFCP.sln create mode 100644 tinyBFCP/tinyBFCP.vcproj create mode 100644 tinyBFCP/version.rc (limited to 'tinyBFCP') diff --git a/tinyBFCP/AStyle.sh b/tinyBFCP/AStyle.sh new file mode 100644 index 0000000..5bf8859 --- /dev/null +++ b/tinyBFCP/AStyle.sh @@ -0,0 +1 @@ +../thirdparties/win32/bin/AStyle.exe --style=k/r --lineend=linux --mode=c --add-brackets --break-closing-brackets --recursive "*.c" "*.h" \ No newline at end of file diff --git a/tinyBFCP/Makefile.am b/tinyBFCP/Makefile.am new file mode 100644 index 0000000..c7a6779 --- /dev/null +++ b/tinyBFCP/Makefile.am @@ -0,0 +1,22 @@ +lib_LTLIBRARIES = libtinyBFCP.la +libtinyBFCP_la_LIBADD = ../tinySAK/libtinySAK.la ../tinyNET/libtinyNET.la +libtinyBFCP_la_CPPFLAGS = -Iinclude -I../tinySAK/src -I../tinyNET/src + +libtinyBFCP_la_SOURCES = \ + src/tbfcp_attr.c\ + src/tbfcp_pkt.c\ + src/tbfcp_session.c\ + src/tbfcp_utils.c + +libtinyBFCP_la_LDFLAGS = $LDFLAGS -no-undefined +if TARGET_OS_IS_ANDROID +libtinyBFCP_la_LDFLAGS += -static +endif + +_includedir = $(includedir)/tinybfcp +_include_HEADERS = include/*.h +__includedir = $(includedir)/tinybfcp/tinybfcp +__include_HEADERS = include/tinybfcp/*.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = tinyBFCP.pc diff --git a/tinyBFCP/include/tinybfcp.h b/tinyBFCP/include/tinybfcp.h new file mode 100644 index 0000000..e6d02a8 --- /dev/null +++ b/tinyBFCP/include/tinybfcp.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_TINYBFCP_H +#define TBFCP_TINYBFCP_H + +#include "tinybfcp/tbfcp_pkt.h" +#include "tinybfcp/tbfcp_attr.h" +#include "tinybfcp/tbfcp_session.h" + +#endif /* TBFCP_TINYBFCP_H */ diff --git a/tinyBFCP/include/tinybfcp/tbfcp_attr.h b/tinyBFCP/include/tinybfcp/tbfcp_attr.h new file mode 100644 index 0000000..c83f805 --- /dev/null +++ b/tinyBFCP/include/tinybfcp/tbfcp_attr.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_ATTR_H +#define TBFCP_ATTR_H + +#include "tinybfcp_config.h" +#include "tinybfcp/tbfcp_types.h" + +#include "tsk_object.h" +#include "tsk_list.h" + +TBFCP_BEGIN_DECLS + +#if !defined(TBFCP_ATTR_HDR_SIZE_IN_OCTETS) +# define TBFCP_ATTR_HDR_SIZE_IN_OCTETS 2 /* 2 Octets: Type(7bits),M(1bit),Length(8bits) */ +#endif /* TBFCP_ATTR_HDR_SIZE_IN_OCTETS */ + +// RFC4582 - 5.2. Attribute Format +typedef struct tbfcp_attr_hdr_xs { + enum tbfcp_attribute_type_e type; // 7bits + unsigned M:1; // Mandatory // 1bit + uint8_t length; // 8bits excluding any padding defined for specific attributes +} tbfcp_attr_hdr_xt; + +typedef struct tbfcp_attr_s { + TSK_DECLARE_OBJECT; + struct tbfcp_attr_s* pc_base; + struct tbfcp_attr_hdr_xs hdr; + enum tbfcp_attribute_format_e format; +} tbfcp_attr_t; +#define TBFCP_DECLARE_ATTR struct tbfcp_attr_s __base__ +#define TBFCP_ATTR(p_self) ((struct tbfcp_attr_s*)(p_self)) +typedef tsk_list_t tbfcp_attrs_L_t; +TINYBFCP_API int tbfcp_attr_get_size_in_octetunits_without_padding(const struct tbfcp_attr_s* pc_self, tsk_size_t* p_size); +TINYBFCP_API int tbfcp_attr_get_size_in_octetunits_with_padding(const struct tbfcp_attr_s* pc_self, tsk_size_t* p_size); +TINYBFCP_API int tbfcp_attr_write_without_padding(const struct tbfcp_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYBFCP_API int tbfcp_attr_write_with_padding(const struct tbfcp_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYBFCP_API int tbfcp_attr_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, struct tbfcp_attr_s** pp_attr); + +typedef struct tbfcp_attr_unsigned16_s { + TBFCP_DECLARE_ATTR; + uint16_t Unsigned16; +} tbfcp_attr_unsigned16_t; +#define TBFCP_ATTR_UNSIGNED16(p_self) ((struct tbfcp_attr_unsigned16_s*)(p_self)) +TINYBFCP_API int tbfcp_attr_unsigned16_create(enum tbfcp_attribute_type_e type, unsigned M, uint16_t Unsigned16, struct tbfcp_attr_unsigned16_s** pp_self); + +typedef struct tbfcp_attr_octetstring16_s { + TBFCP_DECLARE_ATTR; + uint8_t OctetString16[2]; +} tbfcp_attr_octetstring16_t; +#define TBFCP_ATTR_OCTETSTRING16(p_self) ((struct tbfcp_attr_octetstring16_s*)(p_self)) +TINYBFCP_API int tbfcp_attr_octetstring16_create(enum tbfcp_attribute_type_e type, unsigned M, uint8_t OctetString16[2], struct tbfcp_attr_octetstring16_s** pp_self); + +typedef struct tbfcp_attr_octetstring_s { + TBFCP_DECLARE_ATTR; + uint8_t *OctetString; + uint8_t OctetStringLength; // Length in octet excluding any paddding +} tbfcp_attr_octetstring_t; +#define TBFCP_ATTR_OCTETSTRING(p_self) ((struct tbfcp_attr_octetstring_s*)(p_self)) +TINYBFCP_API int tbfcp_attr_octetstring_create(enum tbfcp_attribute_type_e type, unsigned M, const uint8_t *OctetString, uint8_t OctetStringLength, struct tbfcp_attr_octetstring_s** pp_self); + +typedef struct tbfcp_attr_grouped_s { + TBFCP_DECLARE_ATTR; + union { + uint16_t BeneficiaryID; // 5.2.14. BENEFICIARY-INFORMATION + uint16_t FloorRequestID; // 5.2.15. FLOOR-REQUEST-INFORMATION && 5.2.18. OVERALL-REQUEST-STATUS + uint16_t RequestedbyID; // 5.2.16. REQUESTED-BY-INFORMATION + uint16_t FloorID; // 5.2.17. FLOOR-REQUEST-STATUS + } extra_hdr; + uint8_t extra_hdr_size_in_octets; + tbfcp_attrs_L_t *p_list_attrs; +} tbfcp_attr_grouped_t; +#define TBFCP_ATTR_GROUPED(p_self) ((struct tbfcp_attr_grouped_s*)(p_self)) +TINYBFCP_API int tbfcp_attr_grouped_create(enum tbfcp_attribute_type_e type, unsigned M, struct tbfcp_attr_grouped_s** pp_self); +TINYBFCP_API int tbfcp_attr_grouped_create_u16(enum tbfcp_attribute_type_e type, unsigned M, uint16_t extra_hdr_u16_val, struct tbfcp_attr_grouped_s** pp_self); +TINYBFCP_API int tbfcp_attr_grouped_add_attr(struct tbfcp_attr_grouped_s* p_self, struct tbfcp_attr_s** p_attr); +TINYBFCP_API int tbfcp_attr_grouped_find_at(const struct tbfcp_attr_grouped_s* pc_self, enum tbfcp_attribute_format_e e_format, tsk_size_t u_index, const struct tbfcp_attr_s** ppc_attr); + +TBFCP_END_DECLS + +#endif /* TBFCP_ATTR_H */ + diff --git a/tinyBFCP/include/tinybfcp/tbfcp_pkt.h b/tinyBFCP/include/tinybfcp/tbfcp_pkt.h new file mode 100644 index 0000000..92353cc --- /dev/null +++ b/tinyBFCP/include/tinybfcp/tbfcp_pkt.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_PKT_H +#define TBFCP_PKT_H + +#include "tinybfcp_config.h" +#include "tinybfcp/tbfcp_types.h" +#include "tinybfcp/tbfcp_attr.h" + +#include "tsk_object.h" +#include "tsk_list.h" + +TBFCP_BEGIN_DECLS + +#if !defined(TBFCP_PKT_HDR_SIZE_IN_OCTETS) +# define TBFCP_PKT_HDR_SIZE_IN_OCTETS 12 +#endif /* TBFCP_PKT_HDR_SIZE_IN_OCTETS */ + +typedef tsk_list_t tbfcp_pkts_L_t; +typedef struct tbfcp_pkt_s { + TSK_DECLARE_OBJECT; + + struct { + // rfc4582 - 5.1. COMMON-HEADER Format + unsigned ver:3; + unsigned reserved:5; + enum tbfcp_primitive_e primitive; // 8bits + uint16_t pay_len; // 16bits: the length of the message in 4-octet units, excluding the common header + uint32_t conf_id; + uint16_t transac_id; + uint16_t user_id; + } hdr; + int (*f_add_attr)(struct tbfcp_pkt_s* p_self, struct tbfcp_attr_s** pp_attr); + tbfcp_attrs_L_t *p_list_attrs; +} +tbfcp_pkt_t; +#define TBFCP_DECLARE_PKT struct tbfcp_pkt_s __base__ +#define TBFCP_PKT(p_self) ((struct tbfcp_pkt_s*)(p_self)) +TINYBFCP_API int tbfcp_pkt_add_attr(struct tbfcp_pkt_s* p_self, struct tbfcp_attr_s** pp_attr); +TINYBFCP_API int tbfcp_pkt_create_empty(enum tbfcp_primitive_e primitive, struct tbfcp_pkt_s** pp_self); +TINYBFCP_API int tbfcp_pkt_create(enum tbfcp_primitive_e primitive, uint32_t conf_id, uint16_t transac_id, uint16_t user_id, struct tbfcp_pkt_s** pp_self); +TINYBFCP_API int tbfcp_pkt_get_size_in_octetunits_without_padding(const struct tbfcp_pkt_s* pc_self, tsk_size_t* p_size); +TINYBFCP_API int tbfcp_pkt_get_size_in_octetunits_with_padding(const struct tbfcp_pkt_s* pc_self, tsk_size_t* p_size); +TINYBFCP_API int tbfcp_pkt_write_with_padding(const struct tbfcp_pkt_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYBFCP_API int tbfcp_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete); +TINYBFCP_API int tbfcp_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, struct tbfcp_pkt_s** pp_pkt); +TINYBFCP_API int tbfcp_pkt_attr_find_at(const struct tbfcp_pkt_s* pc_self, enum tbfcp_attribute_format_e e_format, tsk_size_t u_index, const struct tbfcp_attr_s** ppc_attr); +#define tbfcp_pkt_attr_find_first(pc_self, e_format, ppc_attr) tbfcp_pkt_attr_find_at(pc_self, e_format, 0, ppc_attr) + +/***** rfc4582 - 5.3.1. FloorRequest *****/ +#define tbfcp_pkt_create_FloorRequest(conf_id, transac_id, user_id, pp_self) tbfcp_pkt_create(tbfcp_primitive_FloorRequest, (conf_id), (transac_id), (user_id), (pp_self)) +#define tbfcp_pkt_create_empty_FloorRequest(p_self) tbfcp_pkt_create_empty(TBFCP_PKT(p_self), tbfcp_primitive_FloorRequest) +TINYBFCP_API int tbfcp_pkt_create_FloorRequest_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, struct tbfcp_pkt_s** pp_self); + +/***** rfc4582 - 5.3.2. FloorRelease *****/ +#define tbfcp_pkt_create_FloorRelease(conf_id, transac_id, user_id, pp_self) tbfcp_pkt_create(tbfcp_primitive_FloorRelease, (conf_id), (transac_id), (user_id), (pp_self)) +#define tbfcp_pkt_create_empty_FloorRelease(p_self) tbfcp_pkt_create_empty(TBFCP_PKT(p_self), tbfcp_primitive_FloorRelease) +TINYBFCP_API int tbfcp_pkt_create_FloorRelease_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, struct tbfcp_pkt_s** pp_self); + + +/**** rfc4582 - 5.3.4. FloorRequestStatus *****/ +#define tbfcp_pkt_create_FloorRequestStatus(conf_id, transac_id, user_id, pp_self) tbfcp_pkt_create(tbfcp_primitive_FloorRequestStatus, (conf_id), (transac_id), (user_id), (pp_self)) +#define tbfcp_pkt_create_empty_FloorRequestStatus(p_self) tbfcp_pkt_create_empty(TBFCP_PKT(p_self), tbfcp_primitive_FloorRequestStatus) +TINYBFCP_API int tbfcp_pkt_create_FloorRequestStatus_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, struct tbfcp_pkt_s** pp_self); + +/**** rfc4582 - 5.3.11. Hello ***/ +#define tbfcp_pkt_create_Hello(conf_id, transac_id, user_id, pp_self) tbfcp_pkt_create(tbfcp_primitive_Hello, (conf_id), (transac_id), (user_id), (pp_self)) +#define tbfcp_pkt_create_empty_Hello(p_self) tbfcp_pkt_create_empty(TBFCP_PKT(p_self), tbfcp_primitive_Hello) + +/**** 5.3.12. HelloAck ***/ +#define tbfcp_pkt_create_HelloAck(conf_id, transac_id, user_id, pp_self) tbfcp_pkt_create(tbfcp_primitive_HelloAck, (conf_id), (transac_id), (user_id), (pp_self)) +#define tbfcp_pkt_create_empty_HelloAck(p_self) tbfcp_pkt_create_empty(TBFCP_PKT(p_self), tbfcp_primitive_HelloAck) +TINYBFCP_API int tbfcp_pkt_create_HelloAck_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, struct tbfcp_pkt_s** pp_self); + +#if 0 +// rfc4582 - 5.3.1. FloorRequest +typedef struct tbfcp_pkt_FloorRequest_s { + TBFCP_DECLARE_PKT; + struct tbfcp_attr_unsigned16_s* p_floor_id; // First [FLOOR-ID]. Others will be in "p_list_exts". + struct tbfcp_attr_unsigned16_s* p_beneficiary_id; // [BENEFICIARY-ID] + struct tbfcp_attr_octetstring_s* p_participant_provided_info; // [PARTICIPANT-PROVIDED-INFO] + struct tbfcp_attr_octetstring16_s* p_priority; // [PRIORITY] +} tbfcp_pkt_FloorRequest_t; +TINYBFCP_API int tbfcp_pkt_FloorRequest_create_empty(struct tbfcp_pkt_FloorRequest_s** pp_self); +TINYBFCP_API int tbfcp_pkt_FloorRequest_create(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, struct tbfcp_pkt_FloorRequest_s** pp_self); +#endif + +TBFCP_END_DECLS + +#endif /* TBFCP_PKT_H */ + diff --git a/tinyBFCP/include/tinybfcp/tbfcp_session.h b/tinyBFCP/include/tinybfcp/tbfcp_session.h new file mode 100644 index 0000000..82e57f6 --- /dev/null +++ b/tinyBFCP/include/tinybfcp/tbfcp_session.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_SESSION_H +#define TBFCP_SESSION_H + +#include "tinybfcp_config.h" +#include "tinybfcp/tbfcp_types.h" + +#include "tinynet.h" + +TBFCP_BEGIN_DECLS + +struct tbfcp_session_s; +struct tbfcp_pkt_s; + +typedef enum tbfcp_session_event_type_e +{ + tbfcp_session_event_type_inf_inc_msg, + tbfcp_session_event_type_err_send_timedout +} +tbfcp_session_event_type_t; + +typedef struct tbfcp_session_event_xs { + enum tbfcp_session_event_type_e e_type; + const struct tbfcp_pkt_s* pc_pkt; + const void* pc_usr_data; +} tbfcp_session_event_xt; + +typedef int (*tbfcp_session_callback_f)(const struct tbfcp_session_event_xs *e); + +TINYBFCP_API int tbfcp_session_create(enum tnet_socket_type_e e_socket_type, const char* pc_local_ip, struct tbfcp_session_s** pp_self); +TINYBFCP_API int tbfcp_session_create_2(struct tnet_ice_ctx_s* p_ice_ctx, struct tbfcp_session_s** pp_self); +TINYBFCP_API int tbfcp_session_set_callback(struct tbfcp_session_s* p_self, tbfcp_session_callback_f f_fun, const void* pc_usr_data); +TINYBFCP_API int tbfcp_session_set_ice_ctx(struct tbfcp_session_s* p_self, struct tnet_ice_ctx_s* p_ice_ctx); +TINYBFCP_API int tbfcp_session_prepare(struct tbfcp_session_s* p_self); +TINYBFCP_API int tbfcp_session_start(struct tbfcp_session_s* p_self); +TINYBFCP_API int tbfcp_session_pause(struct tbfcp_session_s* p_self); +TINYBFCP_API int tbfcp_session_stop(struct tbfcp_session_s* p_self); +TINYBFCP_API int tbfcp_session_set_natt_ctx(struct tbfcp_session_s* p_self, struct tnet_nat_ctx_s* p_natt_ctx); +TINYBFCP_API int tbfcp_session_set_remote_address(struct tbfcp_session_s* p_self, const char* pc_ip, tnet_port_t u_port); +TINYBFCP_API int tbfcp_session_set_remote_role(struct tbfcp_session_s* p_self, enum tbfcp_role_e e_role_remote); +TINYBFCP_API int tbfcp_session_set_remote_setup(struct tbfcp_session_s* p_self, enum tbfcp_setup_e e_setup_remote); +TINYBFCP_API int tbfcp_session_set_conf_ids(struct tbfcp_session_s* p_self, uint32_t u_conf_id, uint16_t u_user_id, uint16_t u_floor_id); +TINYBFCP_API int tbfcp_session_get_profile(const struct tbfcp_session_s* pc_self, const char** ppc_profile); +TINYBFCP_API int tbfcp_session_get_local_role(const struct tbfcp_session_s* pc_self, enum tbfcp_role_e *pe_role_local); +TINYBFCP_API int tbfcp_session_get_local_setup(const struct tbfcp_session_s* pc_self, enum tbfcp_setup_e *pe_setup_local); +TINYBFCP_API int tbfcp_session_get_local_address(const struct tbfcp_session_s* pc_self, const char** ppc_ip, tnet_port_t *pu_port); +TINYBFCP_API int tbfcp_session_create_pkt_Hello(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt); +TINYBFCP_API int tbfcp_session_create_pkt_FloorRequest(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt); +TINYBFCP_API int tbfcp_session_create_pkt_FloorRelease(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt); +TINYBFCP_API int tbfcp_session_send_pkt(struct tbfcp_session_s* p_self, const struct tbfcp_pkt_s* pc_pkt); + +TBFCP_END_DECLS + +#endif /* TBFCP_SESSION_H */ + diff --git a/tinyBFCP/include/tinybfcp/tbfcp_types.h b/tinyBFCP/include/tinybfcp/tbfcp_types.h new file mode 100644 index 0000000..561d7be --- /dev/null +++ b/tinyBFCP/include/tinybfcp/tbfcp_types.h @@ -0,0 +1,207 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_TYPES_H +#define TBFCP_TYPES_H + +#include "tinybfcp_config.h" + +TBFCP_BEGIN_DECLS + +#if !defined(kBfcpFieldMYes) +# define kBfcpFieldMYes 1 +#endif /* kBfcpFieldMYes */ +#if !defined(kBfcpFieldMNo) +# define kBfcpFieldMNo 0 +#endif /* kBfcpFieldMNo */ + +// draft-ietf-bfcpbis-rfc4582bis-11 - 8.3.3. Timer Values +#if !defined(kBfcpTimerT1) +# define kBfcpTimerT1 500 +#endif /* kBfcpTimerT1 */ +#if !defined(kBfcpTimerT2) +# define kBfcpTimerT2 10000 +#endif /* kBfcpTimerT1 */ +#if !defined(kBfcpTimerT1MaxTries) +# define kBfcpTimerT1MaxTries 4 // draft says #3 but we use #4 +#endif /* kBfcpTimerT1MaxTries */ +#if !defined(kBfcpTimerT1Max) +# define kBfcpTimerT1Max (kBfcpTimerT1 * kBfcpTimerT1MaxTries) +#endif /* kBfcpTimerT1 */ + +#if !defined(kBfcpTcpTimerReconnect) +# define kBfcpTcpTimerReconnect 5000 // Try to reconnect the TCP/TLS socket every 5seconds if unexpectedly disconnected +#endif /* kBfcpTcpTimerReconnect */ + +#if !defined(kBfcpTimerKeepAlive) +# define kBfcpTimerKeepAlive 30000 // Send Hello message every 30 seconds +#endif /* kBfcpTimerKeepAlive */ + + +// RFC4582 - 11.1. Registration of the 'TCP/BFCP' and 'TCP/TLS/BFCP' SDP 'proto' Values +#if !defined (kBfcpProfileTLS) +# define kBfcpProfileTLS "TCP/TLS/BFCP" +#endif /* kBfcpProfileTLS */ +#if !defined (kBfcpProfileTCP) +# define kBfcpProfileTCP "TCP/BFCP" +#endif /* kBfcpProfileTCP */ +// draft-ietf-bfcpbis-rfc4582bis-11 - 5.4. Registration of SDP 'proto' Values (11.1) +#if !defined (kBfcpProfileUDP) +# define kBfcpProfileUDP "UDP/BFCP" +#endif /* kBfcpProfileUDP */ +#if !defined (kBfcpProfileDTLS) +# define kBfcpProfileDTLS "UDP/TLS/BFCP" +#endif /* kBfcpProfileDTLS */ + +#if !defined(kBfcpTransportDefault) +# define kBfcpTransportDefault tnet_socket_type_udp_ipv4 +#endif /* kBfcpTransportDefault */ + +#if !defined(kBfcpTransportFriendlyName) +# define kBfcpTransportFriendlyName "BFCP Session" +#endif /* kBfcpTransportFriendlyName */ + +#if !defined(kBfcpBuffMinPad) +# define kBfcpBuffMinPad 40 // to make the buffer kasher +#endif /* kBfcpBuffMinPad */ + + +// rfc4583 - 4. Floor Control Server Determination +#if !defined(kBfcpRoleC) +# define kBfcpRoleC "c-only" +#endif /* kBfcpRoleC */ +#if !defined(kBfcpRoleS) +# define kBfcpRoleS "s-only" +#endif /* kBfcpRoleS */ +#if !defined(kBfcpRoleCS) +# define kBfcpRoleCS "c-s" +#endif /* kBfcpRoleCS */ +#if !defined(kBfcpRoleDefault) +# define kBfcpRoleDefault tbfcp_role_c_only // For know the stack works in client mode only +#endif /* kBfcpRoleDefault */ +typedef enum tbfcp_role_e { + tbfcp_role_c_only = (1 << 0), + tbfcp_role_s_only = (1 << 1), + tbfcp_role_c_s = (tbfcp_role_c_only | tbfcp_role_s_only) +} tbfcp_role_t; + +typedef enum tbfcp_setup_e { + tbfcp_setup_active = (1 << 0), + tbfcp_setup_passive = (1 << 1), + tbfcp_setup_actpass = (tbfcp_setup_active | tbfcp_setup_passive), +} tbfcp_setup_t; +#if !defined(kBfcpSetupDefault) +# define kBfcpSetupDefault tbfcp_setup_actpass +#endif /* kBfcpSetupDefault */ +#if !defined(kBfcpSetupActPass) +# define kBfcpSetupActPass "actpass" +#endif /* kBfcpSetupActPass */ +#if !defined(kBfcpSetupActive) +# define kBfcpSetupActive "active" +#endif /* kBfcpSetupActive */ +#if !defined(kBfcpSetupPassive) +# define kBfcpSetupPassive "passive" +#endif /* kBfcpSetupPassive */ + +// RFC4582 - 5.1. COMMON-HEADER Format +typedef enum tbfcp_primitive_e { + tbfcp_primitive_FloorRequest = 1, // | P -> S | + tbfcp_primitive_FloorRelease = 2, // | P -> S | + tbfcp_primitive_FloorRequestQuery = 3, // | P -> S ; Ch -> S | + tbfcp_primitive_FloorRequestStatus = 4, // | P <- S ; Ch <- S | + tbfcp_primitive_UserQuery = 5, // | P -> S ; Ch -> S | + tbfcp_primitive_UserStatus = 6, // | P <- S ; Ch <- S | + tbfcp_primitive_FloorQuery = 7, // | P -> S ; Ch -> S | + tbfcp_primitive_FloorStatus = 8, // | P <- S ; Ch <- S | + tbfcp_primitive_ChairAction = 9, // | Ch -> S | + tbfcp_primitive_ChairActionAck = 10, // | Ch <- S | + tbfcp_primitive_Hello = 11, // | P -> S ; Ch -> S | + tbfcp_primitive_HelloAck = 12, // | P <- S ; Ch <- S | + tbfcp_primitive_Error = 13, // | P <- S ; Ch <- S + //!\ Update tbfcp_pkt_create_HelloAck_2() if an entry is added or remove +} tbfcp_primitive_t; + +// RFC4582 - 5.2. Attribute Format +typedef enum tbfcp_attribute_type_e { + tbfcp_attribute_type_BENEFICIARY_ID = 1, // | Unsigned16 | + tbfcp_attribute_type_FLOOR_ID = 2, // | Unsigned16 | + tbfcp_attribute_type_FLOOR_REQUEST_ID = 3, // | Unsigned16 | + tbfcp_attribute_type_PRIORITY = 4, // | OctetString16 | + tbfcp_attribute_type_REQUEST_STATUS = 5, // | OctetString16 | + tbfcp_attribute_type_ERROR_CODE = 6, // | OctetString | + tbfcp_attribute_type_ERROR_INFO = 7, // | OctetString | + tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO = 8, // | OctetString | + tbfcp_attribute_type_STATUS_INFO = 9, // | OctetString | + tbfcp_attribute_type_SUPPORTED_ATTRIBUTES = 10, // | OctetString | + tbfcp_attribute_type_SUPPORTED_PRIMITIVES = 11, // | OctetString | + tbfcp_attribute_type_USER_DISPLAY_NAME = 12, // | OctetString | + tbfcp_attribute_type_USER_URI = 13, // | OctetString | + tbfcp_attribute_type_BENEFICIARY_INFORMATION = 14, // | Grouped | + tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION = 15, // | Grouped | + tbfcp_attribute_type_REQUESTED_BY_INFORMATION = 16, // | Grouped | + tbfcp_attribute_type_FLOOR_REQUEST_STATUS = 17, // | Grouped | + tbfcp_attribute_type_OVERALL_REQUEST_STATUS = 18, // | Grouped + //!\ Update tbfcp_pkt_create_HelloAck_2() if an entry is added or remove +} tbfcp_attribute_type_t; + +// RFC4582 - 5.2. Attribute Format +typedef enum tbfcp_attribute_format_e { + tbfcp_attribute_format_Unknown, + tbfcp_attribute_format_Unsigned16, + tbfcp_attribute_format_OctetString16, + tbfcp_attribute_format_OctetString, + tbfcp_attribute_format_Grouped, +} tbfcp_attribute_format_t; + +// RFC4582 - 5.2.4. PRIORITY +typedef enum tbfcp_prio_e { + tbfcp_prio_Lowest = 0, + tbfcp_prio_Low = 1, + tbfcp_prio_Normal = 2, + tbfcp_prio_High = 3, + tbfcp_prio_Highest = 4 +} tbfcp_prio_t; + +// RFC4582 - 5.2.5. REQUEST-STATUS +typedef enum tbfcp_reqstatus_e { + tbfcp_reqstatus_Pending = 1, + tbfcp_reqstatus_Accepted = 2, + tbfcp_reqstatus_Granted = 3, + tbfcp_reqstatus_Denied = 4, + tbfcp_reqstatus_Cancelled = 5, + tbfcp_reqstatus_Released = 6, + tbfcp_reqstatus_Revoked = 7 +} tbfcp_reqstatus_t; + +// RFC4582 - 5.2.6. ERROR-CODE +typedef enum tbfcp_err_code_e { + tbfcp_err_code_Conference_does_not_Exist = 1, + tbfcp_err_code_User_does_not_Exist = 2, + tbfcp_err_code_Unknown_Primitive = 3, + tbfcp_err_code_Unknown_Mandatory_Attribute = 4, + tbfcp_err_code_Unauthorized_Operation = 5, + tbfcp_err_code_Invalid_Floor_ID = 6, + tbfcp_err_code_Floor_Request_ID_Does_Not_Exist = 7, + tbfcp_err_code_You_have_Already_Reached_the_Maximum_Number_of_OngoingFloor_Requests_for_this_Floor = 9, + tbfcp_err_code_Use_TLS = 10, +} tbfcp_err_code_t; + +TBFCP_END_DECLS + +#endif /* TBFCP_TYPES_H */ + diff --git a/tinyBFCP/include/tinybfcp/tbfcp_utils.h b/tinyBFCP/include/tinybfcp/tbfcp_utils.h new file mode 100644 index 0000000..98c23c3 --- /dev/null +++ b/tinyBFCP/include/tinybfcp/tbfcp_utils.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TBFCP_UTILS_H +#define TBFCP_UTILS_H + +#include "tinybfcp_config.h" +#include "tinybfcp/tbfcp_types.h" + +#include "tsk_common.h" + +TBFCP_BEGIN_DECLS + +enum tnet_socket_type_e; + +TINYBFCP_API int tbfcp_utils_get_profile(enum tnet_socket_type_e e_socket_type, const char** ppc_profile); +TINYBFCP_API int tbfcp_utils_get_role(enum tbfcp_role_e e_role, const char** ppc_role); +TINYBFCP_API int tbfcp_utils_parse_role(const char* pc_role, enum tbfcp_role_e* pe_role); +TINYBFCP_API int tbfcp_utils_get_setup(enum tbfcp_role_e e_setup, const char** ppc_setup); +TINYBFCP_API int tbfcp_utils_parse_setup(const char* pc_setup, enum tbfcp_setup_e* pe_setup); +TINYBFCP_API int tbfcp_utils_is_role_acceptable(enum tbfcp_role_e e_role_local, enum tbfcp_role_e e_role_proposed, tsk_bool_t *pb_acceptable); +TINYBFCP_API int tbfcp_utils_is_setup_acceptable(enum tbfcp_setup_e e_setup_local, enum tbfcp_setup_e e_setup_proposed, tsk_bool_t *pb_acceptable); +TINYBFCP_API uint16_t tbfcp_utils_rand_u16(); + +TBFCP_END_DECLS + +#endif /* TBFCP_UTILS_H */ + diff --git a/tinyBFCP/include/tinybfcp_config.h b/tinyBFCP/include/tinybfcp_config.h new file mode 100644 index 0000000..582b785 --- /dev/null +++ b/tinyBFCP/include/tinybfcp_config.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TINYBFCP_CONFIG_H +#define TINYBFCP_CONFIG_H + +#ifdef __SYMBIAN32__ +#undef _WIN32 /* Because of WINSCW */ +#endif + +// Windows (XP/Vista/7/CE and Windows Mobile) macro definition +#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE) +# define TBFCP_UNDER_WINDOWS 1 +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define TBFCP_UNDER_WINDOWS_RT 1 +# endif +#endif + +#if (TBFCP_UNDER_WINDOWS || defined(__SYMBIAN32__)) && defined(TINYBFCP_EXPORTS) +# define TINYBFCP_API __declspec(dllexport) +# define TINYBFCP_GEXTERN extern __declspec(dllexport) +#elif (TBFCP_UNDER_WINDOWS || defined(__SYMBIAN32__)) && !defined(TINYBFCP_IMPORTS_IGNORE) +# define TINYBFCP_API __declspec(dllimport) +# define TINYBFCP_GEXTERN __declspec(dllimport) +#else +# define TINYBFCP_API +# define TINYBFCP_GEXTERN extern +#endif + +/* Guards against C++ name mangling +*/ +#ifdef __cplusplus +# define TBFCP_BEGIN_DECLS extern "C" { +# define TBFCP_END_DECLS } +#else +# define TBFCP_BEGIN_DECLS +# define TBFCP_END_DECLS +#endif + +/* Disable some well-known warnings +*/ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS +#endif + +/* Detecting C99 compilers + */ +#if (__STDC_VERSION__ == 199901L) && !defined(__C99__) +# define __C99__ +#endif + +#include +#ifdef __SYMBIAN32__ +#include +#endif + +#if HAVE_CONFIG_H +#include +#endif + +#if !defined(TBFCP_VERSION) +# define TBFCP_VERSION 1 +#endif /* TBFCP_VERSION */ + +#endif // TINYBFCP_CONFIG_H diff --git a/tinyBFCP/src/tbfcp_attr.c b/tinyBFCP/src/tbfcp_attr.c new file mode 100644 index 0000000..7b5359a --- /dev/null +++ b/tinyBFCP/src/tbfcp_attr.c @@ -0,0 +1,674 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "tinybfcp/tbfcp_attr.h" + +#include "tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" + +#define kWithoutPadding tsk_false +#define kWithPadding tsk_true + +#define ALIGN_ON_32BITS(size_in_octes) if (((size_in_octes) & 3)) (size_in_octes) += (4 - ((size_in_octes) & 3)); +#define ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(p_buffer, size_in_octes) \ + if (((size_in_octes) & 3)) { \ + int c = (4 - ((size_in_octes) & 3)); \ + memset(p_buffer, 0, c); \ + (size_in_octes) += c; \ + } + + +static enum tbfcp_attribute_format_e _tbfcp_attr_get_format(enum tbfcp_attribute_type_e type) +{ + switch (type) { + case tbfcp_attribute_type_BENEFICIARY_ID: + case tbfcp_attribute_type_FLOOR_ID: + case tbfcp_attribute_type_FLOOR_REQUEST_ID: + return tbfcp_attribute_format_Unsigned16; + case tbfcp_attribute_type_PRIORITY: + case tbfcp_attribute_type_REQUEST_STATUS: + return tbfcp_attribute_format_OctetString16; + case tbfcp_attribute_type_ERROR_CODE: + case tbfcp_attribute_type_ERROR_INFO: + case tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO: + case tbfcp_attribute_type_STATUS_INFO: + case tbfcp_attribute_type_SUPPORTED_ATTRIBUTES: + case tbfcp_attribute_type_SUPPORTED_PRIMITIVES: + case tbfcp_attribute_type_USER_DISPLAY_NAME: + case tbfcp_attribute_type_USER_URI: + return tbfcp_attribute_format_OctetString; + case tbfcp_attribute_type_BENEFICIARY_INFORMATION: + case tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION: + case tbfcp_attribute_type_REQUESTED_BY_INFORMATION: + case tbfcp_attribute_type_FLOOR_REQUEST_STATUS: + case tbfcp_attribute_type_OVERALL_REQUEST_STATUS: + return tbfcp_attribute_format_Grouped; + default: + return tbfcp_attribute_format_Unknown; + + } +} + +static int _tbfcp_attr_get_size_in_octetunits(const tbfcp_attr_t* pc_self, tsk_bool_t with_padding, tsk_size_t* p_size) +{ + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (pc_self->format) { + case tbfcp_attribute_format_Unsigned16: + case tbfcp_attribute_format_OctetString16: { + *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + case tbfcp_attribute_format_OctetString: { + *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + ((const tbfcp_attr_octetstring_t*)pc_self)->OctetStringLength); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + case tbfcp_attribute_format_Grouped: { + int ret; + tsk_size_t n_size; + const tbfcp_attr_grouped_t* _pc_self = (const tbfcp_attr_grouped_t*)pc_self; + const tsk_list_item_t* pc_item; + const tbfcp_attr_t* pc_attr; + *p_size = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + _pc_self->extra_hdr_size_in_octets; + tsk_list_foreach(pc_item, _pc_self->p_list_attrs) { + if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) { + if ((ret = tbfcp_attr_get_size_in_octetunits_without_padding(pc_attr, &n_size))) { + return ret; + } + *p_size += n_size; + } + } + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + default: { + TSK_DEBUG_WARN("Attribute format=%d is unknown. Don't be surprised if something goes wrong.", pc_self->format); + *p_size = (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + pc_self->hdr.length); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + } +} + +int tbfcp_attr_get_size_in_octetunits_without_padding(const tbfcp_attr_t* pc_self, tsk_size_t* p_size) +{ + return _tbfcp_attr_get_size_in_octetunits(pc_self, kWithoutPadding, p_size); +} + +int tbfcp_attr_get_size_in_octetunits_with_padding(const tbfcp_attr_t* pc_self, tsk_size_t* p_size) +{ + return _tbfcp_attr_get_size_in_octetunits(pc_self, kWithPadding, p_size); +} + +static int _tbfcp_attr_write(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t with_padding, tsk_size_t *p_written) +{ + tsk_size_t n_min_req_size; + int ret; + if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = _tbfcp_attr_get_size_in_octetunits(pc_self, with_padding, &n_min_req_size))) { + return ret; + } + if (n_min_req_size > n_buff_size) { + TSK_DEBUG_ERROR("Buffer too short %u<%u", n_buff_size, n_min_req_size); + return -2; + } + + p_buff_ptr[0] = ((uint8_t)pc_self->hdr.type) << 1; + p_buff_ptr[0] |= (pc_self->hdr.M & 0x01); + + switch (pc_self->format) { + case tbfcp_attribute_format_Unsigned16: + case tbfcp_attribute_format_OctetString16: { + *p_written = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2; + p_buff_ptr[1] = (uint8_t)*p_written; + if (pc_self->format == tbfcp_attribute_format_Unsigned16) { + *((uint16_t*)&p_buff_ptr[2]) = tnet_htons(((const tbfcp_attr_unsigned16_t*)pc_self)->Unsigned16); + } + else { + p_buff_ptr[2] = ((const tbfcp_attr_octetstring16_t*)pc_self)->OctetString16[0]; + p_buff_ptr[3] = ((const tbfcp_attr_octetstring16_t*)pc_self)->OctetString16[1]; + } + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + return 0; + } + case tbfcp_attribute_format_OctetString: { + const tbfcp_attr_octetstring_t* _pc_self = (const tbfcp_attr_octetstring_t*)pc_self; + *p_written = TBFCP_ATTR_HDR_SIZE_IN_OCTETS + ((_pc_self->OctetStringLength && _pc_self->OctetString) ? _pc_self->OctetStringLength : 0); + p_buff_ptr[1] = (uint8_t)*p_written; + if (_pc_self->OctetStringLength && _pc_self->OctetString) { + memcpy(&p_buff_ptr[2], _pc_self->OctetString, _pc_self->OctetStringLength); + } + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + return 0; + } + case tbfcp_attribute_format_Grouped: { + int ret; + tsk_size_t n_written; + const tbfcp_attr_grouped_t* _pc_self = (const tbfcp_attr_grouped_t*)pc_self; + const tsk_list_item_t* pc_item; + const tbfcp_attr_t* pc_attr; + if (_pc_self->extra_hdr_size_in_octets && _pc_self->extra_hdr_size_in_octets != 2) { + TSK_DEBUG_ERROR("extra_hdr_size_in_octets=%u not valid", _pc_self->extra_hdr_size_in_octets); // for now only 2byte extra values is supported + return -2; + } + if ((ret = tbfcp_attr_get_size_in_octetunits_without_padding(pc_self, p_written))) { + return ret; + } + p_buff_ptr[1] = (uint8_t)*p_written; + p_buff_ptr += 2; + n_buff_size -= 2; + if (_pc_self->extra_hdr_size_in_octets) { + *((uint16_t*)p_buff_ptr) = tnet_htons_2(&_pc_self->extra_hdr); + p_buff_ptr += _pc_self->extra_hdr_size_in_octets; + n_buff_size -= _pc_self->extra_hdr_size_in_octets; + } + tsk_list_foreach(pc_item, _pc_self->p_list_attrs) { + if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) { + if ((ret = _tbfcp_attr_write(pc_attr, p_buff_ptr, n_buff_size, kWithoutPadding, &n_written))) { + return ret; + } + p_buff_ptr += n_written; + n_buff_size -= n_written; + } + } + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + return 0; + } + default: { + TSK_DEBUG_ERROR("Attribute format=%d is unknown.", pc_self->format); + return -2; + } + } +} + +int tbfcp_attr_write_without_padding(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + return _tbfcp_attr_write(pc_self, p_buff_ptr, n_buff_size, kWithoutPadding, p_written); +} + +int tbfcp_attr_write_with_padding(const tbfcp_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + return _tbfcp_attr_write(pc_self, p_buff_ptr, n_buff_size, kWithPadding, p_written); +} + +int tbfcp_attr_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, tbfcp_attr_t** pp_attr) +{ + uint8_t M, Length, PadLength; + tbfcp_attribute_type_t Type; + tbfcp_attribute_format_t Format; + int ret; + if (!pc_buff_ptr || !n_buff_size || !pp_attr || !p_consumed_octets) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (n_buff_size < TBFCP_ATTR_HDR_SIZE_IN_OCTETS) { + TSK_DEBUG_ERROR("Buffer too short(%u)", n_buff_size); + return -2; + } + + Length = pc_buff_ptr[1]; + if (Length > n_buff_size) { + TSK_DEBUG_ERROR("Buffer too short(%u). Length=%u", n_buff_size, Length); + return -3; + } + + PadLength = (Length & 0x03) ? (4 - (Length & 0x03)) : 0; + + *pp_attr = tsk_null; + *p_consumed_octets = Length + PadLength; + + Type = (pc_buff_ptr[0] >> 1) & 0x7F; + M = (pc_buff_ptr[0] & 0x01); + Format = _tbfcp_attr_get_format(Type); + if (Format == tbfcp_attribute_format_Unknown) { + return 0; + } + + if (Format == tbfcp_attribute_format_Unsigned16) { + uint16_t Unsigned16 = tnet_ntohs_2(&pc_buff_ptr[2]); + if ((ret = tbfcp_attr_unsigned16_create(Type, M, Unsigned16, (tbfcp_attr_unsigned16_t**)pp_attr))) { + return ret; + } + } + else if (Format == tbfcp_attribute_format_OctetString16) { + uint8_t OctetString16[2]; + OctetString16[0] = pc_buff_ptr[2]; + OctetString16[1] = pc_buff_ptr[3]; + if ((ret = tbfcp_attr_octetstring16_create(Type, M, OctetString16, (tbfcp_attr_octetstring16_t**)pp_attr))) { + return ret; + } + } + else if (Format == tbfcp_attribute_format_OctetString) { + const uint8_t *OctetString = &pc_buff_ptr[TBFCP_ATTR_HDR_SIZE_IN_OCTETS]; + uint8_t OctetStringLength = (Length - TBFCP_ATTR_HDR_SIZE_IN_OCTETS); + if ((ret = tbfcp_attr_octetstring_create(Type, M, OctetString, OctetStringLength, (tbfcp_attr_octetstring_t**)pp_attr))) { + return ret; + } + } + else if (Format == tbfcp_attribute_format_Grouped) { + tbfcp_attr_grouped_t* p_attr; + if ((ret = tbfcp_attr_grouped_create(Type, M, &p_attr))) { + return ret; + } + *pp_attr = (tbfcp_attr_t*)p_attr; + switch (Type) { + case tbfcp_attribute_type_BENEFICIARY_INFORMATION: { + p_attr->extra_hdr_size_in_octets = 2; + p_attr->extra_hdr.BeneficiaryID = tnet_ntohs_2(&pc_buff_ptr[2]); + break; + } + case tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION: { + p_attr->extra_hdr_size_in_octets = 2; + p_attr->extra_hdr.FloorRequestID = tnet_ntohs_2(&pc_buff_ptr[2]); + break; + } + case tbfcp_attribute_type_REQUESTED_BY_INFORMATION: { + p_attr->extra_hdr_size_in_octets = 2; + p_attr->extra_hdr.RequestedbyID = tnet_ntohs_2(&pc_buff_ptr[2]); + break; + } + case tbfcp_attribute_type_FLOOR_REQUEST_STATUS: { + p_attr->extra_hdr_size_in_octets = 2; + p_attr->extra_hdr.FloorID = tnet_ntohs_2(&pc_buff_ptr[2]); + break; + } + case tbfcp_attribute_type_OVERALL_REQUEST_STATUS: { + p_attr->extra_hdr_size_in_octets = 2; + p_attr->extra_hdr.FloorRequestID = tnet_ntohs_2(&pc_buff_ptr[2]); + break; + } + default: { + return 0; + } + } + if ((TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets) < Length) { + tsk_size_t n_consumed_octets, PayloadLength = Length; + PayloadLength -= TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets; + pc_buff_ptr += TBFCP_ATTR_HDR_SIZE_IN_OCTETS + p_attr->extra_hdr_size_in_octets; + if (PayloadLength >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS) { + do { + if ((ret = tbfcp_attr_read(pc_buff_ptr, PayloadLength, &n_consumed_octets, (tbfcp_attr_t**)&p_attr))) { + break; + } + if ((ret = tbfcp_attr_grouped_add_attr((tbfcp_attr_grouped_t*)(*pp_attr), (tbfcp_attr_t**)&p_attr))) { + TSK_OBJECT_SAFE_FREE(p_attr); + break; + } + pc_buff_ptr += n_consumed_octets; + PayloadLength -= n_consumed_octets; + } + while (PayloadLength >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS); + } + } + } + else { + TSK_DEBUG_ERROR("%d not valid attribute format", Format); + return -4; + } + return 0; +} + + +static int _tbfcp_attr_init(tbfcp_attr_t* p_self, tbfcp_attribute_type_t type, unsigned M, uint8_t length) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!p_self->pc_base) { + p_self->pc_base = p_self; + } + p_self->hdr.type = type; + p_self->hdr.M = M; + p_self->hdr.length = length; + if ((p_self->format = _tbfcp_attr_get_format(type)) == tbfcp_attribute_format_Unknown) { + TSK_DEBUG_WARN("Attribute type=%d is unknown...setting its format to UNKNOWN. Don't be surprised if something goes wrong.", type); + } + + return 0; +} + + +/*************** tbfcp_attr_unsigned16 *******************/ +int tbfcp_attr_unsigned16_create(tbfcp_attribute_type_t type, unsigned M, uint16_t Unsigned16, tbfcp_attr_unsigned16_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_attr_unsigned16_def_t; + tbfcp_attr_unsigned16_t* p_self; + int ret; + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_attr_unsigned16_def_t))) { + TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_unsigned16_def_t' object"); + return -2; + } + if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2))) { + TSK_OBJECT_SAFE_FREE(p_self); + return -3; + } + if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_Unsigned16) { + TSK_DEBUG_ERROR("Format mismatch"); + TSK_OBJECT_SAFE_FREE(p_self); + return -4; + } + p_self->Unsigned16 = Unsigned16; + *pp_self = p_self; + return 0; +} + +static tsk_object_t* tbfcp_attr_unsigned16_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_attr_unsigned16_t *p_u16 = (tbfcp_attr_unsigned16_t *)self; + if (p_u16) { + } + return self; +} +static tsk_object_t* tbfcp_attr_unsigned16_dtor(tsk_object_t * self) +{ + tbfcp_attr_unsigned16_t *p_u16 = (tbfcp_attr_unsigned16_t *)self; + if (p_u16) { + TSK_DEBUG_INFO("*** BFCP Attribute(Unsigned16) destroyed ***"); + + } + return self; +} +static int tbfcp_attr_unsigned16_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2) +{ + const tbfcp_attr_unsigned16_t *pc_att1 = (const tbfcp_attr_unsigned16_t *)_att1; + const tbfcp_attr_unsigned16_t *pc_att2 = (const tbfcp_attr_unsigned16_t *)_att2; + + return (int)(pc_att1-pc_att2); +} +static const tsk_object_def_t tbfcp_attr_unsigned16_def_s = { + sizeof(tbfcp_attr_unsigned16_t), + tbfcp_attr_unsigned16_ctor, + tbfcp_attr_unsigned16_dtor, + tbfcp_attr_unsigned16_cmp, +}; +const tsk_object_def_t *tbfcp_attr_unsigned16_def_t = &tbfcp_attr_unsigned16_def_s; + + + + +/*************** tbfcp_attr_octetstring16 *******************/ +int tbfcp_attr_octetstring16_create(tbfcp_attribute_type_t type, unsigned M, uint8_t OctetString16[2], tbfcp_attr_octetstring16_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_attr_octetstring16_def_t; + tbfcp_attr_octetstring16_t* p_self; + int ret; + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_attr_octetstring16_def_t))) { + TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_octetstring16_def_t' object"); + return -2; + } + if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 2))) { + TSK_OBJECT_SAFE_FREE(p_self); + return -3; + } + if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_OctetString16) { + TSK_DEBUG_ERROR("Format mismatch"); + TSK_OBJECT_SAFE_FREE(p_self); + return -4; + } + p_self->OctetString16[0] = OctetString16[0]; + p_self->OctetString16[1] = OctetString16[1]; + *pp_self = p_self; + return 0; +} + +static tsk_object_t* tbfcp_attr_octetstring16_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_attr_octetstring16_t *p_os16 = (tbfcp_attr_octetstring16_t *)self; + if (p_os16) { + } + return self; +} +static tsk_object_t* tbfcp_attr_octetstring16_dtor(tsk_object_t * self) +{ + tbfcp_attr_octetstring16_t *p_os16 = (tbfcp_attr_octetstring16_t *)self; + if (p_os16) { + TSK_DEBUG_INFO("*** BFCP Attribute(OctetString16) destroyed ***"); + + } + return self; +} +static int tbfcp_attr_octetstring16_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2) +{ + const tbfcp_attr_octetstring16_t *pc_att1 = (const tbfcp_attr_octetstring16_t *)_att1; + const tbfcp_attr_octetstring16_t *pc_att2 = (const tbfcp_attr_octetstring16_t *)_att2; + + return (int)(pc_att1-pc_att2); +} +static const tsk_object_def_t tbfcp_attr_octetstring16_def_s = { + sizeof(tbfcp_attr_octetstring16_t), + tbfcp_attr_octetstring16_ctor, + tbfcp_attr_octetstring16_dtor, + tbfcp_attr_octetstring16_cmp, +}; +const tsk_object_def_t *tbfcp_attr_octetstring16_def_t = &tbfcp_attr_octetstring16_def_s; + + +/*************** tbfcp_attr_octetstring *******************/ +int tbfcp_attr_octetstring_create(tbfcp_attribute_type_t type, unsigned M, const uint8_t *OctetString, uint8_t OctetStringLength, tbfcp_attr_octetstring_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_attr_octetstring_def_t; + tbfcp_attr_octetstring_t* p_self; + int ret; + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_attr_octetstring_def_t))) { + TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_octetstring_def_t' object"); + return -2; + } + if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, (TBFCP_ATTR_HDR_SIZE_IN_OCTETS + OctetStringLength)))) { + TSK_OBJECT_SAFE_FREE(p_self); + return -3; + } + if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_OctetString) { + TSK_DEBUG_ERROR("Format mismatch"); + TSK_OBJECT_SAFE_FREE(p_self); + return -4; + } + if (OctetStringLength) { + if (!(p_self->OctetString = tsk_malloc(OctetStringLength))) { + TSK_DEBUG_ERROR("Failed to alloc %u octets", OctetStringLength); + TSK_OBJECT_SAFE_FREE(p_self); + return -5; + } + if (OctetString) { + memcpy(p_self->OctetString, OctetString, OctetStringLength); + } + p_self->OctetStringLength = OctetStringLength; + } + else { + TBFCP_ATTR(p_self)->hdr.length = TBFCP_ATTR_HDR_SIZE_IN_OCTETS; + p_self->OctetStringLength = 0; + } + *pp_self = p_self; + return 0; +} + +static tsk_object_t* tbfcp_attr_octetstring_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_attr_octetstring_t *p_os = (tbfcp_attr_octetstring_t *)self; + if (p_os) { + } + return self; +} +static tsk_object_t* tbfcp_attr_octetstring_dtor(tsk_object_t * self) +{ + tbfcp_attr_octetstring_t *p_os = (tbfcp_attr_octetstring_t *)self; + if (p_os) { + TSK_DEBUG_INFO("*** BFCP Attribute(OctetString) destroyed ***"); + TSK_SAFE_FREE(p_os->OctetString); + } + return self; +} +static int tbfcp_attr_octetstring_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2) +{ + const tbfcp_attr_octetstring_t *pc_att1 = (const tbfcp_attr_octetstring_t *)_att1; + const tbfcp_attr_octetstring_t *pc_att2 = (const tbfcp_attr_octetstring_t *)_att2; + + return (int)(pc_att1-pc_att2); +} +static const tsk_object_def_t tbfcp_attr_octetstring_def_s = { + sizeof(tbfcp_attr_octetstring_t), + tbfcp_attr_octetstring_ctor, + tbfcp_attr_octetstring_dtor, + tbfcp_attr_octetstring_cmp, +}; +const tsk_object_def_t *tbfcp_attr_octetstring_def_t = &tbfcp_attr_octetstring_def_s; + + + +/*************** tbfcp_attr_grouped *******************/ +int tbfcp_attr_grouped_create(tbfcp_attribute_type_t type, unsigned M, tbfcp_attr_grouped_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_attr_grouped_def_t; + tbfcp_attr_grouped_t* p_self; + int ret; + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_attr_grouped_def_t))) { + TSK_DEBUG_ERROR("Failed to create 'tbfcp_attr_grouped_def_t' object"); + return -2; + } + if ((ret = _tbfcp_attr_init(TBFCP_ATTR(p_self), type, M, TBFCP_ATTR_HDR_SIZE_IN_OCTETS + 0))) { + TSK_OBJECT_SAFE_FREE(p_self); + return -3; + } + if (TBFCP_ATTR(p_self)->format != tbfcp_attribute_format_Grouped) { + TSK_DEBUG_ERROR("Format mismatch"); + TSK_OBJECT_SAFE_FREE(p_self); + return -4; + } + if (!(p_self->p_list_attrs = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create empty list"); + TSK_OBJECT_SAFE_FREE(p_self); + return -5; + } + + *pp_self = p_self; + return 0; +} + +int tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_t type, unsigned M, uint16_t extra_hdr_u16_val, tbfcp_attr_grouped_t** pp_self) +{ + int ret; + if ((ret = tbfcp_attr_grouped_create(type, M, pp_self))) { + return ret; + } + *((uint16_t*)&(*pp_self)->extra_hdr) = extra_hdr_u16_val; + (*pp_self)->extra_hdr_size_in_octets = 2; + return 0; +} + +int tbfcp_attr_grouped_add_attr(tbfcp_attr_grouped_t* p_self, tbfcp_attr_t** p_attr) +{ + if (!p_self || !p_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_list_push_back_data(p_self->p_list_attrs, (void**)p_attr); + return 0; +} + +int tbfcp_attr_grouped_find_at(const struct tbfcp_attr_grouped_s* pc_self, enum tbfcp_attribute_format_e e_format, tsk_size_t u_index, const struct tbfcp_attr_s** ppc_attr) +{ + tsk_size_t _u_index = 0; + const tsk_list_item_t *pc_item; + const struct tbfcp_attr_s* pc_attr; + if (!pc_self || !ppc_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *ppc_attr = tsk_null; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + pc_attr = (const struct tbfcp_attr_s*)pc_item->data; + if (!pc_attr || pc_attr->format != e_format) { + continue; + } + if (_u_index++ >= u_index) { + *ppc_attr = pc_attr; + break; + } + } + return 0; +} + +static tsk_object_t* tbfcp_attr_grouped_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_attr_grouped_t *p_gr = (tbfcp_attr_grouped_t *)self; + if (p_gr) { + } + return self; +} +static tsk_object_t* tbfcp_attr_grouped_dtor(tsk_object_t * self) +{ + tbfcp_attr_grouped_t *p_gr = (tbfcp_attr_grouped_t *)self; + if (p_gr) { + TSK_DEBUG_INFO("*** BFCP Attribute(Grouped) destroyed ***"); + TSK_OBJECT_SAFE_FREE(p_gr->p_list_attrs); + } + return self; +} +static int tbfcp_attr_grouped_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2) +{ + const tbfcp_attr_grouped_t *pc_att1 = (const tbfcp_attr_grouped_t *)_att1; + const tbfcp_attr_grouped_t *pc_att2 = (const tbfcp_attr_grouped_t *)_att2; + + return (int)(pc_att1-pc_att2); +} +static const tsk_object_def_t tbfcp_attr_grouped_def_s = { + sizeof(tbfcp_attr_grouped_t), + tbfcp_attr_grouped_ctor, + tbfcp_attr_grouped_dtor, + tbfcp_attr_grouped_cmp, +}; +const tsk_object_def_t *tbfcp_attr_grouped_def_t = &tbfcp_attr_grouped_def_s; diff --git a/tinyBFCP/src/tbfcp_pkt.c b/tinyBFCP/src/tbfcp_pkt.c new file mode 100644 index 0000000..0adff65 --- /dev/null +++ b/tinyBFCP/src/tbfcp_pkt.c @@ -0,0 +1,585 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "tinybfcp/tbfcp_pkt.h" + +#include "tnet_endianness.h" + +#include "tsk_debug.h" + +#define SWITCH_CASE_TAKE_ATTR(type, cat, field) \ + case (type): \ + if (!p_self->##field) { \ + p_self->##field = (cat)*pp_attr, *pp_attr = tsk_null; \ + return 0; \ + } \ + break; + +static int _tbfcp_pkt_add_attr(tbfcp_pkt_t* p_self, tbfcp_attr_t** pp_attr) +{ + if (!p_self || !pp_attr || !*pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_list_push_back_data(p_self->p_list_attrs, (void**)pp_attr); + return 0; +} + +static int _tbfcp_pkt_deinit(tbfcp_pkt_t *p_self) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + TSK_OBJECT_SAFE_FREE(p_self->p_list_attrs); + return 0; +} + +static int _tbfcp_pkt_init(tbfcp_pkt_t *p_self, tbfcp_primitive_t primitive, uint32_t conf_id, uint16_t transac_id, uint16_t user_id) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (!p_self->p_list_attrs && !(p_self->p_list_attrs = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create list"); + return -2; + } + if (!p_self->f_add_attr) { + p_self->f_add_attr = _tbfcp_pkt_add_attr; + } + + p_self->hdr.ver = TBFCP_VERSION; + p_self->hdr.reserved = 0; + p_self->hdr.primitive = primitive; + p_self->hdr.conf_id = conf_id; + p_self->hdr.transac_id = transac_id; + p_self->hdr.user_id = user_id; + + return 0; +} +#define _tbfcp_pkt_init_empty(p_self, primitive) _tbfcp_pkt_init((p_self), (primitive), 0, 0, 0) + +static int _tbfcp_pkt_init_2(tbfcp_pkt_t *p_self, tbfcp_primitive_t primitive) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (!p_self->p_list_attrs && !(p_self->p_list_attrs = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create list"); + return -2; + } + + p_self->hdr.ver = TBFCP_VERSION; + p_self->hdr.reserved = 0; + p_self->hdr.primitive = primitive; + + return 0; +} + +int tbfcp_pkt_add_attr(tbfcp_pkt_t* p_self, tbfcp_attr_t** pp_attr) +{ + if (!p_self || !pp_attr || !*pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (p_self->f_add_attr) { + return p_self->f_add_attr(p_self, pp_attr); + } + return _tbfcp_pkt_add_attr(p_self, pp_attr); +} + + +int tbfcp_pkt_create_empty(tbfcp_primitive_t primitive, tbfcp_pkt_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_pkt_def_t; + tbfcp_pkt_t* p_self; + int ret; + + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_pkt_def_t))) { + TSK_DEBUG_ERROR("Failed to create object 'tbfcp_pkt_def_t'"); + return -2; + } + if ((ret = _tbfcp_pkt_init_empty(p_self, primitive))) { + TSK_OBJECT_SAFE_FREE(p_self); + return ret; + } + *pp_self = p_self; + return 0; +} + +int tbfcp_pkt_create(tbfcp_primitive_t primitive, uint32_t conf_id, uint16_t transac_id, uint16_t user_id, tbfcp_pkt_t** pp_self) +{ + int ret; + + if ((ret = tbfcp_pkt_create_empty(primitive, pp_self))) { + return ret; + } + if ((ret = _tbfcp_pkt_init((*pp_self), primitive, conf_id, transac_id, user_id))) { + TSK_OBJECT_SAFE_FREE((*pp_self)); + return ret; + } + return ret; +} + +int tbfcp_pkt_get_size_in_octetunits_without_padding(const tbfcp_pkt_t* pc_self, tsk_size_t* p_size) +{ + const tsk_list_item_t* pc_item; + const tbfcp_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *p_size = TBFCP_PKT_HDR_SIZE_IN_OCTETS; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) { + if ((ret = tbfcp_attr_get_size_in_octetunits_without_padding(pc_attr, &n_size))) { + return ret; + } + *p_size += n_size; + } + } + return 0; +} + +int tbfcp_pkt_get_size_in_octetunits_with_padding(const tbfcp_pkt_t* pc_self, tsk_size_t* p_size) +{ + const tsk_list_item_t* pc_item; + const tbfcp_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *p_size = TBFCP_PKT_HDR_SIZE_IN_OCTETS; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) { + if ((ret = tbfcp_attr_get_size_in_octetunits_with_padding(pc_attr, &n_size))) { + return ret; + } + *p_size += n_size; + } + } + return 0; +} + +int tbfcp_pkt_write_with_padding(const tbfcp_pkt_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + const tsk_list_item_t* pc_item; + const tbfcp_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_pkt_get_size_in_octetunits_with_padding(pc_self, p_written))) { + return ret; + } + if ((n_buff_size < *p_written)) { + TSK_DEBUG_ERROR("Buffer too short: %u<%u", n_buff_size, *p_written); + return -1; + } + + p_buff_ptr[0] = (((uint8_t)pc_self->hdr.ver) << 5) | (pc_self->hdr.reserved & 0x7F); + p_buff_ptr[1] = (uint8_t)pc_self->hdr.primitive; + *((uint32_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)((*p_written - TBFCP_PKT_HDR_SIZE_IN_OCTETS) >> 2)); + *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(pc_self->hdr.conf_id); + *((uint16_t*)&p_buff_ptr[8]) = tnet_htons(pc_self->hdr.transac_id); + *((uint16_t*)&p_buff_ptr[10]) = tnet_htons(pc_self->hdr.user_id); + + p_buff_ptr += TBFCP_PKT_HDR_SIZE_IN_OCTETS; + n_buff_size -= TBFCP_PKT_HDR_SIZE_IN_OCTETS; + + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tbfcp_attr_t*)pc_item->data)) { + if ((ret = tbfcp_attr_write_with_padding(pc_attr, p_buff_ptr, n_buff_size, &n_size))) { + return ret; + } + p_buff_ptr += n_size; + n_buff_size -= n_size; + } + } + return 0; +} + +// Useful to check TCP stream contains at least a complete BFCP packet +int tbfcp_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete) +{ + if (!pb_is_complete) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pb_is_complete = tsk_false; + if (pc_buff_ptr && n_buff_size >= TBFCP_PKT_HDR_SIZE_IN_OCTETS) { + tsk_size_t n_paylen_in_octets = (tnet_ntohs_2(&pc_buff_ptr[2]) << 2); + *pb_is_complete = ((n_buff_size - TBFCP_PKT_HDR_SIZE_IN_OCTETS) >= n_paylen_in_octets); + } + return 0; +} + +int tbfcp_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tbfcp_pkt_t** pp_pkt) +{ + tsk_bool_t b_is_complete; + tsk_size_t PayloadLengthInOctets; + tbfcp_primitive_t Primitive; + uint32_t ConferenceID; + uint16_t TransactionID, UserID; + int ret, Ver; + if (!pc_buff_ptr || !n_buff_size || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_pkt_is_complete(pc_buff_ptr, n_buff_size, &b_is_complete))) { + return ret; + } + if (!b_is_complete) { + TSK_DEBUG_ERROR("Buffer too short(%u)", n_buff_size); + return -2; + } + Ver = (pc_buff_ptr[0] >> 5) & 0x07; + if (Ver != TBFCP_VERSION) { + TSK_DEBUG_ERROR("Version(%d)<>%d", Ver, TBFCP_VERSION); + return -3; + } + Primitive = (tbfcp_primitive_t)pc_buff_ptr[1]; + PayloadLengthInOctets = (tnet_ntohs_2(&pc_buff_ptr[2]) << 2); + ConferenceID = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]); + TransactionID = tnet_ntohs_2(&pc_buff_ptr[8]); + UserID = tnet_ntohs_2(&pc_buff_ptr[10]); + + if((ret = tbfcp_pkt_create(Primitive, ConferenceID, TransactionID, UserID, pp_pkt))) { + return ret; + } + + if (PayloadLengthInOctets > 0) { + tbfcp_attr_t* p_attr; + tsk_size_t n_consumed_octets; + pc_buff_ptr += TBFCP_PKT_HDR_SIZE_IN_OCTETS; + do { + if ((ret = tbfcp_attr_read(pc_buff_ptr, PayloadLengthInOctets, &n_consumed_octets, &p_attr))) { + return ret; + } + if ((ret = tbfcp_pkt_add_attr((*pp_pkt), &p_attr))) { + TSK_OBJECT_SAFE_FREE((*pp_pkt)); + return ret; + } + PayloadLengthInOctets -= n_consumed_octets; + pc_buff_ptr += n_consumed_octets; + } + while (PayloadLengthInOctets >= TBFCP_ATTR_HDR_SIZE_IN_OCTETS); + } + + return 0; +} + +int tbfcp_pkt_attr_find_at(const struct tbfcp_pkt_s* pc_self, enum tbfcp_attribute_format_e e_format, tsk_size_t u_index, const struct tbfcp_attr_s** ppc_attr) +{ + tsk_size_t _u_index = 0; + const tsk_list_item_t *pc_item; + const struct tbfcp_attr_s* pc_attr; + if (!pc_self || !ppc_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *ppc_attr = tsk_null; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + pc_attr = (const struct tbfcp_attr_s*)pc_item->data; + if (!pc_attr || pc_attr->format != e_format) { + continue; + } + if (_u_index++ >= u_index) { + *ppc_attr = pc_attr; + break; + } + } + return 0; +} + + +static tsk_object_t* tbfcp_pkt_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_pkt_t *p_pkt = (tbfcp_pkt_t *)self; + if (p_pkt) { + p_pkt->f_add_attr = _tbfcp_pkt_add_attr; + if (!(p_pkt->p_list_attrs = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create list"); + return tsk_null; + } + } + return self; +} +static tsk_object_t* tbfcp_pkt_dtor(tsk_object_t * self) +{ + tbfcp_pkt_t *p_pkt = (tbfcp_pkt_t *)self; + if (p_pkt) { + TSK_DEBUG_INFO("*** BFCP Packet destroyed ***"); + TSK_OBJECT_SAFE_FREE(p_pkt->p_list_attrs); + } + + return self; +} +static int tbfcp_pkt_cmp(const tsk_object_t *_pk1, const tsk_object_t *_pk2) +{ + const tbfcp_pkt_t *pc_pk1 = (const tbfcp_pkt_t *)_pk1; + const tbfcp_pkt_t *pc_pk2 = (const tbfcp_pkt_t *)_pk2; + + return (int)(pc_pk1-pc_pk2); +} +static const tsk_object_def_t tbfcp_pkt_def_s = { + sizeof(tbfcp_pkt_t), + tbfcp_pkt_ctor, + tbfcp_pkt_dtor, + tbfcp_pkt_cmp, +}; +const tsk_object_def_t *tbfcp_pkt_def_t = &tbfcp_pkt_def_s; + + +/***** rfc4582 - 5.3.1. FloorRequest *****/ +int tbfcp_pkt_create_FloorRequest_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, tbfcp_pkt_t** pp_self) +{ + int ret; + tbfcp_attr_unsigned16_t* p_floor_id; + if ((ret = tbfcp_pkt_create_FloorRequest(conf_id, transac_id, user_id, pp_self))) { + return ret; + } + if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_ID, kBfcpFieldMYes, floor_id, &p_floor_id))) { + return ret; + } + if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_id))) { + TSK_OBJECT_SAFE_FREE(p_floor_id); + return ret; + } + return 0; +} + +/***** rfc4582 - 5.3.2. FloorRelease *****/ +int tbfcp_pkt_create_FloorRelease_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, tbfcp_pkt_t** pp_self) +{ + int ret; + tbfcp_attr_unsigned16_t* p_floor_req_id; + if ((ret = tbfcp_pkt_create_FloorRelease(conf_id, transac_id, user_id, pp_self))) { + return ret; + } + if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_REQUEST_ID, kBfcpFieldMYes, floor_req_id, &p_floor_req_id))) { + return ret; + } + if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_req_id))) { + TSK_OBJECT_SAFE_FREE(p_floor_req_id); + return ret; + } + return 0; +} + +/**** rfc4582 - 5.3.4. FloorRequestStatus *****/ +int tbfcp_pkt_create_FloorRequestStatus_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_req_id, tbfcp_pkt_t** pp_self) +{ + int ret; + tbfcp_attr_grouped_t* p_floor_req_info; + if ((ret = tbfcp_pkt_create_FloorRequestStatus(conf_id, transac_id, user_id, pp_self))) { + return ret; + } + if ((ret = tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION, kBfcpFieldMNo, floor_req_id, &p_floor_req_info))) { + return ret; + } + if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_floor_req_info))) { + TSK_OBJECT_SAFE_FREE(p_floor_req_info); + return ret; + } + return 0; +} + +/**** 5.3.12. HelloAck ***/ +int tbfcp_pkt_create_HelloAck_2(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, struct tbfcp_pkt_s** pp_self) +{ + tsk_size_t u; + int ret; + tbfcp_attr_octetstring_t *p_supp_attr, *p_supp_prim; + static const uint8_t* kNullOctetStringPtr = tsk_null; + static const tbfcp_primitive_t __supp_prims[] = { + tbfcp_primitive_FloorRequest, + tbfcp_primitive_FloorRelease, + tbfcp_primitive_FloorRequestQuery, + tbfcp_primitive_FloorRequestStatus, + tbfcp_primitive_UserQuery, + tbfcp_primitive_UserStatus, + tbfcp_primitive_FloorQuery, + tbfcp_primitive_FloorStatus, + tbfcp_primitive_ChairAction, + tbfcp_primitive_ChairActionAck, + tbfcp_primitive_Hello, + tbfcp_primitive_HelloAck, + tbfcp_primitive_Error, + }; + static const tsk_size_t __supp_prims_count = sizeof(__supp_prims)/sizeof(__supp_prims[0]); + static const tbfcp_attribute_type_t __supp_attrs[] = { + tbfcp_attribute_type_BENEFICIARY_ID, + tbfcp_attribute_type_FLOOR_ID, + tbfcp_attribute_type_FLOOR_REQUEST_ID, + tbfcp_attribute_type_PRIORITY, + tbfcp_attribute_type_REQUEST_STATUS, + tbfcp_attribute_type_ERROR_CODE, + tbfcp_attribute_type_ERROR_INFO, + tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO, + tbfcp_attribute_type_STATUS_INFO, + tbfcp_attribute_type_SUPPORTED_ATTRIBUTES, + tbfcp_attribute_type_SUPPORTED_PRIMITIVES, + tbfcp_attribute_type_USER_DISPLAY_NAME, + tbfcp_attribute_type_USER_URI, + tbfcp_attribute_type_BENEFICIARY_INFORMATION, + tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION, + tbfcp_attribute_type_REQUESTED_BY_INFORMATION, + tbfcp_attribute_type_FLOOR_REQUEST_STATUS, + tbfcp_attribute_type_OVERALL_REQUEST_STATUS, + }; + static const tsk_size_t __supp_attrs_count = sizeof(__supp_attrs)/sizeof(__supp_attrs[0]); + + if ((ret = tbfcp_pkt_create_HelloAck(conf_id, transac_id, user_id, pp_self))) { + return ret; + } + /* SUPPORTED-ATTRIBUTES */ + if ((ret = tbfcp_attr_octetstring_create(tbfcp_attribute_type_SUPPORTED_ATTRIBUTES, kBfcpFieldMNo, kNullOctetStringPtr, (uint8_t)__supp_attrs_count, &p_supp_attr))) { + return ret; + } + for (u = 0; u < p_supp_attr->OctetStringLength; ++u) { + p_supp_attr->OctetString[u] = (__supp_attrs[u] << 1/*R*/); + } + if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_supp_attr))) { + TSK_OBJECT_SAFE_FREE(p_supp_attr); + return ret; + } + /* SUPPORTED-PRIMITIVES */ + if ((ret = tbfcp_attr_octetstring_create(tbfcp_attribute_type_SUPPORTED_PRIMITIVES, kBfcpFieldMNo, kNullOctetStringPtr, (uint8_t)__supp_prims_count, &p_supp_prim))) { + return ret; + } + for (u = 0; u < p_supp_prim->OctetStringLength; ++u) { + p_supp_prim->OctetString[u] = __supp_prims[u]; + } + if ((ret = tbfcp_pkt_add_attr(*pp_self, (tbfcp_attr_t**)&p_supp_prim))) { + TSK_OBJECT_SAFE_FREE(p_supp_prim); + return ret; + } + return 0; +} + +#if 0 +/***** rfc4582 - 5.3.1. FloorRequest *****/ +static int _tbfcp_pkt_FloorRequest_add_attr(tbfcp_pkt_t* _p_self, tbfcp_attr_t** pp_attr) +{ + tbfcp_pkt_FloorRequest_t* p_self = (tbfcp_pkt_FloorRequest_t*)_p_self; + if (!p_self || !pp_attr || !*pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch ((*pp_attr)->hdr.type) { + SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_FLOOR_ID, struct tbfcp_attr_unsigned16_s*, p_floor_id); + SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_BENEFICIARY_ID, struct tbfcp_attr_unsigned16_s*, p_beneficiary_id); + SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_PARTICIPANT_PROVIDED_INFO, struct tbfcp_attr_octetstring_s*, p_participant_provided_info); + SWITCH_CASE_TAKE_ATTR(tbfcp_attribute_type_PRIORITY, struct tbfcp_attr_octetstring16_s*, p_priority); + } + return _tbfcp_pkt_add_attr(_p_self, pp_attr); +} + +int tbfcp_pkt_FloorRequest_create_empty(tbfcp_pkt_FloorRequest_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_pkt_FloorRequest_def_t; + tbfcp_pkt_FloorRequest_t* p_self; + int ret; + + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_self = tsk_object_new(tbfcp_pkt_FloorRequest_def_t))) { + TSK_DEBUG_ERROR("Failed to create object 'tbfcp_pkt_FloorRequest_def_t'"); + return -2; + } + if ((ret = _tbfcp_pkt_init_empty_FloorRequest(p_self))) { + TSK_OBJECT_SAFE_FREE(p_self); + return ret; + } + *pp_self = p_self; + return 0; +} + +int tbfcp_pkt_FloorRequest_create(uint32_t conf_id, uint16_t transac_id, uint16_t user_id, uint16_t floor_id, tbfcp_pkt_FloorRequest_t** pp_self) +{ + int ret; + + if ((ret = tbfcp_pkt_FloorRequest_create_empty(pp_self))) { + return ret; + } + if ((ret = _tbfcp_pkt_init_FloorRequest((*pp_self), conf_id, transac_id, user_id))) { + TSK_OBJECT_SAFE_FREE((*pp_self)); + return ret; + } + if ((ret = tbfcp_attr_unsigned16_create(tbfcp_attribute_type_FLOOR_ID, kBfcpFieldMYes, floor_id, &(*pp_self)->p_floor_id))) { + TSK_OBJECT_SAFE_FREE((*pp_self)); + return ret; + } + return ret; +} + +static tsk_object_t* tbfcp_pkt_FloorRequest_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_pkt_FloorRequest_t *p_pkt = (tbfcp_pkt_FloorRequest_t *)self; + if (p_pkt) { + TBFCP_PKT(p_pkt)->f_add_attr = _tbfcp_pkt_FloorRequest_add_attr; + } + return self; +} +static tsk_object_t* tbfcp_pkt_FloorRequest_dtor(tsk_object_t * self) +{ + tbfcp_pkt_FloorRequest_t *p_pkt = (tbfcp_pkt_FloorRequest_t *)self; + if (p_pkt) { + TSK_DEBUG_INFO("*** BFCP Packet(FloorRequest) destroyed ***"); + _tbfcp_pkt_deinit(TBFCP_PKT(p_pkt)); // dtor(base) + TSK_OBJECT_SAFE_FREE(p_pkt->p_floor_id); + TSK_OBJECT_SAFE_FREE(p_pkt->p_beneficiary_id); + TSK_OBJECT_SAFE_FREE(p_pkt->p_participant_provided_info); + TSK_OBJECT_SAFE_FREE(p_pkt->p_priority); + } + + return self; +} +static int tbfcp_pkt_FloorRequest_cmp(const tsk_object_t *_pk1, const tsk_object_t *_pk2) +{ + const tbfcp_pkt_FloorRequest_t *pc_pk1 = (const tbfcp_pkt_FloorRequest_t *)_pk1; + const tbfcp_pkt_FloorRequest_t *pc_pk2 = (const tbfcp_pkt_FloorRequest_t *)_pk2; + + return (int)(pc_pk1-pc_pk2); +} +static const tsk_object_def_t tbfcp_pkt_FloorRequest_def_s = { + sizeof(tbfcp_pkt_FloorRequest_t), + tbfcp_pkt_FloorRequest_ctor, + tbfcp_pkt_FloorRequest_dtor, + tbfcp_pkt_FloorRequest_cmp, +}; +const tsk_object_def_t *tbfcp_pkt_FloorRequest_def_t = &tbfcp_pkt_FloorRequest_def_s; +#endif \ No newline at end of file diff --git a/tinyBFCP/src/tbfcp_session.c b/tinyBFCP/src/tbfcp_session.c new file mode 100644 index 0000000..0a2169b --- /dev/null +++ b/tinyBFCP/src/tbfcp_session.c @@ -0,0 +1,1041 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "tinybfcp/tbfcp_session.h" +#include "tinybfcp/tbfcp_pkt.h" +#include "tinybfcp/tbfcp_utils.h" + +#include "tsk_time.h" +#include "tsk_timer.h" +#include "tsk_object.h" +#include "tsk_memory.h" +#include "tsk_safeobj.h" +#include "tsk_debug.h" + +typedef struct tbfcp_udp_pkt_s { + TSK_DECLARE_OBJECT; + struct { + tsk_timer_id_t u_id; + uint64_t u_timeout; + } timer; + tbfcp_pkt_t *p_pkt; +} tbfcp_udp_pkt_t; +typedef tsk_list_t tbfcp_udp_pkts_L_t; + +typedef struct tbfcp_session_s { + TSK_DECLARE_OBJECT; + + tsk_bool_t b_started; + tsk_bool_t b_stopping; + tsk_bool_t b_prepared; + + tbfcp_udp_pkts_L_t *p_list_udp_pkts; + + struct { + tbfcp_session_callback_f f_fun; + struct tbfcp_session_event_xs e; + } cb; + + // Values received from the server in the 200 OK. Attributes from rfc4583 + struct { + uint32_t u_conf_id; + uint16_t u_user_id; + uint16_t u_floor_id; + } + conf_ids; + + enum tbfcp_role_e e_role_local; + enum tbfcp_role_e e_role_remote; + + enum tbfcp_setup_e e_setup_local; + enum tbfcp_setup_e e_setup_remote; + + enum tnet_socket_type_e e_socket_type; + char* p_local_ip; + tnet_port_t u_local_port; + + char* p_local_public_ip; + tnet_port_t u_local_public_port; + + char* p_remote_ip; + tnet_port_t u_remote_port; + struct sockaddr_storage remote_addr; + + struct tnet_nat_ctx_s* p_natt_ctx; + struct tnet_ice_ctx_s* p_ice_ctx; + struct tnet_transport_s* p_transport; + + uint8_t* p_buff_send_ptr; + tsk_size_t u_buff_send_size; + + struct { + tsk_timer_manager_handle_t* ph_global; + tsk_timer_id_t id_T1; // For UDP only + uint64_t u_timeout_T1; + tsk_timer_id_t id_T2; // For UDP only + uint64_t u_timeout_T2; + tsk_timer_id_t id_TcpReconnect; // For TCP/TLS only + uint64_t u_timeout_TcpReconnect; + } timer; + + TSK_DECLARE_SAFEOBJ; +} tbfcp_session_t; + +typedef enum _bfcp_timer_type_e { + _bfcp_timer_type_T1, // draft-ietf-bfcpbis-rfc4582bis-11 - 4.16. Timer Values (8.3.3) - Initial request retransmission timer (0.5s) + _bfcp_timer_type_T2, // draft-ietf-bfcpbis-rfc4582bis-11 - 4.16. Timer Values (8.3.3) - Response retransmission timer (10s) + _bfcp_timer_type_TcpReconnect, // Try to reconnect the TCP/TLS socket every X seconds if unexpectedly disconnected +} +_bfcp_timer_type_t; + +static int _tbfcp_udp_pkt_create(const tbfcp_pkt_t *pc_pkt, tbfcp_udp_pkt_t** pp_pkt); + +static int _tbfcp_session_send_pkt(tbfcp_session_t* p_self, const tbfcp_pkt_t* pc_pkt); +static int _tbfcp_session_send_Hello(struct tbfcp_session_s* p_self); +static int _tbfcp_session_send_HelloAck(struct tbfcp_session_s* p_self, const tbfcp_pkt_t *pc_hello); +static int _tbfcp_session_send_FloorRequest(struct tbfcp_session_s* p_self); +static int _tbfcp_session_process_incoming_pkt(struct tbfcp_session_s* p_self, const tbfcp_pkt_t *pc_pkt); +static int _tbfcp_session_socket_type_make_valid(enum tnet_socket_type_e e_in_st, enum tnet_socket_type_e *pe_out_st); +static int _tbfcp_session_timer_callback(const void* pc_arg, tsk_timer_id_t timer_id); +static int _tbfcp_session_timer_schedule(struct tbfcp_session_s* p_self, _bfcp_timer_type_t e_timer, uint64_t u_timeout); +static int _tbfcp_session_transport_layer_dgram_cb(const tnet_transport_event_t* e); +static int _tbfcp_session_transport_layer_stream_cb(const tnet_transport_event_t* e); + +#define _tbfcp_session_raise(_p_self, _e_type, _pc_pkt) \ + if ((_p_self)->cb.f_fun) { \ + (_p_self)->cb.e.e_type = (_e_type); \ + (_p_self)->cb.e.pc_pkt = (_pc_pkt); \ + (_p_self)->cb.f_fun(&_p_self->cb.e); \ + } +#define _tbfcp_session_raise_inf_inc_msg(_p_self, _pc_pkt) _tbfcp_session_raise(_p_self, tbfcp_session_event_type_inf_inc_msg, _pc_pkt) +#define _tbfcp_session_raise_err_send_timedout(_p_self, _pc_pkt) _tbfcp_session_raise(_p_self, tbfcp_session_event_type_err_send_timedout, _pc_pkt) + +static int __pred_find_udp_pkt_by_timer(const tsk_list_item_t *item, const void *u64_id) { + if (item && item->data) { + return (int)(((const struct tbfcp_udp_pkt_s *)item->data)->timer.u_id - *((const uint64_t*)u64_id)); + } + return -1; +} +static int __pred_find_udp_pkt_by_transac_id(const tsk_list_item_t *item, const void *u16_transac_id) { + if (item && item->data) { + return (int)(((const struct tbfcp_udp_pkt_s *)item->data)->p_pkt->hdr.transac_id - *((const uint16_t*)u16_transac_id)); + } + return -1; +} + +int tbfcp_session_create(tnet_socket_type_t e_socket_type, const char* pc_local_ip, tbfcp_session_t** pp_self) +{ + extern const tsk_object_def_t *tbfcp_session_def_t; + int ret; + tnet_socket_type_t e_st; + tbfcp_session_t* p_self; + + if (!pp_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = _tbfcp_session_socket_type_make_valid(e_socket_type, &e_st))) { + return ret; + } + if (!(p_self = tsk_object_new(tbfcp_session_def_t))) { + TSK_DEBUG_ERROR("Failed to create 'tbfcp_session_def_t' object"); + return -2; + } + p_self->e_socket_type = e_st; + tsk_strupdate(&p_self->p_local_ip, pc_local_ip); + *pp_self = p_self; + return 0; +} + +int tbfcp_session_create_2(struct tnet_ice_ctx_s* p_ice_ctx, tbfcp_session_t** pp_self) +{ + tnet_socket_type_t e_st; + const char* pc_local_ip; + int ret; + if (!pp_self || !p_ice_ctx) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // TODO: ICE expect RTP and RTCP comp-ids only + TSK_DEBUG_ERROR("Not supported yet"); + return -2; + + // TODO: For now ICE works with UDP (and DTLS) only + e_st = tnet_ice_ctx_use_ipv6(p_ice_ctx) ? tnet_socket_type_udp_ipv4 : tnet_socket_type_udp_ipv6; + pc_local_ip = tnet_ice_ctx_use_ipv6(p_ice_ctx) ? "::1" : "127.0.0.1"; + if ((ret = _tbfcp_session_socket_type_make_valid(e_st, &e_st))) { + return ret; + } + if ((ret = tbfcp_session_create(e_st, pc_local_ip, pp_self))) { + return ret; + } + (*pp_self)->p_ice_ctx = tsk_object_ref(p_ice_ctx); + return 0; +} + +int tbfcp_session_set_callback(struct tbfcp_session_s* p_self, tbfcp_session_callback_f f_fun, const void* pc_usr_data) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + p_self->cb.f_fun = f_fun; + p_self->cb.e.pc_usr_data = pc_usr_data; + return 0; +} + +int tbfcp_session_set_ice_ctx(tbfcp_session_t* p_self, struct tnet_ice_ctx_s* p_ice_ctx) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + TSK_OBJECT_SAFE_FREE(p_self->p_ice_ctx); + if (p_ice_ctx) { + p_self->p_ice_ctx = tsk_object_ref(p_ice_ctx); + } + return 0; +} + +int tbfcp_session_prepare(tbfcp_session_t* p_self) +{ + int ret = 0; + const char *bfcp_local_ip; + tnet_port_t bfcp_local_port; + + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + if (p_self->b_prepared) { + TSK_DEBUG_INFO("BFCP session already prepared"); + goto bail; + } + if (p_self->p_transport) { + TSK_DEBUG_ERROR("BFCP session already has a transport. Unexpected."); + ret = -2; + goto bail; + } + + bfcp_local_ip = TNET_SOCKET_HOST_ANY; + bfcp_local_port = TNET_SOCKET_PORT_ANY; + + /*if (p_self->p_ice_ctx) { + // Get Sockets when the transport is started + bfcp_local_ip = tnet_ice_ctx_use_ipv6(p_self->p_ice_ctx) ? "::1" : "127.0.0.1"; + } + else*/ { + // create transport + if (!p_self->p_transport && !(p_self->p_transport = tnet_transport_create(p_self->p_local_ip, p_self->u_local_port, p_self->e_socket_type, kBfcpTransportFriendlyName))) { + TSK_DEBUG_ERROR("Failed to create %s Transport", kBfcpTransportFriendlyName); + return -3; + } + // set transport callback + if ((ret = tnet_transport_set_callback(p_self->p_transport, TNET_SOCKET_TYPE_IS_DGRAM(p_self->e_socket_type) ? _tbfcp_session_transport_layer_dgram_cb : _tbfcp_session_transport_layer_stream_cb, p_self))) { + goto bail; + } + bfcp_local_ip = p_self->p_transport->master->ip; + bfcp_local_port = p_self->p_transport->master->port; + } + + tsk_strupdate(&p_self->p_local_public_ip, bfcp_local_ip); + p_self->u_local_public_port = bfcp_local_port; + + p_self->b_prepared = tsk_true; + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_start(tbfcp_session_t* p_self) +{ + int ret; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + if (p_self->b_started) { + TSK_DEBUG_INFO("BFCP session already started"); + ret = 0; + goto bail; + } + + if (!p_self->b_prepared) { + TSK_DEBUG_ERROR("BFCP session not prepared yet"); + ret = -2; + goto bail; + } + + // start global timer manager - nothing will be done if already started by another component + if ((ret = tsk_timer_manager_start(p_self->timer.ph_global))) { + TSK_DEBUG_ERROR("Failed to start timer"); + goto bail; + } + + // check remote IP address validity + if ((tsk_striequals(p_self->p_remote_ip, "0.0.0.0") || tsk_striequals(p_self->p_remote_ip, "::"))) { // most likely loopback testing + tnet_ip_t source = {0}; + tsk_bool_t updated = tsk_false; + if (p_self->p_transport && p_self->p_transport->master) { + updated = (tnet_getbestsource(p_self->p_transport->master->ip, p_self->p_transport->master->port, p_self->p_transport->master->type, &source) == 0); + } + // Not allowed to send data to "0.0.0.0" + TSK_DEBUG_INFO("BFCP remote IP contains not allowed value ...changing to '%s'", updated ? source : "oops"); + if (updated) { + tsk_strupdate(&p_self->p_remote_ip, source); + } + } + // init remote remote addr + if ((ret = tnet_sockaddr_init(p_self->p_remote_ip, p_self->u_remote_port, p_self->p_transport->master->type, &p_self->remote_addr))) { + tnet_transport_shutdown(p_self->p_transport); + TSK_OBJECT_SAFE_FREE(p_self->p_transport); + TSK_DEBUG_ERROR("Invalid BFCP host:port [%s:%u]", p_self->p_remote_ip, p_self->u_remote_port); + goto bail; + } + if ((ret = tnet_transport_set_natt_ctx(p_self->p_transport, p_self->p_natt_ctx))) { + TSK_DEBUG_ERROR("Failed to start to set NATT ctx for the %s transport", kBfcpTransportFriendlyName); + goto bail; + } + + // start the transport + if ((ret = tnet_transport_start(p_self->p_transport))) { + TSK_DEBUG_ERROR("Failed to start the %s transport", kBfcpTransportFriendlyName); + goto bail; + } + + p_self->b_started = tsk_true; + + // Send hello now if UDP/DTLS. Otherwise (TCP/TLS), wait for the connection to complete. + //if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->e_socket_type)) { + // if ((ret = _tbfcp_session_send_Hello(p_self))) { + // goto bail; + // } + //} + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_pause(tbfcp_session_t* p_self) +{ + int ret = 0; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + goto bail; + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_stop(tbfcp_session_t* p_self) +{ + int ret = 0; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // FIXME: send FloorRelease if a FloorRequest is pending + + // lock() + tsk_safeobj_lock(p_self); + + // stop the session if not already done + if (!p_self->b_started) { + TSK_DEBUG_INFO("BFCP session already stopped"); + goto bail; + } + + // remove all pending udp packets + tsk_list_clear_items(p_self->p_list_udp_pkts); + + p_self->b_stopping = tsk_true; + // this is a global timer shared by many components -> stopping it won't remove + // all scheduled items as it could continue running if still used + if (TSK_TIMER_ID_IS_VALID(p_self->timer.id_T1)) { + tsk_timer_manager_cancel(p_self->timer.ph_global, p_self->timer.id_T1); + p_self->timer.id_T1 = TSK_INVALID_TIMER_ID; + } + if (TSK_TIMER_ID_IS_VALID(p_self->timer.id_T2)) { + tsk_timer_manager_cancel(p_self->timer.ph_global, p_self->timer.id_T2); + p_self->timer.id_T2 = TSK_INVALID_TIMER_ID; + } + if (TSK_TIMER_ID_IS_VALID(p_self->timer.id_TcpReconnect)) { + tsk_timer_manager_cancel(p_self->timer.ph_global, p_self->timer.id_TcpReconnect); + p_self->timer.id_TcpReconnect = TSK_INVALID_TIMER_ID; + } + + // free transport to force next call to start() to create new one with new sockets + if (p_self->p_transport) { + tnet_transport_shutdown(p_self->p_transport); + TSK_OBJECT_SAFE_FREE(p_self->p_transport); + } + + p_self->b_started = tsk_false; + p_self->b_stopping = tsk_false; + p_self->b_prepared = tsk_false; + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_set_natt_ctx(tbfcp_session_t* p_self, struct tnet_nat_ctx_s* p_natt_ctx) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + TSK_OBJECT_SAFE_FREE(p_self->p_natt_ctx); + p_self->p_natt_ctx = tsk_object_ref(p_natt_ctx); + return 0; +} + +int tbfcp_session_set_remote_address(tbfcp_session_t* p_self, const char* pc_ip, tnet_port_t u_port) +{ + if (!p_self || !pc_ip /*|| u_port < 1024*/) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // if ICE is enabled then, these values will be updated when the session start()s and call ice_init() + tsk_strupdate(&p_self->p_remote_ip, pc_ip); + p_self->u_remote_port = u_port; + return 0; +} + +int tbfcp_session_set_remote_role(tbfcp_session_t* p_self, enum tbfcp_role_e e_role_remote) +{ + tsk_bool_t b_is_role_acceptable; + int ret; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_utils_is_role_acceptable(p_self->e_role_local, e_role_remote, &b_is_role_acceptable))) { + return ret; + } + if (!b_is_role_acceptable) { + TSK_DEBUG_ERROR("%d not acceptable as remote role because local role = %d", e_role_remote, p_self->e_role_local); + return -2; + } + p_self->e_role_remote = e_role_remote; + return 0; +} + +int tbfcp_session_set_remote_setup(struct tbfcp_session_s* p_self, enum tbfcp_setup_e e_setup_remote) +{ + tsk_bool_t b_is_setup_acceptable; + int ret; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_utils_is_setup_acceptable(p_self->e_setup_local, e_setup_remote, &b_is_setup_acceptable))) { + return ret; + } + if (!b_is_setup_acceptable) { + TSK_DEBUG_ERROR("%d not acceptable as remote setup because local setup = %d", e_setup_remote, p_self->e_setup_local); + return -2; + } + p_self->e_setup_remote = e_setup_remote; + return 0; +} + +int tbfcp_session_set_conf_ids(tbfcp_session_t* p_self, uint32_t u_conf_id, uint16_t u_user_id, uint16_t u_floor_id) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + p_self->conf_ids.u_conf_id = u_conf_id; + p_self->conf_ids.u_user_id = u_user_id; + p_self->conf_ids.u_floor_id = u_floor_id; + return 0; +} + +int tbfcp_session_get_profile(const tbfcp_session_t* pc_self, const char** ppc_profile) +{ + if (!pc_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + return tbfcp_utils_get_profile(pc_self->e_socket_type, ppc_profile); +} + +int tbfcp_session_get_local_role(const tbfcp_session_t* pc_self, enum tbfcp_role_e *pe_role_local) +{ + if (!pc_self || !pe_role_local) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pe_role_local = pc_self->e_role_local; + return 0; +} + +int tbfcp_session_get_local_setup(const struct tbfcp_session_s* pc_self, enum tbfcp_setup_e *pe_setup_local) +{ + if (!pc_self || !pe_setup_local) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pe_setup_local = pc_self->e_setup_local; + return 0; +} + +int tbfcp_session_get_local_address(const tbfcp_session_t* pc_self, const char** ppc_ip, tnet_port_t *pu_port) +{ + if (!pc_self || !ppc_ip || !pu_port) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *ppc_ip = pc_self->p_local_public_ip; + *pu_port = pc_self->u_local_public_port; + return 0; +} + +int tbfcp_session_create_pkt_Hello(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt) +{ + int ret; + if (!p_self || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // lock() + tsk_safeobj_lock(p_self); + if ((ret = tbfcp_pkt_create_Hello(p_self->conf_ids.u_conf_id, tbfcp_utils_rand_u16(), p_self->conf_ids.u_user_id, pp_pkt))) { + goto bail; + } + +bail: + // lock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_create_pkt_FloorRequest(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt) +{ + int ret; + if (!p_self || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // lock() + tsk_safeobj_lock(p_self); + if ((ret = tbfcp_pkt_create_FloorRequest_2(p_self->conf_ids.u_conf_id, tbfcp_utils_rand_u16(), p_self->conf_ids.u_user_id, p_self->conf_ids.u_floor_id, pp_pkt))) { + goto bail; + } + +bail: + // lock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_create_pkt_FloorRelease(struct tbfcp_session_s* p_self, struct tbfcp_pkt_s** pp_pkt) +{ + int ret; + if (!p_self || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // lock() + tsk_safeobj_lock(p_self); + if ((ret = tbfcp_pkt_create_FloorRelease_2(p_self->conf_ids.u_conf_id, tbfcp_utils_rand_u16(), p_self->conf_ids.u_user_id, p_self->conf_ids.u_floor_id, pp_pkt))) { + goto bail; + } + +bail: + // lock() + tsk_safeobj_unlock(p_self); + return ret; +} + +static int _tbfcp_session_send_buff(tbfcp_session_t* p_self, const void* pc_buff_ptr, tsk_size_t u_buff_size) +{ + int ret = 0; + tsk_size_t u_sent_bytes = 0; + if (!p_self || !pc_buff_ptr || !u_buff_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + if (!p_self->b_started) { + TSK_DEBUG_ERROR("BFCP session not started"); + ret = -2; + goto bail; + } + + if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->e_socket_type)) { + u_sent_bytes = tnet_transport_sendto(p_self->p_transport, p_self->p_transport->master->fd, (const struct sockaddr *)&p_self->remote_addr, pc_buff_ptr, u_buff_size); + } + else { + TSK_DEBUG_ERROR("Not implemented yet"); + ret = -3; + goto bail; + } + + if (u_sent_bytes != u_buff_size) { + TSK_DEBUG_ERROR("Failed to send %u bytes. Only %u sent", u_buff_size, u_sent_bytes); + ret = -2; + goto bail; + } + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int tbfcp_session_send_pkt(tbfcp_session_t* p_self, const tbfcp_pkt_t* pc_pkt) +{ + int ret = 0; + tbfcp_udp_pkt_t *p_udp_pkt = tsk_null; + if (!p_self || !pc_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->e_socket_type)) { + const tsk_list_item_t* pc_item = tsk_list_find_item_by_pred(p_self->p_list_udp_pkts, __pred_find_udp_pkt_by_transac_id, &pc_pkt->hdr.transac_id); + if (pc_item) { + p_udp_pkt = tsk_object_ref(TSK_OBJECT(pc_item->data)); + } else { + tbfcp_udp_pkt_t *_p_udp_pkt = tsk_null; + if ((ret = _tbfcp_udp_pkt_create(pc_pkt, &_p_udp_pkt))) { + goto bail; + } + p_udp_pkt = tsk_object_ref(_p_udp_pkt); + tsk_list_push_back_data(p_self->p_list_udp_pkts, (void**)&_p_udp_pkt); + } + } + else { + } + + if ((ret = _tbfcp_session_send_pkt(p_self, pc_pkt))) { + goto bail; + } + if (p_udp_pkt) { + p_udp_pkt->timer.u_id = tsk_timer_manager_schedule(p_self->timer.ph_global, p_udp_pkt->timer.u_timeout, _tbfcp_session_timer_callback, p_self); + p_udp_pkt->timer.u_timeout += kBfcpTimerT1; + } + +bail: + TSK_OBJECT_SAFE_FREE(p_udp_pkt); + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int _tbfcp_session_send_pkt(tbfcp_session_t* p_self, const tbfcp_pkt_t* pc_pkt) +{ + int ret; + tsk_size_t u_min_size; + if (!p_self || !pc_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + if (!p_self->b_started) { + TSK_DEBUG_ERROR("BFCP session not started"); + ret = -2; + goto bail; + } + if ((ret = tbfcp_pkt_get_size_in_octetunits_with_padding(pc_pkt, &u_min_size))) { + goto bail; + } + u_min_size += kBfcpBuffMinPad; + if (p_self->u_buff_send_size < u_min_size) { + if (!(p_self->p_buff_send_ptr = tsk_realloc(p_self->p_buff_send_ptr, u_min_size))) { + TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", u_min_size); + ret = -3; + p_self->u_buff_send_size = 0; + goto bail; + } + p_self->u_buff_send_size = u_min_size; + } + + if ((ret = tbfcp_pkt_write_with_padding(pc_pkt, p_self->p_buff_send_ptr, p_self->u_buff_send_size, &u_min_size))) { + goto bail; + } + if ((ret = _tbfcp_session_send_buff(p_self, p_self->p_buff_send_ptr, u_min_size))) { + goto bail; + } + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +int _tbfcp_session_send_Hello(tbfcp_session_t* p_self) +{ + tbfcp_pkt_t* p_pkt = tsk_null; + int ret; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_pkt_create_Hello(p_self->conf_ids.u_conf_id, tbfcp_utils_rand_u16(), p_self->conf_ids.u_user_id, &p_pkt))) { + goto bail; + } + if ((ret = tbfcp_session_send_pkt(p_self, p_pkt))) { + goto bail; + } + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + return ret; +} + +int _tbfcp_session_send_HelloAck(tbfcp_session_t* p_self, const tbfcp_pkt_t *pc_hello) +{ + tbfcp_pkt_t* p_pkt = tsk_null; + int ret; + if (!p_self || !pc_hello) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_pkt_create_HelloAck_2(pc_hello->hdr.conf_id, pc_hello->hdr.transac_id, pc_hello->hdr.user_id, &p_pkt))) { + goto bail; + } + if ((ret = _tbfcp_session_send_pkt(p_self, p_pkt))) { + goto bail; + } + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + return ret; +} + +static int _tbfcp_session_send_FloorRequest(tbfcp_session_t* p_self) +{ + tbfcp_pkt_t* p_pkt = tsk_null; + int ret; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tbfcp_pkt_create_FloorRequest_2(p_self->conf_ids.u_conf_id, tbfcp_utils_rand_u16(), p_self->conf_ids.u_user_id, p_self->conf_ids.u_floor_id, &p_pkt))) { + goto bail; + } + if ((ret = tbfcp_session_send_pkt(p_self, p_pkt))) { + goto bail; + } + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + return ret; +} + +static int _tbfcp_session_process_incoming_pkt(tbfcp_session_t* p_self, const tbfcp_pkt_t *pc_pkt) +{ + int ret = 0; + if (!p_self || !pc_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // lock() + tsk_safeobj_lock(p_self); + + switch (pc_pkt->hdr.primitive) { + case tbfcp_primitive_Hello: + if ((ret = _tbfcp_session_send_HelloAck(p_self, pc_pkt))) { + goto bail; + } + break; + case tbfcp_primitive_HelloAck: + default: + break; + } + + // raise event + _tbfcp_session_raise_inf_inc_msg(p_self, pc_pkt); + // remove request + tsk_list_remove_item_by_pred(p_self->p_list_udp_pkts, __pred_find_udp_pkt_by_transac_id, &pc_pkt->hdr.transac_id); + +bail: + // unlock() + tsk_safeobj_unlock(p_self); + return ret; +} + +// clear junks (e.g. IPSec) +static int _tbfcp_session_socket_type_make_valid(enum tnet_socket_type_e e_in_st, enum tnet_socket_type_e *pe_out_st) +{ + if (!pe_out_st) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (TNET_SOCKET_TYPE_IS_DTLS(e_in_st) || TNET_SOCKET_TYPE_IS_UDP(e_in_st) || TNET_SOCKET_TYPE_IS_TLS(e_in_st) || TNET_SOCKET_TYPE_IS_TCP(e_in_st)) { + *pe_out_st = e_in_st; + } + else { + *pe_out_st = kBfcpTransportDefault; + } + return 0; +} + +static int _tbfcp_session_timer_schedule(tbfcp_session_t* p_self, _bfcp_timer_type_t e_timer, uint64_t u_timeout) +{ + int ret = 0; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(p_self); // must + switch (e_timer) { + case _bfcp_timer_type_T1: + if (!TSK_TIMER_ID_IS_VALID(p_self->timer.id_T1)) { + p_self->timer.id_T1 = tsk_timer_mgr_global_schedule(u_timeout, _tbfcp_session_timer_callback, p_self); + } + else { + TSK_DEBUG_ERROR("T1 timer is still valid"); + ret = -3; + } + break; + case _bfcp_timer_type_T2: + if (!TSK_TIMER_ID_IS_VALID(p_self->timer.id_T2)) { + p_self->timer.id_T2 = tsk_timer_mgr_global_schedule(u_timeout, _tbfcp_session_timer_callback, p_self); + } + else { + TSK_DEBUG_ERROR("T2 timer is still valid"); + ret = -3; + } + break; + case _bfcp_timer_type_TcpReconnect: + if (!TSK_TIMER_ID_IS_VALID(p_self->timer.id_TcpReconnect)) { + p_self->timer.id_TcpReconnect = tsk_timer_mgr_global_schedule(u_timeout, _tbfcp_session_timer_callback, p_self); + } + else { + TSK_DEBUG_ERROR("TcpReconnect timer is still valid"); + ret = -3; + } + break; + default: + TSK_DEBUG_ERROR("%d not valid BFCP timer", e_timer); + ret = -2; + break; + } + tsk_safeobj_unlock(p_self); + return ret; +} + +static int _tbfcp_session_timer_callback(const void* pc_arg, tsk_timer_id_t timer_id) +{ + tbfcp_session_t* p_session = (tbfcp_session_t*)pc_arg; + const tsk_list_item_t* pc_item; + tsk_safeobj_lock(p_session); // must + if (!p_session->b_started) goto bail; + pc_item = tsk_list_find_item_by_pred(p_session->p_list_udp_pkts, __pred_find_udp_pkt_by_timer, &timer_id); + if (pc_item) { + tbfcp_udp_pkt_t* pc_udp_pkt = (tbfcp_udp_pkt_t*)pc_item->data; + if (pc_udp_pkt->timer.u_timeout <= kBfcpTimerT1Max) { + tbfcp_session_send_pkt(p_session, pc_udp_pkt->p_pkt); + } + else { + // raise event + _tbfcp_session_raise_err_send_timedout(p_session, pc_udp_pkt->p_pkt); + // remove pkt + tsk_list_remove_item_by_pred(p_session->p_list_udp_pkts, __pred_find_udp_pkt_by_timer, &timer_id); + } + } +#if 0 + if (p_session->timer.id_T1 == timer_id) { + p_session->timer.id_T1 = TSK_INVALID_TIMER_ID; + // OnExpire(session, EVENT_BYE); + } + else if (p_session->timer.id_T2 == timer_id) { + p_session->timer.id_T2 = TSK_INVALID_TIMER_ID; + // OnExpire(session, EVENT_REPORT); + } +#endif +bail: + tsk_safeobj_unlock(p_session); + return 0; +} + +static int _tbfcp_session_transport_layer_dgram_cb(const tnet_transport_event_t* e) +{ + tbfcp_session_t* p_session = (tbfcp_session_t*)e->callback_data; + int ret; + tbfcp_pkt_t* p_pkt = tsk_null; + switch(e->type){ + case event_data: { + break; + } + case event_closed: + case event_connected: + default:{ + return 0; + } + } + + if ((ret = tbfcp_pkt_read(e->data, e->size, &p_pkt))) { + goto bail; + } + if ((ret = _tbfcp_session_process_incoming_pkt(p_session, p_pkt))) { + goto bail; + } + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + return ret; +} + +static int _tbfcp_session_transport_layer_stream_cb(const tnet_transport_event_t* e) +{ + // tbfcp_session_t* p_session = (tbfcp_session_t*)e->callback_data; + TSK_DEBUG_ERROR("Not implemented yet"); + return -1; +} + +static tsk_object_t* tbfcp_session_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_session_t *p_session = (tbfcp_session_t *)self; + if (p_session) { + p_session->timer.id_T1 = TSK_INVALID_TIMER_ID; + p_session->timer.id_T2 = TSK_INVALID_TIMER_ID; + if (!(p_session->p_list_udp_pkts = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create en empty list"); + return tsk_null; + } + // get a handle for the global timer manager + if (!(p_session->timer.ph_global = tsk_timer_mgr_global_ref())) { + TSK_DEBUG_ERROR("Failed to get a reference to the global timer"); + return tsk_null; + } + p_session->u_local_port = TNET_SOCKET_PORT_ANY; + p_session->e_role_local = kBfcpRoleDefault; + p_session->e_setup_local = kBfcpSetupDefault; + tsk_safeobj_init(p_session); + } + return self; +} +static tsk_object_t* tbfcp_session_dtor(tsk_object_t * self) +{ + tbfcp_session_t *p_session = (tbfcp_session_t *)self; + if (p_session) { + TSK_DEBUG_INFO("*** BFCP session destroyed ***"); + // stop the session if not already done + tbfcp_session_stop(p_session); + // release the handle for the global timer manager + tsk_timer_mgr_global_unref(&p_session->timer.ph_global); + + TSK_FREE(p_session->p_local_ip); + TSK_FREE(p_session->p_local_public_ip); + TSK_FREE(p_session->p_remote_ip); + TSK_FREE(p_session->p_buff_send_ptr); + TSK_OBJECT_SAFE_FREE(p_session->p_natt_ctx); + TSK_OBJECT_SAFE_FREE(p_session->p_ice_ctx); + TSK_OBJECT_SAFE_FREE(p_session->p_transport); + TSK_OBJECT_SAFE_FREE(p_session->p_list_udp_pkts); + tsk_safeobj_deinit(p_session); + } + + return self; +} +static int tbfcp_session_cmp(const tsk_object_t *_pss1, const tsk_object_t *_pss2) +{ + const tbfcp_session_t *pc_ss1 = (const tbfcp_session_t *)_pss1; + const tbfcp_session_t *pc_ss2 = (const tbfcp_session_t *)_pss2; + return (int)(pc_ss1 - pc_ss2); +} +static const tsk_object_def_t tbfcp_session_def_s = { + sizeof(tbfcp_session_t), + tbfcp_session_ctor, + tbfcp_session_dtor, + tbfcp_session_cmp, +}; +const tsk_object_def_t *tbfcp_session_def_t = &tbfcp_session_def_s; + + + +static int _tbfcp_udp_pkt_create(const tbfcp_pkt_t *pc_pkt, tbfcp_udp_pkt_t** pp_pkt) +{ + extern const tsk_object_def_t *tbfcp_udp_pkt_def_t; + if (!pc_pkt || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pp_pkt = tsk_object_new(tbfcp_udp_pkt_def_t); + if (!(*pp_pkt)) { + TSK_DEBUG_ERROR("Failed to create object with type= 'tbfcp_udp_pkt_def_t'"); + return -2; + } + (*pp_pkt)->p_pkt = tsk_object_ref(TSK_OBJECT(pc_pkt)); + return 0; +} + +static tsk_object_t* tbfcp_udp_pkt_ctor(tsk_object_t * self, va_list * app) +{ + tbfcp_udp_pkt_t *p_udp_pkt = (tbfcp_udp_pkt_t *)self; + if (p_udp_pkt) { + p_udp_pkt->timer.u_timeout = kBfcpTimerT1; + p_udp_pkt->timer.u_id = TSK_INVALID_TIMER_ID; + } + return self; +} +static tsk_object_t* tbfcp_udp_pkt_dtor(tsk_object_t * self) +{ + tbfcp_udp_pkt_t *p_udp_pkt = (tbfcp_udp_pkt_t *)self; + if (p_udp_pkt) { + TSK_OBJECT_SAFE_FREE(p_udp_pkt->p_pkt); + TSK_DEBUG_INFO("*** tbfcp_udp_pkt_t destroyed ***"); + } + return self; +} +static const tsk_object_def_t tbfcp_udp_pkt_def_s = { + sizeof(tbfcp_udp_pkt_t), + tbfcp_udp_pkt_ctor, + tbfcp_udp_pkt_dtor, + tsk_null, +}; +const tsk_object_def_t *tbfcp_udp_pkt_def_t = &tbfcp_udp_pkt_def_s; diff --git a/tinyBFCP/src/tbfcp_utils.c b/tinyBFCP/src/tbfcp_utils.c new file mode 100644 index 0000000..7c0ff25 --- /dev/null +++ b/tinyBFCP/src/tbfcp_utils.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "tinybfcp/tbfcp_utils.h" + +#include "tinynet.h" +#include "tsk_string.h" +#include "tsk_debug.h" + +int tbfcp_utils_get_profile(enum tnet_socket_type_e e_socket_type, const char** ppc_profile) +{ + if (!ppc_profile) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (TNET_SOCKET_TYPE_IS_DTLS(e_socket_type)) { + *ppc_profile = kBfcpProfileDTLS; + return 0; + } + if (TNET_SOCKET_TYPE_IS_UDP(e_socket_type)) { + *ppc_profile = kBfcpProfileUDP; + return 0; + } + if (TNET_SOCKET_TYPE_IS_TLS(e_socket_type)) { + *ppc_profile = kBfcpProfileTLS; + return 0; + } + if (TNET_SOCKET_TYPE_IS_TCP(e_socket_type)) { + *ppc_profile = kBfcpProfileTCP; + return 0; + } + TSK_DEBUG_ERROR("%d not supported as valid socket type for BFCP sessions", e_socket_type); + return -2; +} + +int tbfcp_utils_get_role(enum tbfcp_role_e e_role, const char** ppc_role) +{ + if (!ppc_role) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (e_role) { + case tbfcp_role_c_only: + *ppc_role = kBfcpRoleC; + return 0; + case tbfcp_role_s_only: + *ppc_role = kBfcpRoleS; + return 0; + case tbfcp_role_c_s: + *ppc_role = kBfcpRoleCS; + return 0; + default: + TSK_DEBUG_ERROR("%d not valid BFCP role", e_role); + return -2; + } +} + +int tbfcp_utils_parse_role(const char* pc_role, enum tbfcp_role_e* pe_role) +{ + if (!pc_role || !pe_role) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (tsk_striequals(pc_role, kBfcpRoleC)) { + *pe_role = tbfcp_role_c_only; + return 0; + } + if (tsk_striequals(pc_role, kBfcpRoleS)) { + *pe_role = tbfcp_role_s_only; + return 0; + } + if (tsk_striequals(pc_role, kBfcpRoleCS)) { + *pe_role = tbfcp_role_c_s; + return 0; + } + TSK_DEBUG_ERROR("%s not valid BFCP role", pc_role); + return -2; +} + +int tbfcp_utils_get_setup(enum tbfcp_role_e e_setup, const char** ppc_setup) +{ + if (!ppc_setup) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (e_setup) { + case tbfcp_setup_actpass: + *ppc_setup = kBfcpSetupActPass; + return 0; + case tbfcp_setup_active: + *ppc_setup = kBfcpSetupActive; + return 0; + case tbfcp_setup_passive: + *ppc_setup = kBfcpSetupPassive; + return 0; + default: + TSK_DEBUG_ERROR("%d not valid BFCP setup", e_setup); + return -2; + } +} + +int tbfcp_utils_parse_setup(const char* pc_setup, enum tbfcp_setup_e* pe_setup) +{ + if (!pc_setup || !pe_setup) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (tsk_striequals(pc_setup, kBfcpSetupActPass)) { + *pe_setup = tbfcp_setup_actpass; + return 0; + } + if (tsk_striequals(pc_setup, kBfcpSetupActive)) { + *pe_setup = tbfcp_setup_active; + return 0; + } + if (tsk_striequals(pc_setup, kBfcpSetupPassive)) { + *pe_setup = tbfcp_setup_passive; + return 0; + } + TSK_DEBUG_ERROR("%s not valid BFCP setup", pc_setup); + return -2; +} + +int tbfcp_utils_is_role_acceptable(enum tbfcp_role_e e_role_local, enum tbfcp_role_e e_role_proposed, tsk_bool_t *pb_acceptable) +{ + if (!pb_acceptable) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (e_role_local) { + case tbfcp_role_c_only: + *pb_acceptable = (e_role_proposed == tbfcp_role_s_only || e_role_proposed == tbfcp_role_c_s); + break; + case tbfcp_role_s_only: + *pb_acceptable = (e_role_proposed == tbfcp_role_c_only || e_role_proposed == tbfcp_role_c_s); + break; + case tbfcp_role_c_s: + *pb_acceptable = tsk_true; + break; + default: + *pb_acceptable = tsk_false; + break; + } + return 0; +} + +int tbfcp_utils_is_setup_acceptable(enum tbfcp_setup_e e_setup_local, enum tbfcp_setup_e e_setup_proposed, tsk_bool_t *pb_acceptable) +{ + if (!pb_acceptable) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (e_setup_local) { + case tbfcp_setup_active: + *pb_acceptable = (e_setup_proposed == tbfcp_setup_passive || e_setup_proposed == tbfcp_setup_actpass); + break; + case tbfcp_setup_passive: + *pb_acceptable = (e_setup_proposed == tbfcp_setup_active || e_setup_proposed == tbfcp_setup_actpass); + break; + case tbfcp_setup_actpass: + *pb_acceptable = tsk_true; + break; + default: + *pb_acceptable = tsk_false; + break; + } + return 0; +} + +uint16_t tbfcp_utils_rand_u16() +{ + static long __rand = 0; + long num = tsk_atomic_inc(&__rand); + return ((num % 0xFF) << 8) | (tsk_time_epoch() % 0xFF); +} diff --git a/tinyBFCP/test/stdafx.c b/tinyBFCP/test/stdafx.c new file mode 100644 index 0000000..68df985 --- /dev/null +++ b/tinyBFCP/test/stdafx.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/tinyBFCP/test/stdafx.h b/tinyBFCP/test/stdafx.h new file mode 100644 index 0000000..d747cb8 --- /dev/null +++ b/tinyBFCP/test/stdafx.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TEST_TINYBFCP_STDAFX_H +#define TEST_TINYBFCP_STDAFX_H + +#include "targetver.h" + +#include + +#if (defined(_WIN32) || defined(WIN32) || defined(_WIN32_WCE)) && !defined(__SYMBIAN32__) +#include +#endif + +// TODO: reference additional headers your program requires here +#endif /* TEST_TINYHTTP_STDAFX_H */ diff --git a/tinyBFCP/test/targetver.h b/tinyBFCP/test/targetver.h new file mode 100644 index 0000000..0bebc33 --- /dev/null +++ b/tinyBFCP/test/targetver.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef _TEST_TINYBFCP_VER +#define _TEST_TINYBFCP_VER + +#if (defined(_WIN32) || defined(WIN32) || defined(_WIN32_WCE)) && !defined(__SYMBIAN32__) +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#endif + +#endif diff --git a/tinyBFCP/test/test.c b/tinyBFCP/test/test.c new file mode 100644 index 0000000..4ec5bdf --- /dev/null +++ b/tinyBFCP/test/test.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stdafx.h" +#include +#include +#include + +#include "tinynet.h" +#include "tsk.h" + +#define kConfId 1927375685 +#define kTransacId 32871 +#define kUserId 18177 +#define kFloorId 10665 +#define kFloorReqId 2 +#define kReqStatus 3 // Granted +#define kQueuePosition 0 +#define kUserDisplayName "Mamadou DIOP" +#define kUserUri "Mamadou DIOP@TEST.COM" +#define kRemoteIP "192.168.0.28" +#define kRemotePort 5060 +#define kLocalIP "192.168.0.37" +#define kLocalPort 5060 + +#define kNullOctetStringPtr 0 + +#define BAIL_IF_ERR(expr) { int _ret_; if ((_ret_) = (expr)) { TSK_DEBUG_ERROR("Error %d", (_ret_)); goto bail; } } + +#define LOOP 0 + +#define RUN_TEST_ALL 0 +#define RUN_TEST_PARSER 0 +#define RUN_TEST_SESSION 1 + +#include "test_parser.h" +#include "test_session.h" + + +#ifdef _WIN32_WCE +int _tmain(int argc, _TCHAR* argv[]) +#else +int main() +#endif +{ + tnet_startup(); + + do { + /* Print copyright information */ + printf("Doubango Project\nCopyright (C) 2014 Mamadou Diop \n\n"); + +#if RUN_TEST_PARSER || RUN_TEST_ALL + test_parser(); +#endif +#if RUN_TEST_SESSION || RUN_TEST_ALL + test_session(); +#endif + } + while(LOOP); + + tnet_cleanup(); + + getchar(); + + return 0; +} + diff --git a/tinyBFCP/test/test.vcproj b/tinyBFCP/test/test.vcproj new file mode 100644 index 0000000..4949dc7 --- /dev/null +++ b/tinyBFCP/test/test.vcproj @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tinyBFCP/test/test_parser.h b/tinyBFCP/test/test_parser.h new file mode 100644 index 0000000..baf9603 --- /dev/null +++ b/tinyBFCP/test/test_parser.h @@ -0,0 +1,215 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TEST_TINYBFCP_PARSER_H +#define TEST_TINYBFCP_PARSER_H + +#include "tinybfcp.h" + +#define SEND_BUFF(buff_ptr, buff_size) \ + { \ + struct sockaddr_storage addr_to; \ + tnet_socket_t* socket = tnet_socket_create(kLocalIP, kLocalPort, tnet_socket_type_udp_ipv4); \ + tnet_sockaddr_init(kRemoteIP, kRemotePort, tnet_socket_type_udp_ipv4, &addr_to); \ + tnet_sockfd_sendto(socket->fd, (const struct sockaddr *)&addr_to, (buff_ptr), (buff_size)); \ + TSK_OBJECT_SAFE_FREE(socket); \ + } \ + + +uint8_t __parse_buff_write_ptr[1200]; +static const tsk_size_t __parse_buff_write_size = sizeof(__parse_buff_write_ptr)/sizeof(__parse_buff_write_ptr[0]); +uint8_t __parse_buff_read_ptr[1200]; +static const tsk_size_t __parse_buff_read_size = sizeof(__parse_buff_read_ptr)/sizeof(__parse_buff_read_ptr[0]); + +static int test_parser_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size) +{ + int ret; + tsk_size_t u; + if (!pc_buf1_ptr || !pc_buf2_ptr || (n_buff1_size != n_buff2_size)) { + return -1; + } + for (u = 0; u < n_buff1_size; ++u) { + if ((ret = (pc_buf1_ptr[u] - pc_buf2_ptr[u]))) { + return ret; + } + } + return 0; +} + +static int test_parser_add_user_info(tbfcp_pkt_t* p_pkt) +{ + tbfcp_attr_octetstring_t* p_attr = tsk_null; + if (!p_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + BAIL_IF_ERR(tbfcp_attr_octetstring_create(tbfcp_attribute_type_USER_DISPLAY_NAME, kBfcpFieldMNo, kUserDisplayName, tsk_strlen(kUserDisplayName), &p_attr)); + BAIL_IF_ERR(tbfcp_pkt_add_attr(p_pkt, (tbfcp_attr_t**)&p_attr)); + BAIL_IF_ERR(tbfcp_attr_octetstring_create(tbfcp_attribute_type_USER_URI, kBfcpFieldMNo, kUserUri, tsk_strlen(kUserUri), &p_attr)); + BAIL_IF_ERR(tbfcp_pkt_add_attr(p_pkt, (tbfcp_attr_t**)&p_attr)); + return 0; + +bail: + TSK_OBJECT_SAFE_FREE(p_attr); + return -1; +} + +static void test_parser_Hello() +{ + tbfcp_pkt_t* p_pkt = tsk_null; + tsk_size_t n_written_bytes, n_read_bytes; + + (n_read_bytes); + + BAIL_IF_ERR(tbfcp_pkt_create_Hello(kConfId, kTransacId, kUserId, &p_pkt)); + BAIL_IF_ERR(test_parser_add_user_info(p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes)); + //SEND_BUFF(__parse_buff_write_ptr, n_written_bytes); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes)); + //SEND_BUFF(__parse_buff_read_ptr, n_read_bytes); + + BAIL_IF_ERR(test_parser_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes)); + TSK_DEBUG_INFO("test_parser_Hello...OK"); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); +} + +static void test_parser_HelloAck() +{ + tbfcp_pkt_t* p_pkt = tsk_null; + tsk_size_t n_written_bytes, n_read_bytes; + + (n_read_bytes); + + BAIL_IF_ERR(tbfcp_pkt_create_HelloAck_2(kConfId, kTransacId, kUserId, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes)); + //SEND_BUFF(__parse_buff_write_ptr, n_written_bytes); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes)); + //SEND_BUFF(__parse_buff_read_ptr, n_read_bytes); + + BAIL_IF_ERR(test_parser_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes)); + TSK_DEBUG_INFO("test_parser_HelloAck...OK"); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); +} + +static void test_parser_FloorRequest() +{ + tbfcp_pkt_t* p_pkt = tsk_null; + tsk_size_t n_written_bytes, n_read_bytes; + + (n_read_bytes); + + BAIL_IF_ERR(tbfcp_pkt_create_FloorRequest_2(kConfId, kTransacId, kUserId, kFloorId, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes)); + //SEND_BUFF(__parse_buff_write_ptr, n_written_bytes); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes)); + //SEND_BUFF(__parse_buff_read_ptr, n_read_bytes); + + BAIL_IF_ERR(test_parser_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes)); + TSK_DEBUG_INFO("test_parser_FloorRequest...OK"); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); +} + +static void test_parser_FloorRequestStatus() +{ + tbfcp_pkt_t* p_pkt = tsk_null; + tbfcp_attr_grouped_t* p_floor_req_info = tsk_null; + tbfcp_attr_grouped_t* p_overal_req_status = tsk_null; + tbfcp_attr_octetstring16_t* p_req_status = tsk_null; + tbfcp_attr_grouped_t* p_floor_req_status = tsk_null; + tsk_size_t n_written_bytes, n_read_bytes; + static uint8_t ReqStatusOctesString16[2] = { kReqStatus, kQueuePosition }; + + (n_read_bytes); + + // PKT$FLOOR_REQUEST_INFORMATION"OVERALL_REQUEST_STATUS'REQUEST_STATUS',FLOOR_REQUEST_STATUS"$ + + BAIL_IF_ERR(tbfcp_pkt_create_FloorRequestStatus(kConfId, kTransacId, kUserId, &p_pkt)); + BAIL_IF_ERR(tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_FLOOR_REQUEST_INFORMATION, kBfcpFieldMNo, kFloorReqId, &p_floor_req_info)); + BAIL_IF_ERR(tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_OVERALL_REQUEST_STATUS, kBfcpFieldMNo, kFloorReqId, &p_overal_req_status)); + BAIL_IF_ERR(tbfcp_attr_octetstring16_create(tbfcp_attribute_type_REQUEST_STATUS, kBfcpFieldMNo, ReqStatusOctesString16, &p_req_status)); + BAIL_IF_ERR(tbfcp_attr_grouped_add_attr(p_overal_req_status, (tbfcp_attr_t**)&p_req_status)); + BAIL_IF_ERR(tbfcp_attr_grouped_add_attr(p_floor_req_info,(tbfcp_attr_t**) &p_overal_req_status)); + BAIL_IF_ERR(tbfcp_attr_grouped_create_u16(tbfcp_attribute_type_FLOOR_REQUEST_STATUS, kBfcpFieldMNo, kFloorId, &p_floor_req_status)); + BAIL_IF_ERR(tbfcp_attr_grouped_add_attr(p_floor_req_info, (tbfcp_attr_t**)&p_floor_req_status)); + BAIL_IF_ERR(tbfcp_pkt_add_attr(p_pkt, (tbfcp_attr_t**)&p_floor_req_info)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes)); + //SEND_BUFF(__parse_buff_write_ptr, n_written_bytes); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes)); + //SEND_BUFF(__parse_buff_read_ptr, n_read_bytes); + + BAIL_IF_ERR(test_parser_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes)); + TSK_DEBUG_INFO("test_parser_FloorRequestStatus...OK"); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + TSK_OBJECT_SAFE_FREE(p_floor_req_info); + TSK_OBJECT_SAFE_FREE(p_overal_req_status); + TSK_OBJECT_SAFE_FREE(p_req_status); + TSK_OBJECT_SAFE_FREE(p_floor_req_status); +} + +static void test_parser_FloorRelease() +{ + tbfcp_pkt_t* p_pkt = tsk_null; + tsk_size_t n_written_bytes, n_read_bytes; + + BAIL_IF_ERR(tbfcp_pkt_create_FloorRelease_2(kConfId, kTransacId, kUserId, kFloorReqId, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes)); + //SEND_BUFF(__parse_buff_write_ptr, n_written_bytes); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt)); + BAIL_IF_ERR(tbfcp_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes)); + //SEND_BUFF(__parse_buff_read_ptr, n_read_bytes); + + BAIL_IF_ERR(test_parser_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes)); + TSK_DEBUG_INFO("test_parser_FloorRelease...OK"); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); +} + +static void test_parser() +{ + test_parser_Hello(); + test_parser_HelloAck(); + test_parser_FloorRequest(); + test_parser_FloorRequestStatus(); + test_parser_FloorRelease(); +} + +#endif /* TEST_TINYBFCP_PARSER_H */ diff --git a/tinyBFCP/test/test_session.h b/tinyBFCP/test/test_session.h new file mode 100644 index 0000000..0ec239c --- /dev/null +++ b/tinyBFCP/test/test_session.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TEST_TINYBFCP_SESSION_H +#define TEST_TINYBFCP_SESSION_H + +#include "tinybfcp.h" + +static void test_session_tcp() +{ +} + +static void test_session_udp() +{ + struct tbfcp_session_s* p_session = tsk_null; + tbfcp_pkt_t* p_pkt = tsk_null; + + BAIL_IF_ERR(tbfcp_session_create(tnet_socket_type_udp_ipv4, kLocalIP, &p_session)); + BAIL_IF_ERR(tbfcp_session_set_remote(p_session, kRemoteIP, kRemotePort)); + BAIL_IF_ERR(tbfcp_session_prepare(p_session)); + BAIL_IF_ERR(tbfcp_session_start(p_session)); + TSK_DEBUG_INFO("PRESS ENTER to continue"); + getchar(); + + BAIL_IF_ERR(tbfcp_pkt_create_FloorRequest_2(kConfId, kTransacId, kUserId, kFloorId, &p_pkt)); + BAIL_IF_ERR(tbfcp_session_send_pkt(p_session, p_pkt)); + TSK_DEBUG_INFO("PRESS ENTER to continue"); + getchar(); + + TSK_OBJECT_SAFE_FREE(p_pkt); + BAIL_IF_ERR(tbfcp_pkt_create_Hello(kConfId, kTransacId, kUserId, &p_pkt)); + BAIL_IF_ERR(tbfcp_session_send_pkt(p_session, p_pkt)); + TSK_DEBUG_INFO("PRESS ENTER to continue"); + getchar(); + +bail: + TSK_OBJECT_SAFE_FREE(p_pkt); + TSK_OBJECT_SAFE_FREE(p_session); +} + +static void test_session() +{ + test_session_tcp(); + test_session_udp(); +} + +#endif /* TEST_TINYBFCP_SESSION_H */ diff --git a/tinyBFCP/tinyBFCP.pc.in b/tinyBFCP/tinyBFCP.pc.in new file mode 100644 index 0000000..37d4117 --- /dev/null +++ b/tinyBFCP/tinyBFCP.pc.in @@ -0,0 +1,15 @@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@ +includedir = @includedir@ + +Name : libtinyBFCP +Description : Doubango Telecom tinyBFCP (BFCP protocol) library +Version : @PACKAGE_VERSION@ +Requires: +Requires.private: tinySAK = @PACKAGE_VERSION@ tinyNET = @PACKAGE_VERSION@ +Conflicts: +Cflags : -I${includedir}/tinybfcp +Libs : -L${libdir} -ltinyBFCP +Libs.private: + diff --git a/tinyBFCP/tinyBFCP.sln b/tinyBFCP/tinyBFCP.sln new file mode 100644 index 0000000..06ce19e --- /dev/null +++ b/tinyBFCP/tinyBFCP.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyBFCP", "tinyBFCP.vcproj", "{78605D89-4D51-41AC-AFE2-061B4CAB81F1}" + ProjectSection(ProjectDependencies) = postProject + {7522A458-92F4-4259-B906-E84C2A65D9F1} = {7522A458-92F4-4259-B906-E84C2A65D9F1} + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} = {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}" + ProjectSection(ProjectDependencies) = postProject + {7522A458-92F4-4259-B906-E84C2A65D9F1} = {7522A458-92F4-4259-B906-E84C2A65D9F1} + {78605D89-4D51-41AC-AFE2-061B4CAB81F1} = {78605D89-4D51-41AC-AFE2-061B4CAB81F1} + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} = {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\tinySAK\tinySAK.vcproj", "{6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "..\tinyNET\tinyNET.vcproj", "{7522A458-92F4-4259-B906-E84C2A65D9F1}" + ProjectSection(ProjectDependencies) = postProject + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} = {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Static_Debug|Win32 = Static_Debug|Win32 + Static_Release|Win32 = Static_Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Debug|Win32.ActiveCfg = Debug|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Debug|Win32.Build.0 = Debug|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Release|Win32.ActiveCfg = Release|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Release|Win32.Build.0 = Release|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Static_Debug|Win32.ActiveCfg = Debug|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Static_Debug|Win32.Build.0 = Debug|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Static_Release|Win32.ActiveCfg = Release|Win32 + {78605D89-4D51-41AC-AFE2-061B4CAB81F1}.Static_Release|Win32.Build.0 = Release|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Debug|Win32.ActiveCfg = Debug|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Debug|Win32.Build.0 = Debug|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Release|Win32.ActiveCfg = Release|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Release|Win32.Build.0 = Release|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Static_Debug|Win32.ActiveCfg = Debug|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Static_Debug|Win32.Build.0 = Debug|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Static_Release|Win32.ActiveCfg = Release|Win32 + {3FC1411B-9B7E-4078-9BD5-70EB663ECF5F}.Static_Release|Win32.Build.0 = Release|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.Build.0 = Debug|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.ActiveCfg = Release|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.Build.0 = Release|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Win32.ActiveCfg = Static_Debug|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Win32.Build.0 = Static_Debug|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Win32.ActiveCfg = Static_Release|Win32 + {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Win32.Build.0 = Static_Release|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.ActiveCfg = Debug|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.Build.0 = Debug|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.ActiveCfg = Release|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.Build.0 = Release|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Win32.ActiveCfg = Debug|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Win32.Build.0 = Debug|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Win32.ActiveCfg = Release|Win32 + {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tinyBFCP/tinyBFCP.vcproj b/tinyBFCP/tinyBFCP.vcproj new file mode 100644 index 0000000..86f9605 --- /dev/null +++ b/tinyBFCP/tinyBFCP.vcproj @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tinyBFCP/version.rc b/tinyBFCP/version.rc new file mode 100644 index 0000000..fd931a5 --- /dev/null +++ b/tinyBFCP/version.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +// #include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2.0.0.1156 + PRODUCTVERSION 2.0.0.1156 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Doubango telecom" + VALUE "FileDescription", "Doubango IMS Framework" + VALUE "FileVersion", "2.0.0.1156" + VALUE "InternalName", "tinyhttp.dll" + VALUE "LegalCopyright", "(c) 2010-2014 Doubango Telecom. All rights reserved." + VALUE "OriginalFilename", "tinybfcp.dll" + VALUE "ProductName", "Doubango IMS Framework" + VALUE "ProductVersion", "2.0.0.1156" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + -- cgit v1.1