sal_op_impl.c 11.3 KB
Newer Older
jehan's avatar
jehan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
linphone
Copyright (C) 2012  Belledonne Communications, Grenoble, France

This program 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 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "sal_impl.h"


/*create an operation */
SalOp * sal_op_new(Sal *sal){
	SalOp *op=ms_new0(SalOp,1);
	__sal_op_init(op,sal);
26
	op->type=SalOpUnknown;
27
	sal_op_ref(op);
jehan's avatar
jehan committed
28 29 30
	return op;
}
void sal_op_release(SalOp *op){
31
	op->state=SalOpStateTerminated;
32 33 34
	sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn not mean freeing op. Make sure back pointer will not be used later*/
	if (op->registration_refresher) belle_sip_refresher_stop(op->registration_refresher);
	if (op->refresher) belle_sip_refresher_stop(op->refresher);
35 36 37
	sal_op_unref(op);
}
void sal_op_release_impl(SalOp *op){
38
	ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type));
39
	if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction);
40
	if (op->auth_info) sal_auth_info_delete(op->auth_info);
41
	if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer);
42 43 44
	if (op->registration_refresher) {
		belle_sip_refresher_stop(op->registration_refresher);
		belle_sip_object_unref(op->registration_refresher);
45
		op->registration_refresher=NULL;
46
	}
47 48 49
	if(op->replaces) belle_sip_object_unref(op->replaces);
	if(op->referred_by) belle_sip_object_unref(op->referred_by);

50
	if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
jehan's avatar
jehan committed
51
	__sal_op_free(op);
jehan's avatar
jehan committed
52 53
	return ;
}
54

jehan's avatar
jehan committed
55
void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){
56 57 58 59 60 61 62
	if (op->type == SalOpRegister) {
		/*Registration authenticate is just about registering again*/
		sal_register_refresh(op,-1);
	}else {
		/*for sure auth info will be accesible from the provider*/
		sal_process_authentication(op);
	}
jehan's avatar
jehan committed
63 64
	return ;
}
jehan's avatar
jehan committed
65

jehan's avatar
jehan committed
66 67 68 69 70 71
void sal_op_cancel_authentication(SalOp *h){
	ms_fatal("sal_op_cancel_authentication not implemented yet");
	return ;
}

int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){
72 73
	*realm=op->auth_info?op->auth_info->realm:NULL;
	*username=op->auth_info?op->auth_info->username:NULL;
jehan's avatar
jehan committed
74 75
	return 0;
}
jehan's avatar
jehan committed
76 77 78 79 80 81 82 83 84 85 86 87 88
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op,belle_sip_header_from_t* from_header) {
	belle_sip_uri_t* req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)from_header));
	belle_sip_header_contact_t* contact_header;
	if (sal_op_get_contact_address(op)) {
		contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op)));
	} else {
		contact_header= belle_sip_header_contact_new();
		belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,belle_sip_uri_new());
		belle_sip_uri_set_user(belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact_header),belle_sip_uri_get_user(req_uri));
	}
	belle_sip_object_unref(req_uri);
	return contact_header;
}
jehan's avatar
jehan committed
89
belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
jehan's avatar
jehan committed
90 91
	belle_sip_header_from_t* from_header;
	belle_sip_header_to_t* to_header;
jehan's avatar
jehan committed
92 93
	belle_sip_provider_t* prov=op->base.root->prov;
	belle_sip_request_t *req;
jehan's avatar
jehan committed
94 95 96
	belle_sip_uri_t* req_uri;
	char token[10];

jehan's avatar
jehan committed
97 98 99 100
	from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))
												,belle_sip_random_token(token,sizeof(token)));
	to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL);
	req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header));
jehan's avatar
jehan committed
101 102 103

	req=belle_sip_request_create(
							req_uri,
jehan's avatar
jehan committed
104
							method,
jehan's avatar
jehan committed
105
		                    belle_sip_provider_create_call_id(prov),
jehan's avatar
jehan committed
106
		                    belle_sip_header_cseq_create(20,method),
jehan's avatar
jehan committed
107 108 109 110
		                    from_header,
		                    to_header,
		                    belle_sip_header_via_new(),
		                    70);
jehan's avatar
jehan committed
111

jehan's avatar
jehan committed
112
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->base.root->user_agent));
jehan's avatar
jehan committed
113
	return req;
jehan's avatar
jehan committed
114 115 116
}


jehan's avatar
jehan committed
117

jehan's avatar
jehan committed
118 119
/*ping: main purpose is to obtain its own contact address behind firewalls*/
int sal_ping(SalOp *op, const char *from, const char *to){
jehan's avatar
jehan committed
120 121 122
	sal_op_set_from(op,from);
	sal_op_set_to(op,to);
	return sal_op_send_request(op,sal_op_build_request(op,"OPTION"));
jehan's avatar
jehan committed
123 124
}

jehan's avatar
jehan committed
125 126 127
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) {
	belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t);
	char user_agent_string[256];
jehan's avatar
jehan committed
128
	if(user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) {
jehan's avatar
jehan committed
129 130 131 132 133
		op->base.remote_ua=ms_strdup(user_agent_string);
	}
}

void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
134
	belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ);
jehan's avatar
jehan committed
135 136 137
	belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
	sal_op_send_request(op,request);
}
138

jehan's avatar
jehan committed
139 140

static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request,bool_t add_contact) {
jehan's avatar
jehan committed
141 142
	belle_sip_client_transaction_t* client_transaction;
	belle_sip_provider_t* prov=op->base.root->prov;
143
	belle_sip_uri_t* outbound_proxy=NULL;
jehan's avatar
jehan committed
144
	belle_sip_header_contact_t* contact;
Simon Morlat's avatar
Simon Morlat committed
145
	
146 147
	if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) {
		/*don't put route header if  dialog is in confirmed state*/
Simon Morlat's avatar
Simon Morlat committed
148 149 150 151 152 153 154 155
		const MSList *elem=sal_op_get_route_addresses(op);
		belle_sip_uri_t *next_hop_uri;
		const char *transport;
		if (elem) {
			outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data);
			next_hop_uri=outbound_proxy;
		}else{
			next_hop_uri=belle_sip_request_get_uri(request);
jehan's avatar
jehan committed
156
		}
Simon Morlat's avatar
Simon Morlat committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		transport=belle_sip_uri_get_transport_param(next_hop_uri);
		if (transport==NULL){
			/*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use
			 * the first available transport*/
			if (belle_sip_provider_get_listening_point(prov,"UDP")==0){
				if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){
					transport="tcp";
				}else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL){
					transport="tls";
				}
			}
			if (transport){
				belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport);
				belle_sip_uri_set_transport_param(next_hop_uri,transport);
			}
			belle_sip_uri_fix(next_hop_uri);
173
		}
jehan's avatar
jehan committed
174
	}
175

jehan's avatar
jehan committed
176
	client_transaction = belle_sip_provider_create_client_transaction(prov,request);
177
	belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op));
178 179 180 181
	if ( strcmp("INVITE",belle_sip_request_get_method(request))==0 ||  strcmp("REGISTER",belle_sip_request_get_method(request))==0) {
		if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
		op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/
		belle_sip_object_ref(op->pending_client_trans);
182
	}
jehan's avatar
jehan committed
183 184
	if (add_contact) {
		contact = sal_op_create_contact(op,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_from_t));
jehan's avatar
jehan committed
185
		belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT);
jehan's avatar
jehan committed
186 187
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
	}
188
	if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION)
jehan's avatar
jehan committed
189 190
		&& !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) {
		/*hmm just in case we already have authentication param in cache*/
191
		belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL);
jehan's avatar
jehan committed
192
	}
193
	return belle_sip_client_transaction_send_request_to(client_transaction,outbound_proxy/*might be null*/);
jehan's avatar
jehan committed
194

jehan's avatar
jehan committed
195
}
jehan's avatar
jehan committed
196

jehan's avatar
jehan committed
197
int sal_op_send_request(SalOp* op, belle_sip_request_t* request)  {
jehan's avatar
jehan committed
198
	bool_t need_contact=FALSE;
jehan's avatar
jehan committed
199 200 201 202 203 204 205 206 207
	/*
  	  Header field          where   proxy ACK BYE CAN INV OPT REG
      ___________________________________________________________
      Contact                 R            o   -   -   m   o   o
	 */
	if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
			||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
			||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0
			||strcmp(belle_sip_request_get_method(request),"OPTION")==0)
jehan's avatar
jehan committed
208
		need_contact=TRUE;
jehan's avatar
jehan committed
209

jehan's avatar
jehan committed
210
	return _sal_op_send_request_with_contact(op, request,need_contact);
jehan's avatar
jehan committed
211 212
}

jehan's avatar
jehan committed
213

214
void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) {
jehan's avatar
jehan committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
		switch(code) {
		case 400:
			*sal_err=SalErrorUnknown;
			break;
		case 404:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonNotFound;
			break;
		case 415:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonMedia;
			break;
		case 422:
			ms_error ("422 not implemented yet");;
			break;
		case 480:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonTemporarilyUnavailable;
			break;
		case 486:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonBusy;
			break;
		case 487:
			break;
		case 600:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonDoNotDisturb;
			break;
		case 603:
			*sal_err=SalErrorFailure;
			*sal_reason=SalReasonDeclined;
			break;
		default:
			if (code>0){
				*sal_err=SalErrorFailure;
				*sal_reason=SalReasonUnknown;
			}else *sal_err=SalErrorNoResponse;
			/* no break */
		}
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}
/*return TRUE if error code*/
bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) {
	int code = belle_sip_response_get_status_code(response);
	belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
	*sal_err=SalErrorUnknown;
	*sal_reason = SalReasonUnknown;

	if (reason_header){
		snprintf(reason
				,reason_size
				,"%s %s"
				,belle_sip_response_get_reason_phrase(response)
				,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
	} else {
		strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size);
	}
	if (code>400) {
		sal_compute_sal_errors_from_code(code,sal_err,sal_reason);
jehan's avatar
jehan committed
274 275 276 277 278
		return TRUE;
	} else {
		return FALSE;
	}
}
279
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
280
	/*check if dialog has changed*/
281
	if (dialog && dialog != op->dialog) {
282
		ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op);
283
		/*fixme, shouldn't we cancel previous dialog*/
284 285 286 287 288
		if (op->dialog) {
			belle_sip_dialog_set_application_data(op->dialog,NULL);
			belle_sip_object_unref(op->dialog);
			sal_op_unref(op);
		}
289
		op->dialog=dialog;
290
		belle_sip_dialog_set_application_data(op->dialog,op);
291
		sal_op_ref(op);
292 293 294
		belle_sip_object_ref(op->dialog);
	}
}
295 296 297 298 299 300 301 302 303 304 305 306
/*return reffed op*/
SalOp* sal_op_ref(SalOp* op) {
	op->ref++;
	return op;
}
/*return null, destroy op if ref count =0*/
void* sal_op_unref(SalOp* op) {
	if (--op->ref <=0) {
		sal_op_release_impl(op);
	}
	return NULL;
}