Update MSRP media handler.

This commit is contained in:
bossiel 2010-03-25 00:07:04 +00:00
parent 855d471d0f
commit f7bcf6f79e
7 changed files with 277 additions and 62 deletions

View File

@ -41,7 +41,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;include;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;include;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;;&quot;$(DOUBANGO_HOME)\tinySDP\include&quot;;&quot;$(DOUBANGO_HOME)\tinyNET\src&quot;"
PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_WINDOWS;_USRDLL;TINYMEDIA_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -63,7 +63,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(OutDir)\tinySAK.lib"
AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinySDP.lib $(OutDir)\tinyNET.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"

View File

@ -52,16 +52,22 @@ typedef struct tmsrp_media_s
{
TMED_DECLARE_MEDIA;
tsdp_ctx_handle_t* sdp_ctx;
tsdp_header_M_t *local;
tsdp_header_M_t *remote;
tsdp_header_M_t *negociated;
tmsrp_session_setup_t setup;
tnet_fd_t connectedFD; // FullDuplex Socket
tnet_socket_t* localSocket;
struct{
struct tsdp_header_M_s* M;
tnet_socket_t* socket;
}local;
struct{
struct tsdp_header_M_s* M;
//struct tsdp_header_C_s* C;
}remote;
struct{
struct tsdp_header_M_s* M;
}negociated;
}
tmsrp_media_t;

View File

@ -31,6 +31,7 @@
#include "tinySDP/headers/tsdp_header_A.h"
#include "tinySDP/headers/tsdp_header_C.h"
#include "tinySDP/headers/tsdp_header_M.h"
#include "tnet_utils.h"
@ -38,6 +39,45 @@
#include "tsk_memory.h"
#include "tsk_debug.h"
#define TMSRP_CONNECT_TIMEOUT 2500
tmsrp_session_setup_t setup_from_string(const char* setup)
{
tmsrp_session_setup_t ret = setup_active;
if(setup){
if(tsk_strequals(setup, "holdconn")){
ret = setup_holdconn;
}
else if(tsk_strequals(setup, "passive")){
ret = setup_passive;
}
else if(tsk_strequals(setup, "actpass")){
ret = setup_actpass;
}
else{
ret = setup_active;
}
}
return ret;
}
const char* setup_to_string(tmsrp_session_setup_t setup)
{
switch(setup)
{
case setup_active:
return "active";
case setup_passive:
return "passive";
case setup_actpass:
return "actpass";
case setup_holdconn:
return "holdconn";
}
return "active";
}
/* =========================== Plugin ============================= */
int tmsrp_media_set_params(tmedia_t* self, const tsk_params_L_t* params)
@ -48,18 +88,7 @@ int tmsrp_media_set_params(tmedia_t* self, const tsk_params_L_t* params)
// setup
if((param = tsk_params_get_param_by_name(params, "msrp/setup"))){
if(tsk_strequals(param->name, "holdconn")){
msrp->setup = setup_holdconn;
}
else if(tsk_strequals(param->name, "passive")){
msrp->setup = setup_passive;
}
else if(tsk_strequals(param->name, "actpass")){
msrp->setup = setup_actpass;
}
else{
msrp->setup = setup_active;
}
msrp->setup = setup_from_string(param->value);
}
return 0;
@ -67,10 +96,65 @@ int tmsrp_media_set_params(tmedia_t* self, const tsk_params_L_t* params)
int tmsrp_media_start(tmedia_t* self)
{
int ret = -1;
tmsrp_media_t *msrp = TMSRP_MEDIA(self);
TSK_DEBUG_INFO("tmsrp_media_start");
struct sockaddr_storage to;
if(!msrp || !msrp->local.socket || msrp->local.socket->fd <= 0){
goto bail;
}
return 0;
if(!msrp->local.M || !msrp->remote.M){
ret = -2;
goto bail;
}
if(!msrp->remote.M->C){
ret = -3;
goto bail;
}
switch(msrp->setup){
case setup_active:
case setup_actpass:
{
//
// ACTIVE
//
if((ret = tnet_sockaddr_init(msrp->remote.M->C->addr, msrp->remote.M->port, msrp->local.socket->type, &to))){
goto bail;
}
if((ret = tnet_sockfd_connetto(msrp->local.socket->fd, &to))){
goto bail;
}
else{
msrp->connectedFD = msrp->local.socket->fd;
if((ret = tnet_sockfd_waitUntilWritable(msrp->connectedFD, TMSRP_CONNECT_TIMEOUT))){
TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected.", TMSRP_CONNECT_TIMEOUT);
goto bail;
}
/* draft-denis-simple-msrp-comedia-02 - 4.2.3. Setting up the connection
Once the TCP session is established, and if the answerer was the
active connection endpoint, it MUST send an MSRP request. In
particular, if it has no pending data to send, it MUST send an empty
MSRP SEND request. That is necessary for the other endpoint to
authenticate this TCP session.
*/
// ... send bodiless message
}
break;
}
default:
{
//
// PASSIVE
//
break;
}
}
bail:
return ret;
}
int tmsrp_media_pause(tmedia_t* self)
@ -92,36 +176,37 @@ int tmsrp_media_stop(tmedia_t* self)
const tsdp_header_M_t* tmsrp_media_get_local_offer(tmedia_t* self)
{
tmsrp_media_t *msrp = TMSRP_MEDIA(self);
const tsdp_header_A_t* A;
const char* proto = "TCP/MSRP";
const char* sheme = "msrp";
tsk_bool_t answer;
tsk_bool_t ipv6;
tsk_istr_t sessionid;
if(!msrp || !msrp->localSocket || msrp->localSocket->fd <= 0){
if(!msrp || !msrp->local.socket || msrp->local.socket->fd <= 0){
goto bail;
}
// answer or initial offer?
answer = (msrp->remote != tsk_null);
answer = (msrp->remote.M != tsk_null);
// using ipv6?
ipv6 = TNET_SOCKET_TYPE_IS_IPV6(msrp->localSocket->type);
ipv6 = TNET_SOCKET_TYPE_IS_IPV6(msrp->local.socket->type);
if(TNET_SOCKET_TYPE_IS_TLS(msrp->localSocket->type)){
if(TNET_SOCKET_TYPE_IS_TLS(msrp->local.socket->type)){
proto = "TCP/TLS/MSRP";
sheme = "msrps";
}
if(!msrp->local){
if(!msrp->local.M){
char* path = tsk_null;
tsk_strrandom(&sessionid);
tsk_sprintf(&path, "%s://%s:%u/%s;tcp", sheme, msrp->localSocket->ip, msrp->localSocket->port, sessionid); //tcp is ok even if tls is used.
tsk_sprintf(&path, "%s://%s:%u/%s;tcp", sheme, msrp->local.socket->ip, msrp->local.socket->port, sessionid); //tcp is ok even if tls is used.
if((msrp->local = TSDP_HEADER_M_CREATE(self->plugin->media, msrp->localSocket->port, proto))){
tsdp_header_M_add_headers(msrp->local,
if((msrp->local.M = TSDP_HEADER_M_CREATE(self->plugin->media, msrp->local.socket->port, proto))){
tsdp_header_M_add_headers(msrp->local.M,
TSDP_FMT_VA_ARGS("*"),
TSDP_HEADER_C_VA_ARGS("IN", ipv6?"IP6":"IP4", &msrp->localSocket->ip),
TSDP_HEADER_C_VA_ARGS("IN", ipv6?"IP6":"IP4", &msrp->local.socket->ip),
TSDP_HEADER_A_VA_ARGS("sendrecv", tsk_null),
TSDP_HEADER_A_VA_ARGS("path", path),
@ -131,20 +216,54 @@ const tsdp_header_M_t* tmsrp_media_get_local_offer(tmedia_t* self)
);
TSK_FREE(path);
if(!answer){
tsdp_header_M_add_headers(msrp->local,
if(answer){ /* We are about to send 2xx INVITE(sdp) */
/* RFC 4145 - 4.1. The Setup Attribute in the Offer/Answer Model
Offer Answer
________________
active passive / holdconn
passive active / holdconn
actpass active / passive / holdconn
holdconn holdconn
*/
if((A = tsdp_header_M_findA(msrp->remote.M, "setup"))){
tmsrp_session_setup_t setup = setup_from_string(A->value);
switch(setup){
case setup_actpass:
case setup_passive:
msrp->setup = setup_active;
break;
case setup_active:
msrp->setup = setup_passive;
break;
}
tsdp_header_M_add_headers(msrp->local.M,
TSDP_HEADER_A_VA_ARGS("accept-types", "text/plain"), // FIXME: match with the offer
TSDP_HEADER_A_VA_ARGS("connection", "new"),
tsk_null
);
}
}
else{ /* We are about to send INVITE(sdp) */
tsdp_header_M_add_headers(msrp->local.M,
TSDP_HEADER_A_VA_ARGS("accept-types", "text/plain"),
TSDP_HEADER_A_VA_ARGS("setup", "actpass"),
TSDP_HEADER_A_VA_ARGS("connection", "new"),
tsk_null
);
}
}
// Common headers
tsdp_header_M_add_headers(msrp->local.M,
TSDP_HEADER_A_VA_ARGS("setup", setup_to_string(msrp->setup)),
tsk_null
);
}
bail:
return msrp->local;
return msrp->local.M;
}
const tsdp_header_M_t* tmsrp_media_get_negotiated_offer(tmedia_t* self)
@ -158,9 +277,67 @@ const tsdp_header_M_t* tmsrp_media_get_negotiated_offer(tmedia_t* self)
int tmsrp_media_set_remote_offer(tmedia_t* self, const tsdp_message_t* offer)
{
tmsrp_media_t *msrp = TMSRP_MEDIA(self);
TSK_DEBUG_INFO("tmsrp_media_set_remote_offer");
const tsdp_header_C_t* C;
const tsdp_header_A_t* A;
const tsdp_header_M_t* M;
int ret = -1;
size_t index;
tsk_bool_t found = tsk_false;
tsk_bool_t answer;
return 0;
if(!offer || !msrp || !msrp->local.socket || msrp->local.socket->fd <= 0){
goto bail;
}
// answer or initial offer?
answer = (msrp ->local.M != tsk_null);
// Find header M associated to our "media"
for(index = 0; (M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(offer, tsdp_htype_M, index)); index++){
if(tsk_strequals(M->media, self->plugin->media)){
found = tsk_true;
break;
}
}
// media found?
if(found){
TSK_OBJECT_SAFE_FREE(msrp->remote.M);
if((msrp->remote.M = (tsdp_header_M_t*)tsdp_header_clone(TSDP_HEADER(M)))){
// Find remote connection (C)
if(!msrp->remote.M->C){ // Get Session Level Connection
if((C = (const tsdp_header_C_t*)tsdp_message_get_header(offer, tsdp_htype_C))){
msrp->remote.M->C = (tsdp_header_C_t*)tsdp_header_clone(TSDP_HEADER(C));
}
}
}
}
else{
TSK_DEBUG_WARN("Failed to match media(%s)", self->plugin->media);
goto bail;
}
if(answer){ /* We are about to receive 2xx INVITE(sdp) */
}
else{ /* We are about to receive INVITE(sdp) */
msrp->setup = setup_passive; // default value
// OMA-TS-SIMPLE_IM-V1_0-20080903-C - 5.8.1 Negotiate direction of the MSRP connection setup
if((A = tsdp_header_M_findA(msrp->remote.M, "setup"))){
tmsrp_session_setup_t setup = setup_from_string(A->value);
switch(setup){
case setup_actpass:
case setup_passive:
msrp->setup = setup_active;
break;
case setup_active:
msrp->setup = setup_passive;
break;
}
}
}
bail:
return ret;
}
/* ======================================================== */
@ -209,18 +386,18 @@ static void* tmsrp_media_create(tsk_object_t *self, va_list * app)
tmedia_init(TMEDIA(msrp), name);
msrp->setup = setup_actpass; // draft-denis-simple-msrp-comedia-02 - 4.1.1. Sending the offer
TMEDIA(msrp)->protocol = tsk_strdup("TCP/MSRP");
msrp->sdp_ctx = TSDP_CTX_CREATE();
if(host == TNET_SOCKET_HOST_ANY){
// Because wa cannot use bestsource (no dest)
// if this is not used then the host address will be equal to "0.0.0.0" or "::"
// when used with SIP, the stack will provide a routable IP (e.g. 192.168.16.104)
tnet_gethostname(&local);
msrp->localSocket = TNET_SOCKET_CREATE(local, TNET_SOCKET_PORT_ANY, socket_type);
msrp->local.socket = TNET_SOCKET_CREATE(local, TNET_SOCKET_PORT_ANY, socket_type);
}
else{
msrp->localSocket = TNET_SOCKET_CREATE(host, TNET_SOCKET_PORT_ANY, socket_type);
msrp->local.socket = TNET_SOCKET_CREATE(host, TNET_SOCKET_PORT_ANY, socket_type);
}
}
else{
@ -233,15 +410,21 @@ static void* tmsrp_media_destroy(tsk_object_t *self)
{
tmsrp_media_t *msrp = self;
if(msrp){
tsk_bool_t closeFD = (msrp->local.socket && msrp->local.socket->fd != msrp->connectedFD);
tmedia_deinit(TMEDIA(msrp));
TSK_OBJECT_SAFE_FREE(msrp->sdp_ctx);
TSK_OBJECT_SAFE_FREE(msrp->local);
TSK_OBJECT_SAFE_FREE(msrp->remote);
TSK_OBJECT_SAFE_FREE(msrp->negociated);
tnet_sockfd_close(&msrp->connectedFD);
TSK_OBJECT_SAFE_FREE(msrp->localSocket);
// local
TSK_OBJECT_SAFE_FREE(msrp->local.M);
TSK_OBJECT_SAFE_FREE(msrp->local.socket);
// remote
TSK_OBJECT_SAFE_FREE(msrp->remote.M);
//TSK_OBJECT_SAFE_FREE(msrp->remote.C);
// negociated
TSK_OBJECT_SAFE_FREE(msrp->negociated.M);
if(closeFD){
tnet_sockfd_close(&msrp->connectedFD);
}
}
else{
TSK_DEBUG_ERROR("Null dummy media.");

View File

@ -41,7 +41,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;&quot;$(SolutionDir)\include&quot;;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;&quot;$(SolutionDir)\include&quot;;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;;&quot;$(DOUBANGO_HOME)\tinyNET\src&quot;;&quot;$(DOUBANGO_HOME)\tinyMEDIA\include&quot;;&quot;$(DOUBANGO_HOME)\tinySDP\include&quot;"
PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -63,7 +63,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyMSRP.lib"
AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib $(OutDir)\tinyMSRP.lib $(OutDir)\tinyMEDIA.lib $(OutDir)\tinySDP.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"

View File

@ -23,27 +23,53 @@
#define _TEST_MSRPSESSION_H
#include "tinySDP/headers/tsdp_header_M.h"
#include "tinySDP/parsers/tsdp_parser_message.h"
#define REMOTE_SDP1 \
"c=IN IP4 192.168.0.15\r\n" \
"m=message 5060 TCP/MSRP *\r\n" \
"a=accept-types:text/plain\r\n" \
"a=path:msrp://atlanta.example.com:7654/jshA7weztas;tcp\r\n" \
"a=setup:passive\r\n" \
"a=connection:new\r\n"
#define REMOTE_SDP2 \
"m=message 5060 TCP/MSRP *\r\n" \
"c=IN IP4 192.168.0.15\r\n" \
"a=accept-types:text/plain\r\n" \
"a=path:msrp://atlanta.example.com:7654/jshA7weztas;tcp\r\n" \
"a=setup:passive\r\n" \
"a=connection:new\r\n"
#define REMOTE_SDP REMOTE_SDP1
void test_session()
{
tmedia_t* msrp = tsk_null;
char* str;
const tsdp_header_M_t *m;
tsdp_message_t* remote;
// Register dummy media
tmedia_plugin_register(tmsrp_media_plugin_def_t);
if((msrp = tmedia_factory_create("msrp", TNET_SOCKET_HOST_ANY, tnet_socket_type_tcp_ipv4))){
// Get offer
if((m = tmedia_get_local_offer(msrp))){
if((str = tsdp_header_tostring(TSDP_HEADER(m)))){
TSK_DEBUG_INFO("m(offer)=%s", str);
TSK_FREE(str);
}
}
// Set offer
if((remote = tsdp_message_parse(REMOTE_SDP, strlen(REMOTE_SDP)))){
tmedia_set_remote_offer(msrp, remote);
TSK_OBJECT_SAFE_FREE(remote);
}
tmedia_get_negotiated_offer(msrp);
tmedia_set_remote_offer(msrp, tsk_null);
tmedia_start(msrp);
tmedia_pause(msrp);

View File

@ -2,19 +2,19 @@
* Copyright (C) 2009 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou@yahoo.fr>
*
*
* 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 General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*

View File

@ -41,7 +41,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;;&quot;$(DOUBANGO_HOME)\tinyMSRP\include&quot;;&quot;$(DOUBANGO_HOME)\tinyHTTP\include&quot;;&quot;$(DOUBANGO_HOME)\tinyMEDIA\include&quot;;&quot;$(DOUBANGO_HOME)\tinySDP\include&quot;"
AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;&quot;$(DOUBANGO_HOME)\tinyNET\src&quot;;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;;&quot;$(DOUBANGO_HOME)\tinyMSRP\include&quot;;&quot;$(DOUBANGO_HOME)\tinyHTTP\include&quot;;&quot;$(DOUBANGO_HOME)\tinyMEDIA\include&quot;;&quot;$(DOUBANGO_HOME)\tinySDP\include&quot;"
PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_WINDOWS;_USRDLL;TINYMSRP_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -63,7 +63,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyHTTP.lib $(OutDir)\tinySDP.lib $(OutDir)\tinyMEDIA.lib"
AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyHTTP.lib $(OutDir)\tinySDP.lib $(OutDir)\tinyMEDIA.lib $(OutDir)\tinyNET.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"