summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/msrp/tdav_session_msrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/msrp/tdav_session_msrp.c')
-rw-r--r--tinyDAV/src/msrp/tdav_session_msrp.c946
1 files changed, 946 insertions, 0 deletions
diff --git a/tinyDAV/src/msrp/tdav_session_msrp.c b/tinyDAV/src/msrp/tdav_session_msrp.c
new file mode 100644
index 0000000..8ca4daa
--- /dev/null
+++ b/tinyDAV/src/msrp/tdav_session_msrp.c
@@ -0,0 +1,946 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* 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.
+*
+*/
+
+/**@file tdav_session_msrp.c
+ * @brief The Message Session Relay Protocol (MSRP) session.
+ * Used for both Message (RFC 4975) and file transfer (RFC 5547).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinydav/msrp/tdav_session_msrp.h"
+
+#include <string.h> /* strtok() */
+
+#define TDAV_MSRP_CONNECT_TIMEOUT 2000
+
+static void send_pending_file(tdav_session_msrp_t *session);
+static void send_bodiless(tdav_session_msrp_t *msrp);
+
+/*
+ * http://tools.ietf.org/html/draft-ietf-simple-msrp-acm-09
+ * http://tools.ietf.org/html/draft-ietf-simple-msrp-sessmatch-06
+ * http://www.openmobilealliance.org/technical/release_program/docs/SIMPLE_IM/V1_0-20100322-C/OMA-TS-SIMPLE_IM-V1_0-20100322-C.pdf
+*/
+
+int tdav_msrp_event_proxy_cb(tmsrp_event_t* _event/*!Not the owner of the object*/)
+{
+ tdav_session_msrp_t* msrp;
+ int ret = 0;
+
+ if(!_event || !_event->callback_data){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ msrp = tsk_object_ref((void*)_event->callback_data);
+ if(TMEDIA_SESSION_MSRP(msrp)->callback.func){
+ _event->callback_data = TMEDIA_SESSION_MSRP(msrp)->callback.data; // steal callback data
+ ret = TMEDIA_SESSION_MSRP(msrp)->callback.func(_event); // call callback function()
+ }
+ tsk_object_unref(msrp);
+
+ return ret;
+}
+
+int tdav_transport_layer_stream_cb(const tnet_transport_event_t* e)
+{
+ const tdav_session_msrp_t *session = e->callback_data;
+ tmsrp_receiver_t* receiver;
+ int ret = -1;
+
+#define TMSRP_ALERT_USER(type) \
+ { \
+ tdav_session_msrp_t *msrp = tsk_object_ref((void*)session); \
+ tmsrp_event_t* _event = tmsrp_event_create(msrp, tsk_false, type, tsk_null); \
+ tdav_msrp_event_proxy_cb(_event); \
+ TSK_OBJECT_SAFE_FREE(_event); \
+ tsk_object_unref(msrp); \
+ }
+
+ switch(e->type){
+ case event_data: {
+ break;
+ }
+ case event_accepted:
+ if(!session->connectedFD){
+ tdav_session_msrp_t *msrp = tsk_object_ref((void*)session);
+ /* We are passive ==> update connection info */
+ msrp->connectedFD = e->local_fd;
+ tmsrp_sender_set_fd(msrp->sender, msrp->connectedFD);
+ tmsrp_receiver_set_fd(msrp->receiver, msrp->connectedFD);
+ msrp->fresh_conn = tsk_true;
+ /* Send Bodiless request */
+ if(msrp->send_bodiless){
+ send_bodiless(msrp);
+ msrp->send_bodiless = tsk_false;
+ }
+ /* Alert user */
+ TMSRP_ALERT_USER(tmsrp_event_type_connected);
+
+ tsk_object_unref(msrp);
+ }
+ break;
+ case event_closed:
+ if(e->local_fd == session->connectedFD){
+ TSK_DEBUG_INFO("MSRP Socket closed");
+ TMSRP_ALERT_USER(tmsrp_event_type_disconnected);
+ }
+ return 0;
+
+ case event_connected:
+ {
+ tdav_session_msrp_t *msrp = tsk_object_ref((void*)session);
+ if(e->local_fd == msrp->connectedFD){
+ msrp->fresh_conn = tsk_true;
+ /* Send Bodiless request */
+ if(msrp->send_bodiless){
+ send_bodiless(msrp);
+ msrp->send_bodiless = tsk_false;
+ }
+ /* Alert user */
+ TMSRP_ALERT_USER(tmsrp_event_type_connected);
+ }
+ tsk_object_unref(msrp);
+ }
+ break;
+ default:{
+ return 0;
+ }
+ }
+
+ if(e->data && (receiver = tsk_object_ref((void*)session->receiver))){
+ ret = tmsrp_receiver_recv(receiver, e->data, e->size);
+ tsk_object_unref(receiver);
+ }
+
+ if(session->fresh_conn){
+ tdav_session_msrp_t *msrp = tsk_object_ref((void*)session);
+ /* send pending file - and data?*/
+ if(session->offerer){
+ send_pending_file(msrp);
+ }
+ msrp->fresh_conn = tsk_false;
+ tsk_object_unref(msrp);
+ }
+
+ return ret;
+}
+
+static void send_pending_file(tdav_session_msrp_t *msrp){
+ if(msrp && msrp->file.path && !msrp->file.sent){
+ msrp->file.sent = tsk_true;
+ tsmrp_sender_send_file(msrp->sender, msrp->file.path);
+ }
+}
+
+static void send_bodiless(tdav_session_msrp_t *msrp){
+ tmsrp_request_t* BODILESS;
+ if(msrp->config->To_Path && msrp->config->From_Path){
+ if((BODILESS = tmsrp_create_bodiless(msrp->config->To_Path->uri, msrp->config->From_Path->uri))){
+ char* str;
+ if((str = tmsrp_message_tostring(BODILESS))){
+ if(!tnet_sockfd_send(msrp->connectedFD, str, tsk_strlen(str), 0)){
+ TSK_DEBUG_WARN("Failed to send bodiless request.");
+ }
+ TSK_FREE(str);
+ }
+
+ TSK_OBJECT_SAFE_FREE(BODILESS);
+ }
+ }
+}
+
+static tdav_msrp_setup_t setup_from_string(const char* setup)
+{
+ tdav_msrp_setup_t ret = msrp_setup_active;
+
+ if(setup){
+ if(tsk_strequals(setup, "holdconn")){
+ ret = msrp_setup_holdconn;
+ }
+ else if(tsk_strequals(setup, "passive")){
+ ret = msrp_setup_passive;
+ }
+ else if(tsk_strequals(setup, "actpass")){
+ ret = msrp_setup_actpass;
+ }
+ else{
+ ret = msrp_setup_active;
+ }
+ }
+ return ret;
+}
+
+static const char* setup_to_string(tdav_msrp_setup_t setup)
+{
+ switch(setup){
+ case msrp_setup_active:
+ return "active";
+ case msrp_setup_passive:
+ return "passive";
+ case msrp_setup_actpass:
+ return "actpass";
+ case msrp_setup_holdconn:
+ return "holdconn";
+ }
+ return "active";
+}
+
+static int init_neg_types(tdav_session_msrp_t* msrp, const tsdp_header_M_t* m)
+{
+ const tsdp_header_A_t* A;
+
+ if((A = tsdp_header_M_findA(m, "accept-types"))){
+ char* atype = strtok((char*)A->value, " ");
+ const char* default_atype = atype;
+ while(atype){
+ if(tsk_striequals(atype, "message/CPIM")){
+ tsk_strupdate(&msrp->neg_accept_type, atype);
+ if((A = tsdp_header_M_findA(m, "accept-wrapped-types"))){
+ char* awtype = strtok((char*)A->value, " ");
+ tsk_strupdate(&msrp->neg_accept_w_type, awtype); // first
+ }
+ break;
+ }
+ atype = strtok(tsk_null, " ");
+ }
+
+ if(!msrp->neg_accept_type){
+ tsk_strupdate(&msrp->neg_accept_type, default_atype);
+ }
+
+ return 0;
+ }
+ return -1;
+}
+
+static int populate_lo(tdav_session_msrp_t* self, tsk_bool_t initial)
+{
+ if(!self || !TMEDIA_SESSION(self)->M.lo){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(initial){
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("setup", setup_to_string(self->setup)),
+
+ tsk_null
+ );
+
+ if(self->accept_types || self->neg_accept_type){
+ /* a=accept-types:message/CPIM application/octet-stream */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("accept-types", self->accept_types ? self->accept_types : self->neg_accept_type),
+ tsk_null);
+ }
+ if(self->accept_w_types || self->neg_accept_w_type){
+ /* a=accept-wrapped-types:application/octet-stream */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("accept-wrapped-types", self->accept_w_types ? self->accept_w_types : self->neg_accept_w_type),
+ tsk_null);
+ }
+
+ /*=== File Transfer ===*/
+ if(self->file.path){
+ /* Compute default 'file-selector' */
+ if(!self->file.selector && !TMEDIA_SESSION(self)->M.ro){
+ int index = tsk_strLastIndexOf(self->file.path, tsk_strlen(self->file.path), "\\");
+ if(index == -1){
+ index = tsk_strLastIndexOf(self->file.path, tsk_strlen(self->file.path), "/");
+ }
+ index++;
+ tsk_sprintf(&self->file.selector, "name:\"%s\" type:application/octet-stream", (self->file.path + index));
+ }
+ /* Compute default 'file-transfer-id' */
+ if(!self->file.transfer_id && !TMEDIA_SESSION(self)->M.ro){
+ tsk_istr_t rand_string;
+ tsk_strrandom(&rand_string);
+ self->file.transfer_id = tsk_strdup(rand_string);
+ }
+
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("sendonly", tsk_null),
+ tsk_null);
+ }
+ else{
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("sendrecv", tsk_null),
+ tsk_null);
+ }
+
+ if(self->file.selector){
+ /* a=file-selector:name:"test.pcap" type:application/octet-stream size:11376 hash:sha-1:8D:55:24:2B:F4:F9:9B:A2:54:A3:5B:91:00:15:9E:A3:D4:48:D7:DF */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("file-selector", self->file.selector),
+ tsk_null);
+ }
+ if(self->file.transfer_id){
+ /* a=file-transfer-id:vscxggbwkfnqduxwfnfozvsrtkjprepg */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("file-transfer-id", self->file.transfer_id),
+ tsk_null);
+ }
+ if(self->file.disposition){
+ /* a=file-disposition:attachment */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("file-disposition", self->file.disposition),
+ tsk_null);
+ }
+ if(self->file.date){
+ /* a=file-date:creation:2010-02-13T17:50:31.763Z */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("file-date", self->file.date),
+ tsk_null);
+ }
+ if(self->file.icon){
+ /* a=file-icon:cid:test@doubango.org */
+ tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ TSDP_HEADER_A_VA_ARGS("file-icon", self->file.icon),
+ tsk_null);
+ }
+ }
+
+ return 0;
+}
+
+static tsk_bool_t match_offer(const tdav_session_msrp_t* self, const tsdp_header_M_t* M)
+{
+ return tsk_true;
+}
+
+/* ============ Plugin interface ================= */
+
+int tdav_session_msrp_set(tmedia_session_t* self, const tmedia_param_t* param)
+{
+ int ret = 0;
+ tdav_session_msrp_t* msrp;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TSK_DEBUG_INFO("tdav_session_msrp_set");
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ if(param->value_type == tmedia_pvt_pchar){
+ if(tsk_striequals(param->key, "remote-ip")){
+ // only if no ip associated to the "m=" line
+ if(param->value && !msrp->remote_ip){
+ msrp->remote_ip = tsk_strdup(param->value);
+ }
+ }
+ else if(tsk_striequals(param->key, "local-ip")){
+ tsk_strupdate(&msrp->local_ip, param->value);
+ }
+ else if(tsk_striequals(param->key, "local-ipver")){
+ msrp->useIPv6 = tsk_striequals(param->value, "ipv6");
+ }
+ else if(tsk_striequals(param->key, "accept-types")){
+ tsk_strupdate(&msrp->accept_types, param->value);
+ }
+ else if(tsk_striequals(param->key, "accept-wrapped-types")){
+ tsk_strupdate(&msrp->accept_w_types, param->value);
+ }
+
+ /* Configuration */
+ else if(tsk_striequals(param->key, "Failure-Report")){
+ msrp->config->Failure_Report = tsk_striequals(param->value, "yes");
+ }
+ else if(tsk_striequals(param->key, "Success-Report")){
+ msrp->config->Success_Report = tsk_striequals(param->value, "yes");
+ }
+
+ /* File Transfer */
+ else if(tsk_striequals(param->key, "file-path") && !tsk_strnullORempty((const char*)param->value)){
+ tsk_strupdate(&msrp->file.path, param->value);
+ }
+ else if(tsk_striequals(param->key, "file-selector")){
+ tsk_strupdate(&msrp->file.selector, param->value);
+ }
+ else if(tsk_striequals(param->key, "file-disposition")){
+ tsk_strupdate(&msrp->file.disposition, param->value);
+ }
+ else if(tsk_striequals(param->key, "file-date")){
+ tsk_strupdate(&msrp->file.date, param->value);
+ }
+ else if(tsk_striequals(param->key, "file-icon")){
+ tsk_strupdate(&msrp->file.icon, param->value);
+ }
+ else if(tsk_striequals(param->key, "file-transfer-id")){
+ tsk_strupdate(&msrp->file.transfer_id, param->value);
+ }
+ }
+ else if(param->value_type == tmedia_pvt_pobject){
+ if(tsk_striequals(param->key, "natt-ctx")){
+ TSK_OBJECT_SAFE_FREE(msrp->natt_ctx);
+ msrp->natt_ctx = tsk_object_ref(param->value);
+ }
+ }
+ else if(param->value_type == tmedia_pvt_int64 || param->value_type == tmedia_pvt_int32){
+ if(tsk_striequals(param->key, "chunck-duration")){
+ msrp->chunck_duration = TSK_TO_UINT32((uint8_t*)param->value);
+ if(msrp->sender){
+ msrp->sender->chunck_duration = msrp->chunck_duration;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int tdav_session_msrp_prepare(tmedia_session_t* self)
+{
+ tdav_session_msrp_t* msrp;
+ tnet_socket_type_t socket_type = tnet_socket_type_tcp_ipv4;
+ int ret = 0;
+
+#if 1
+ tnet_port_t local_port = TNET_SOCKET_PORT_ANY;
+#else
+ tnet_port_t local_port = 2000;
+#endif
+
+ TSK_DEBUG_INFO("tdav_session_msrp_prepare");
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ /* set local port */
+ if(!msrp->transport){
+ if(msrp->useIPv6){
+ TNET_SOCKET_TYPE_SET_IPV6Only(socket_type);
+ }
+
+ if(!msrp->local_ip){
+ tnet_host_t local;
+ tnet_gethostname(&local);
+ msrp->transport = tnet_transport_create(local, local_port, socket_type, "MSRP/MSRPS transport");
+ }
+ else{
+ msrp->transport = tnet_transport_create(msrp->local_ip, local_port, socket_type, "MSRP/MSRPS transport");
+ }
+ /* Set NAT context */
+ if(msrp->natt_ctx){
+ tnet_transport_set_natt_ctx(msrp->transport, msrp->natt_ctx);
+ }
+ }
+
+ /* sender will be prepared in tdav_session_msrp_start() */
+ /* receiver will be prepared in tdav_session_msrp_start() */
+
+ return ret;
+}
+
+int tdav_session_msrp_start(tmedia_session_t* self)
+{
+ tdav_session_msrp_t* msrp;
+ int ret;
+
+ TSK_DEBUG_INFO("tdav_session_msrp_start");
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ /* start the transport */
+ if((ret = tnet_transport_start(msrp->transport))){
+ goto bail;
+ }
+
+ switch(msrp->setup){
+ case msrp_setup_active:
+ case msrp_setup_actpass:
+ {
+ //
+ // ACTIVE
+ //
+ TSK_DEBUG_INFO("connectto(%s:%d)", msrp->remote_ip, msrp->remote_port);
+ if((msrp->connectedFD = tnet_transport_connectto_2(msrp->transport, msrp->remote_ip, msrp->remote_port)) == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Failed to connect to the remote party");
+ ret = -2;
+ goto bail;
+ }
+ else{
+ //TSK_DEBUG_INFO("Msrp connected FD=%d", msrp->connectedFD);
+ //if((ret = tnet_sockfd_waitUntilWritable(msrp->connectedFD, TDAV_MSRP_CONNECT_TIMEOUT)) && msrp->offerer){
+ // TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected to (%s:%d).", TDAV_MSRP_CONNECT_TIMEOUT, msrp->remote_ip, msrp->remote_port);
+ // 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.
+
+ ...RFC 4975 - 7.1
+ */
+ msrp->send_bodiless = tsk_true;
+ }
+ break;
+ }
+ default:
+ {
+ //
+ // PASSIVE
+ //
+ break;
+ }
+ }
+
+ // create and start the receiver
+ if(!msrp->receiver){
+ if((msrp->receiver = tmsrp_receiver_create(msrp->config, msrp->connectedFD))){
+ tnet_transport_set_callback(msrp->transport, TNET_TRANSPORT_CB_F(tdav_transport_layer_stream_cb), msrp);
+ if((ret = tmsrp_receiver_start(msrp->receiver, msrp, tdav_msrp_event_proxy_cb))){
+ TSK_DEBUG_ERROR("Failed to start the MSRP receiver");
+ goto bail;
+ }
+ }
+ }
+
+ // create and start the sender
+ if(!msrp->sender){
+ if((msrp->sender = tmsrp_sender_create(msrp->config, msrp->connectedFD))){
+ msrp->sender->chunck_duration = msrp->chunck_duration;
+ if((ret = tmsrp_sender_start(msrp->sender))){
+ TSK_DEBUG_ERROR("Failed to start the MSRP sender");
+ goto bail;
+ }
+ }
+ }
+
+bail:
+ return ret;
+}
+
+int tdav_session_msrp_pause(tmedia_session_t* self)
+{
+ TSK_DEBUG_ERROR("Not Implemented");
+ return -1;
+}
+
+int tdav_session_msrp_stop(tmedia_session_t* self)
+{
+ tdav_session_msrp_t* msrp;
+ int ret;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ if(msrp->sender){
+ if((ret = tmsrp_sender_stop(msrp->sender))){
+ TSK_DEBUG_ERROR("Failed to stop the MSRP sender");
+ }
+ }
+ if(msrp->receiver){
+ if((ret = tmsrp_receiver_stop(msrp->receiver))){
+ TSK_DEBUG_ERROR("Failed to stop the MSRP receiver");
+ }
+ }
+
+ if(msrp->transport){
+ if((ret = tnet_transport_shutdown(msrp->transport))){
+ TSK_DEBUG_ERROR("Failed to stop the MSRP transport");
+ }
+ }
+
+ return 0;
+}
+
+const tsdp_header_M_t* tdav_session_msrp_get_lo(tmedia_session_t* self)
+{
+ tdav_session_msrp_t* msrp;
+ tsk_bool_t changed = tsk_false;
+
+ const char* proto = "TCP/MSRP";
+ const char* sheme = "msrp";
+
+ TSK_DEBUG_INFO("tdav_session_msrp_get_lo");
+
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ if(!msrp->transport){
+ TSK_DEBUG_ERROR("Not prepared");
+ return tsk_null;
+ }
+
+ if(/*TNET_SOCKET_TYPE_IS_TLS(type)*/ tsk_false){
+ proto = "TCP/TLS/MSRP";
+ sheme = "msrps";
+ }
+
+ if(self->ro_changed && self->M.lo){
+ /* Codecs */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "fmtp");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "rtpmap");
+ tsk_list_clear_items(self->M.lo->FMTs);
+
+ /* QoS */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "curr");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "des");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "conf");
+ }
+
+ changed = (self->ro_changed || !self->M.lo);
+
+ if(!self->M.lo){
+ tsk_istr_t id;
+ char* path = tsk_null;
+ tnet_ip_t ip = "0.0.0.0";
+ tnet_port_t port = 0;
+
+ tsk_strrandom(&id);
+ tnet_transport_get_public_ip_n_port(msrp->transport, msrp->transport->master->fd, &ip, &port);
+ tsk_sprintf(&path, "%s://%s:%u/%s;tcp", sheme, ip, port, id); //tcp is ok even if tls is used.
+
+ if((self->M.lo = tsdp_header_M_create(self->plugin->media, port, proto))){
+ tmsrp_uri_t* uri;
+
+ tsdp_header_M_add_headers(self->M.lo,
+ TSDP_FMT_VA_ARGS("*"),
+ TSDP_HEADER_C_VA_ARGS("IN", msrp->useIPv6 ? "IP6" : "IP4", ip),
+ TSDP_HEADER_A_VA_ARGS("path", path),
+ tsk_null);
+
+ if((uri = tmsrp_uri_parse(path, tsk_strlen(path)))){
+ TSK_OBJECT_SAFE_FREE(msrp->config->From_Path);
+ msrp->config->From_Path = tmsrp_header_From_Path_create(uri);
+ TSK_OBJECT_SAFE_FREE(uri);
+ }
+ }
+ TSK_FREE(path);
+
+ if(self->M.ro){ /* We are probably about to send 2xx INVITE(sdp) */
+ /* [OMA-TS-SIMPLE_IM-V1_0-20100322-C] - 5.8.1 Negotiate direction of the MSRP connection setup
+ Offer Answer
+ ________________
+ active passive / holdconn
+ passive active / holdconn
+ actpass active / passive / holdconn
+ holdconn holdconn
+ */
+ const tsdp_header_A_t* A;
+ if((A = tsdp_header_M_findA(self->M.ro, "setup"))){
+ tdav_msrp_setup_t setup = setup_from_string(A->value);
+ switch(setup){
+ case msrp_setup_passive:
+ msrp->setup = msrp_setup_active;
+ break;
+ case msrp_setup_actpass:
+ case msrp_setup_active:
+ msrp->setup = msrp_setup_passive;
+ break;
+ }
+ tsdp_header_M_add_headers(self->M.lo,
+ TSDP_HEADER_A_VA_ARGS("connection", "new"),
+ tsk_null
+ );
+ }
+ msrp->offerer = tsk_false;
+ }
+ else{ /* We are probably about to send initial INVITE */
+ tsdp_header_M_add_headers(self->M.lo,
+ TSDP_HEADER_A_VA_ARGS("connection", "new"),
+ tsk_null
+ );
+ msrp->offerer = tsk_true;
+ }
+
+ /* Other SDP fields */
+ populate_lo(msrp, tsk_true);
+ } // !lo
+
+
+ return self->M.lo;
+}
+
+int tdav_session_msrp_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ tdav_session_msrp_t* msrp;
+ const tsdp_header_A_t* A;
+ tsk_bool_t answer;
+
+ TSK_DEBUG_INFO("tdav_session_msrp_set_ro");
+
+ if(!self || !m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ msrp = (tdav_session_msrp_t*)self;
+
+ // answer or initial offer?
+ answer = (self->M.lo != tsk_null);
+
+ /* update remote offer */
+ TSK_OBJECT_SAFE_FREE(self->M.ro);
+ self->M.ro = tsk_object_ref((void*)m);
+
+ if(self->M.lo){
+ if((match_offer(msrp, m))){
+
+ }
+ else{
+ TSK_DEBUG_ERROR("MSRP offer doesn't match");
+ return -1;
+ }
+ /* QoS */
+ if(self->qos){
+ tmedia_qos_tline_t* ro_tline;
+ if(self->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(self->M.ro))){
+ tmedia_qos_tline_set_ro(self->qos, ro_tline);
+ TSK_OBJECT_SAFE_FREE(ro_tline);
+ }
+ }
+ }
+
+ /* To-Path */
+ if((A = tsdp_header_M_findA(m, "path"))){
+ tmsrp_uri_t* uri;
+ if((uri = tmsrp_uri_parse(A->value, tsk_strlen(A->value)))){
+ TSK_OBJECT_SAFE_FREE(msrp->config->To_Path);
+ msrp->config->To_Path = tmsrp_header_To_Path_create(uri);
+ TSK_OBJECT_SAFE_FREE(uri);
+ }
+ }
+
+ // OMA-TS-SIMPLE_IM-V1_0-20080903-C - 5.8.1 Negotiate direction of the MSRP connection setup
+ if((A = tsdp_header_M_findA(m, "setup"))){
+ tdav_msrp_setup_t setup = setup_from_string(A->value);
+ switch(setup){
+ case msrp_setup_actpass:
+ case msrp_setup_passive:
+ msrp->setup = msrp_setup_active;
+ break;
+ case msrp_setup_active:
+ msrp->setup = msrp_setup_passive;
+ break;
+ }
+ }
+
+ /* Neg parameters */
+ init_neg_types(msrp, m);
+
+
+ /* [OMA-TS-SIMPLE_IM-V1_0-20100322-C] - 5.8.2 Support of Application Level Gateway */
+
+ /* get connection associated to this media line
+ * If the connnection is global, then the manager will call tdav_session_audio_set() */
+ if(m->C && m->C->addr && !msrp->remote_ip){
+ tsk_strupdate(&msrp->remote_ip, m->C->addr);
+ msrp->useIPv6 = tsk_striequals(m->C->addrtype, "IP6");
+ }
+ /* set remote port */
+ msrp->remote_port = m->port;
+
+ return 0;
+}
+
+/* ============ Public functions ================= */
+int tdav_session_msrp_send_file(tmedia_session_msrp_t* self, const char* path, va_list *app)
+{
+ tdav_session_msrp_t* msrp;
+ int ret;
+
+ if(!path || !(msrp = (tdav_session_msrp_t*)self) || !msrp->sender){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ //if(1 || !msrp->file.selector){
+ // /* File transfer without selector line
+ // - a=file-selector:name:"test.pcap" type:application/octet-stream size:20312
+ // */
+ // FILE* file = fopen(path, "rb");
+ // const char* fname = path + tsk_strlen(path);
+ // while(fname && (fname> path) && *fname != '\\' && *fname != '/'){
+ // fname--;
+ // }
+
+ // if(file){
+ // tsk_size_t size = 0;
+ // fseek(file, 0L, SEEK_END);
+ // size = ftell(file);
+ // fclose(file);
+
+ // tsk_sprintf(&msrp->file.selector, "name:\"%s\" type:application/octet-stream size:%u",
+ // fname, size);
+ // tsdp_header_M_add_headers(TMEDIA_SESSION(self)->M.lo,
+ // TSDP_HEADER_A_VA_ARGS("file-selector", msrp->file.selector),
+ // tsk_null);
+ // }
+ //}
+
+ ret = tsmrp_sender_send_file(msrp->sender, path);
+
+ return ret;
+}
+
+int tdav_session_msrp_send_message(tmedia_session_msrp_t* self, const void* data, tsk_size_t size, const tmedia_params_L_t *params)
+{
+ const tdav_session_msrp_t* msrp;
+ const tmedia_param_t* param;
+ int ret;
+ const tsk_list_item_t* item;
+ const char* content_type = tsk_null;
+ const char* w_content_type = tsk_null;
+
+ if(!data || !size || !(msrp = (tdav_session_msrp_t*)self) || !msrp->sender){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_foreach(item, params){
+ if((param = TMEDIA_PARAM(item->data))){
+ if((param->media_type & tmedia_msrp) == param->media_type
+ && param->plugin_type == tmedia_ppt_session
+ && param->value_type == tmedia_pvt_pchar){
+
+ if(tsk_striequals(param->key, "content-type")){
+ content_type = (const char*)param->value;
+ }
+ else if(tsk_striequals(param->key, "w-content-type")){
+ w_content_type = (const char*)param->value;
+ }
+ }
+ }
+ }
+
+ if(content_type || w_content_type){ // user-defined content-types
+ ret = tsmrp_sender_send_data(msrp->sender, data, size, content_type, w_content_type);
+ }
+ else{ // neg. content-types
+ ret = tsmrp_sender_send_data(msrp->sender, data, size,
+ msrp->neg_accept_type, msrp->neg_accept_w_type
+ );
+ }
+
+ return ret;
+}
+
+
+
+
+
+//=================================================================================================
+// Session MSRp Plugin object definition
+//
+/* constructor */
+static tsk_object_t* tdav_session_msrp_ctor(tsk_object_t * self, va_list * app)
+{
+ tdav_session_msrp_t *session = self;
+ if(session){
+ /* init base: called by tmedia_session_create() */
+ /* init self */
+ TMEDIA_SESSION_MSRP(session)->send_file = tdav_session_msrp_send_file;
+ TMEDIA_SESSION_MSRP(session)->send_message = tdav_session_msrp_send_message;
+
+ session->config = tmsrp_config_create();
+ session->setup = msrp_setup_actpass; /* draft-denis-simple-msrp-comedia-02 - 4.1.1. Sending the offer */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tdav_session_msrp_dtor(tsk_object_t * self)
+{
+ tdav_session_msrp_t *session = self;
+ if(session){
+
+ /* deinit self (rtp manager should be destroyed after the producer) */
+ TSK_OBJECT_SAFE_FREE(session->config);
+
+ TSK_OBJECT_SAFE_FREE(session->receiver);
+ TSK_OBJECT_SAFE_FREE(session->sender);
+ TSK_OBJECT_SAFE_FREE(session->transport);
+
+ TSK_FREE(session->remote_ip);
+ TSK_FREE(session->local_ip);
+
+ TSK_FREE(session->neg_accept_type);
+ TSK_FREE(session->neg_accept_w_type);
+ TSK_FREE(session->accept_types);
+ TSK_FREE(session->accept_w_types);
+
+ /* File */
+ TSK_FREE(session->file.path);
+ TSK_FREE(session->file.selector);
+ TSK_FREE(session->file.disposition);
+ TSK_FREE(session->file.date);
+ TSK_FREE(session->file.icon);
+ TSK_FREE(session->file.transfer_id);
+
+ /* NAT Traversal context */
+ TSK_OBJECT_SAFE_FREE(session->natt_ctx);
+
+ /* deinit base */
+ tmedia_session_deinit(self);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tdav_session_msrp_def_s =
+{
+ sizeof(tdav_session_msrp_t),
+ tdav_session_msrp_ctor,
+ tdav_session_msrp_dtor,
+ tmedia_session_cmp,
+};
+/* plugin definition*/
+static const tmedia_session_plugin_def_t tdav_session_msrp_plugin_def_s =
+{
+ &tdav_session_msrp_def_s,
+
+ tmedia_msrp,
+ "message",
+
+ tdav_session_msrp_set,
+ tdav_session_msrp_prepare,
+ tdav_session_msrp_start,
+ tdav_session_msrp_pause,
+ tdav_session_msrp_stop,
+
+ /* Audio part */
+ { tsk_null },
+
+ tdav_session_msrp_get_lo,
+ tdav_session_msrp_set_ro
+};
+const tmedia_session_plugin_def_t *tdav_session_msrp_plugin_def_t = &tdav_session_msrp_plugin_def_s;
+
OpenPOWER on IntegriCloud