Commit ce24877b authored by johan's avatar johan

File transfer: add a cancel function to the core

- allow cancellation during upload or download
+ fix bug in file transfer message tester
parent d8cc5b60
......@@ -48,10 +48,13 @@ static size_t linphone_chat_message_compute_filepart_header_size(const char *fil
}
static void process_io_error(void *data, const belle_sip_io_error_event_t *event){
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
ms_error("I/O Error during file upload or download to/from %s - msg [%p] chat room[%p]", msg->chat_room->lc->file_transfer_server, msg, msg->chat_room);
msg->cb(msg, LinphoneChatMessageStateNotDelivered, msg->chat_room->lc);
}
static void process_auth_requested(void *data, belle_sip_auth_event_t *event){
printf("We have a auth requested!\n");
LinphoneChatMessage* msg=(LinphoneChatMessage *)data;
ms_error("Error during file upload or download : auth requested to connect %s - msg [%p] chat room[%p]", msg->chat_room->lc->file_transfer_server, msg, msg->chat_room);
msg->cb(msg, LinphoneChatMessageStateNotDelivered, msg->chat_room->lc);
}
/**
......@@ -157,9 +160,14 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg);
msg->http_request=req; /* update the reference to the http request to be able to cancel it during upload */
belle_http_provider_send_request(msg->chat_room->lc->http_provider,req,l);
}
if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */
if (code == 200 ) { /* file has been uploaded correctly, get server reply and send it */
/* TODO Check that the transfer has not been cancelled, note this shall be removed once the belle sip API will provide a cancel request as we shall never reach this part if the transfer is actually cancelled */
if (msg->http_request == NULL) {
return;
}
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
msg->message = ms_strdup(body);
linphone_content_uninit(msg->file_transfer_information);
......@@ -338,6 +346,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
cbs.process_io_error=process_io_error;
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */
msg->http_request = req; /* keep a reference on the request to be able to cancel it */
belle_http_provider_send_request(cr->lc->http_provider,req,l);
linphone_chat_message_unref(msg);
return;
......@@ -371,8 +380,8 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
sal_message_send(op,identity,cr->peer,content_type, NULL);
ms_free(content_type);
} else {
if (msg->content_type == NULL) {
} else { /* the message is either text or have a file transfer using RCS recommendation */
if (msg->content_type == NULL) { /* if no content type is specified, it is a text message */
sal_text_send(op, identity, cr->peer,msg->message);
} else {
sal_message_send(op, identity, cr->peer, msg->content_type, msg->message);
......@@ -450,7 +459,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer bu twe shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */
if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer but we shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */
xmlChar *file_url = NULL;
xmlDocPtr xmlMessageBody;
xmlNodePtr cur;
......@@ -668,6 +677,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con
msg->is_read=TRUE;
msg->content_type = NULL; /* this property is used only when transfering file */
msg->file_transfer_information = NULL; /* this property is used only when transfering file */
msg->http_request = NULL;
return msg;
}
......@@ -953,9 +963,12 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const
}
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const uint8_t *buffer, size_t size){
//printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer);
LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data;
LinphoneCore *lc = chatMsg->chat_room->lc;
/* TODO: while belle sip doesn't implement the cancel http request method, test if a request is still linked to the message before forwarding the data to callback */
if (chatMsg->http_request == NULL) {
return;
}
/* call back given by application level */
if (lc->vtable.file_transfer_received != NULL) {
lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
......@@ -1036,7 +1049,7 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
*
* @param message #LinphoneChatMessage
*/
void linphone_chat_message_start_file_download(const LinphoneChatMessage *message) {
void linphone_chat_message_start_file_download(LinphoneChatMessage *message) {
belle_http_request_listener_callbacks_t cbs={0};
belle_http_request_listener_t *l;
belle_generic_uri_t *uri;
......@@ -1059,8 +1072,25 @@ void linphone_chat_message_start_file_download(const LinphoneChatMessage *messag
cbs.process_auth_requested=process_auth_requested;
l=belle_http_request_listener_create_from_callbacks(&cbs, (void *)message);
belle_sip_object_data_set(BELLE_SIP_OBJECT(req),"message",(void *)message,NULL);
message->http_request = req; /* keep a reference on the request to be able to cancel the download */
belle_http_provider_send_request(message->chat_room->lc->http_provider,req,l);
}
/**
* Cancel an ongoing file transfer attached to this message.(upload or download)
* @param msg #LinphoneChatMessage
*/
void linphone_chat_room_cancel_file_transfer(LinphoneChatMessage *msg) {
ms_message("Cancelled file transfer %s - msg [%p] chat room[%p]", (msg->external_body_url==NULL)?msg->chat_room->lc->file_transfer_server:msg->external_body_url, msg, msg->chat_room);
/* TODO: here we shall call the cancel http request from bellesip API when it is available passing msg->http_request */
/* waiting for this API, just set to NULL the reference to the request in the message and any request */
msg->http_request = NULL;
if (msg->cb) {
msg->cb(msg, LinphoneChatMessageStateNotDelivered, msg->chat_room->lc);
}
}
/**
* Set origin of the message
*@param message #LinphoneChatMessage obj
......@@ -1288,11 +1318,11 @@ LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneCha
linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr));
linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc)));
msg->content_type=NULL; /* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */
msg->http_request=NULL; /* this will store the http request during file upload to the server */
return msg;
}
/**
* @}
*/
......@@ -1331,7 +1331,8 @@ LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const Linpho
LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url);
LINPHONE_PUBLIC const LinphoneContent* linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_start_file_download(const LinphoneChatMessage*message);
LINPHONE_PUBLIC void linphone_chat_message_start_file_download(LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_room_cancel_file_transfer(LinphoneChatMessage* msg);
LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message);
LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data);
LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* message);
......
......@@ -163,8 +163,9 @@ struct _LinphoneChatMessage {
bool_t is_read;
unsigned int storage_id;
SalOp *op;
LinphoneContent *file_transfer_information;
char *content_type;
LinphoneContent *file_transfer_information; /**< used to store file transfer information when the message is of file transfer type */
char *content_type; /**< is used to specified the type of message to be sent, used only for file transfer message */
belle_http_request_t *http_request; /**< keep a reference to the http_request in case of file transfer in order to be able to cancel the transfer */
};
BELLE_SIP_DECLARE_VPTR(LinphoneChatMessage);
......
......@@ -46,11 +46,11 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess
ms_free(from);
counters = get_stats(lc);
counters->number_of_LinphoneMessageReceived++;
if (linphone_chat_message_get_file_transfer_information(message))
counters->number_of_LinphoneMessageReceivedWithFile++;
if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message);
linphone_chat_message_ref(counters->last_received_chat_message=message);
if (linphone_chat_message_get_external_body_url(message)) {
if (linphone_chat_message_get_file_transfer_information(message)) {
counters->number_of_LinphoneMessageReceivedWithFile++;
} else if (linphone_chat_message_get_external_body_url(message)) {
counters->number_of_LinphoneMessageExtBodyReceived++;
if (message_external_body_url) {
CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url);
......@@ -75,7 +75,7 @@ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, cons
/*next chunk*/
file = (FILE*)linphone_chat_message_get_user_data(message);
if (size==0) { /* tranfer complerte */
if (size==0) { /* tranfer complete */
stats* counters = get_stats(lc);
linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message));
linphone_chat_message_destroy(message);
......@@ -377,10 +377,10 @@ static void file_transfer_message(void) {
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1));
if (marie->stat.last_received_info_message ) {
linphone_chat_message_start_file_download((const LinphoneChatMessage*)marie->stat.last_received_info_message);
if (marie->stat.last_received_chat_message ) {
linphone_chat_message_start_file_download(marie->stat.last_received_chat_message);
}
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1));
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1);
......@@ -439,6 +439,111 @@ static void file_transfer_message_io_error(void) {
linphone_core_manager_destroy(pauline);
}
static void file_transfer_message_upload_cancelled(void) {
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneContent content;
const char* big_file_content="big file"; /* setting dummy file content to something */
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
reset_counters(&marie->stat);
reset_counters(&pauline->stat);
/* setting dummy file content to something */
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
/* Globally configure an http file transfer server. */
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
/* create a file transfer message */
memset(&content,0,sizeof(content));
content.type="text";
content.subtype="plain";
content.size=sizeof(big_file); /*total size to be transfered*/
content.name = "bigfile.txt";
message = linphone_chat_room_create_file_transfer_message(chat_room, &content);
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
/*wait for file to be 50% uploaded and cancel the transfer */
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer, 50));
linphone_chat_room_cancel_file_transfer(message);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,0);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void file_transfer_message_download_cancelled(void) {
int i;
char* to;
LinphoneChatRoom* chat_room;
LinphoneChatMessage* message;
LinphoneContent content;
const char* big_file_content="big file"; /* setting dummy file content to something */
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
reset_counters(&marie->stat);
reset_counters(&pauline->stat);
/* setting dummy file content to something */
for (i=0;i<sizeof(big_file);i+=strlen(big_file_content))
memcpy(big_file+i, big_file_content, strlen(big_file_content));
big_file[0]=*"S";
big_file[sizeof(big_file)-1]=*"E";
/* Globally configure an http file transfer server. */
linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php");
/* create a chatroom on pauline's side */
to = linphone_address_as_string(marie->identity);
chat_room = linphone_core_create_chat_room(pauline->lc,to);
/* create a file transfer message */
memset(&content,0,sizeof(content));
content.type="text";
content.subtype="plain";
content.size=sizeof(big_file); /*total size to be transfered*/
content.name = "bigfile.txt";
message = linphone_chat_room_create_file_transfer_message(chat_room, &content);
linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc);
/* wait for marie to receive pauline's message */
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1));
if (marie->stat.last_received_chat_message ) { /* get last message and use it to download file */
linphone_chat_message_start_file_download(marie->stat.last_received_chat_message);
/* wait for file to be 50% downloaded */
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.progress_of_LinphoneFileTransfer, 50));
/* and cancel the transfer */
linphone_chat_room_cancel_file_transfer(marie->stat.last_received_chat_message);
}
//CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1));
CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,0);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void text_message_with_send_error(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
......@@ -672,6 +777,8 @@ test_t message_tests[] = {
{ "Text message with external body", text_message_with_external_body },
{ "File transfer message", file_transfer_message },
{ "File transfer message with io error", file_transfer_message_io_error },
{ "File transfer message upload cancelled", file_transfer_message_upload_cancelled },
{ "File transfer message download cancelled", file_transfer_message_download_cancelled },
{ "Text message denied", text_message_denied },
{ "Info message", info_message },
{ "Info message with body", info_message_with_body },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment