diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c deleted file mode 100644 index aca1caacf..000000000 --- a/coreapi/sal_eXosip2.c +++ /dev/null @@ -1,2692 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "sal_eXosip2.h" -#include "offeranswer.h" - -#ifdef ANDROID -// Necessary to make it linked -static void for_linker() { eXosip_transport_hook_register(NULL); } -#endif -static bool_t call_failure(Sal *sal, eXosip_event_t *ev); - -static void text_received(Sal *sal, eXosip_event_t *ev); - -static void masquerade_via(osip_message_t *msg, const char *ip, const char *port); -static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact); -static void update_contact_from_response(SalOp *op, osip_message_t *response); - - -void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ - void *data; - while(!osip_list_eol(l,0)) { - data=osip_list_get(l,0); - osip_list_remove(l,0); - if (data) freefunc(data); - } -} - -void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){ - if (eXosip_guess_localip(address_family,ip,iplen)<0){ - /*default to something */ - strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); - ms_error("Could not find default routable ip address !"); - } -} - -static SalOp * sal_find_call(Sal *sal, int cid){ - const MSList *elem; - SalOp *op; - for(elem=sal->calls;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->cid==cid) return op; - } - return NULL; -} - -static void sal_add_call(Sal *sal, SalOp *op){ - sal->calls=ms_list_append(sal->calls,op); -} - -static void sal_remove_call(Sal *sal, SalOp *op){ - sal->calls=ms_list_remove(sal->calls, op); -} - -static SalOp * sal_find_register(Sal *sal, int rid){ - const MSList *elem; - SalOp *op; - for(elem=sal->registers;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->rid==rid) return op; - } - return NULL; -} - -static void sal_add_register(Sal *sal, SalOp *op){ - sal->registers=ms_list_append(sal->registers,op); -} - -static void sal_remove_register(Sal *sal, int rid){ - MSList *elem; - SalOp *op; - for(elem=sal->registers;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->rid==rid) { - sal->registers=ms_list_remove_link(sal->registers,elem); - return; - } - } -} - -static SalOp * sal_find_other(Sal *sal, osip_message_t *message){ - const MSList *elem; - SalOp *op; - osip_call_id_t *callid=osip_message_get_call_id(message); - if (callid==NULL) { - ms_error("There is no call-id in this message !"); - return NULL; - } - for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (osip_call_id_match(callid,op->call_id)==0) return op; - } - return NULL; -} - -void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ - osip_call_id_t *callid=osip_message_get_call_id(request); - if (callid==NULL) { - ms_error("There is no call id in the request !"); - return; - } - osip_call_id_clone(callid,&op->call_id); - sal->other_transactions=ms_list_append(sal->other_transactions,op); -} - -static void sal_remove_other(Sal *sal, SalOp *op){ - sal->other_transactions=ms_list_remove(sal->other_transactions,op); -} - - -static void sal_add_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_append(sal->pending_auths,op); -} - - -static void sal_remove_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_remove(sal->pending_auths,op); -} - -void sal_exosip_fix_route(SalOp *op){ - if (sal_op_get_route(op)!=NULL){ - osip_route_t *rt=NULL; - osip_uri_param_t *lr_param=NULL; - - osip_route_init(&rt); - if (osip_route_parse(rt,sal_op_get_route(op))<0){ - ms_warning("Bad route %s!",sal_op_get_route(op)); - sal_op_set_route(op,NULL); - }else{ - /* check if the lr parameter is set , if not add it */ - osip_uri_uparam_get_byname(rt->url, "lr", &lr_param); - if (lr_param==NULL){ - char *tmproute; - osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); - osip_route_to_str(rt,&tmproute); - sal_op_set_route(op,tmproute); - osip_free(tmproute); - } - } - osip_route_free(rt); - } -} - -SalOp * sal_op_new(Sal *sal){ - SalOp *op=ms_new0(SalOp,1); - __sal_op_init(op,sal); - op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1; - op->result=NULL; - op->supports_session_timers=FALSE; - op->sdp_offering=TRUE; - op->pending_auth=NULL; - op->sdp_answer=NULL; - op->reinvite=FALSE; - op->call_id=NULL; - op->replaces=NULL; - op->referred_by=NULL; - op->masquerade_via=FALSE; - op->auto_answer_asked=FALSE; - op->auth_info=NULL; - op->terminated=FALSE; - return op; -} - -bool_t sal_call_autoanswer_asked(SalOp *op) -{ - return op->auto_answer_asked; -} - -void sal_op_release(SalOp *op){ - if (op->sdp_answer) - sdp_message_free(op->sdp_answer); - if (op->pending_auth) - eXosip_event_free(op->pending_auth); - if (op->rid!=-1){ - sal_remove_register(op->base.root,op->rid); - eXosip_register_remove(op->rid); - } - if (op->cid!=-1){ - ms_message("Cleaning cid %i",op->cid); - sal_remove_call(op->base.root,op); - } - if (op->sid!=-1){ - sal_remove_out_subscribe(op->base.root,op); - } - if (op->nid!=-1){ - sal_remove_in_subscribe(op->base.root,op); - if (op->call_id) - osip_call_id_free(op->call_id); - op->call_id=NULL; - } - if (op->pending_auth){ - sal_remove_pending_auth(op->base.root,op); - } - if (op->result) - sal_media_description_unref(op->result); - if (op->call_id){ - sal_remove_other(op->base.root,op); - osip_call_id_free(op->call_id); - } - if (op->replaces){ - ms_free(op->replaces); - } - if (op->referred_by){ - ms_free(op->referred_by); - } - if (op->auth_info) { - sal_auth_info_delete(op->auth_info); - } - __sal_op_free(op); -} - -static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){ - int ortp_level=ORTP_DEBUG; - switch(level){ - case OSIP_INFO1: - case OSIP_INFO2: - case OSIP_INFO3: - case OSIP_INFO4: - ortp_level=ORTP_MESSAGE; - break; - case OSIP_WARNING: - ortp_level=ORTP_WARNING; - break; - case OSIP_ERROR: - case OSIP_BUG: - ortp_level=ORTP_ERROR; - break; - case OSIP_FATAL: - ortp_level=ORTP_FATAL; - break; - case END_TRACE_LEVEL: - break; - } - if (ortp_log_level_enabled(level)){ - int len=strlen(chfr); - char *chfrdup=ortp_strdup(chfr); - /*need to remove endline*/ - if (len>1){ - if (chfrdup[len-1]=='\n') - chfrdup[len-1]='\0'; - if (chfrdup[len-2]=='\r') - chfrdup[len-2]='\0'; - } - ortp_logv(ortp_level,chfrdup,ap); - ortp_free(chfrdup); - } -} - - -Sal * sal_init(){ - static bool_t firsttime=TRUE; - Sal *sal; - if (firsttime){ - osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); - firsttime=FALSE; - } - eXosip_init(); - sal=ms_new0(Sal,1); - sal->keepalive_period=30; - sal->double_reg=TRUE; - sal->use_rports=TRUE; - sal->use_101=TRUE; - sal->reuse_authorization=FALSE; - sal->rootCa = 0; - sal->verify_server_certs=TRUE; - sal->verify_server_cn=TRUE; - sal->expire_old_contact=FALSE; - sal->add_dates=FALSE; - sal->dscp=-1; - return sal; -} - -void sal_uninit(Sal* sal){ - eXosip_quit(); - if (sal->rootCa) - ms_free(sal->rootCa); - ms_free(sal); -} - -void sal_set_user_pointer(Sal *sal, void *user_data){ - sal->up=user_data; -} - -void *sal_get_user_pointer(const Sal *sal){ - return sal->up; -} - -static void unimplemented_stub(){ - ms_warning("Unimplemented SAL callback"); -} - -void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ - memcpy(&ctx->callbacks,cbs,sizeof(*cbs)); - if (ctx->callbacks.call_received==NULL) - ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub; - if (ctx->callbacks.call_ringing==NULL) - ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub; - if (ctx->callbacks.call_accepted==NULL) - ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub; - if (ctx->callbacks.call_failure==NULL) - ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; - if (ctx->callbacks.call_terminated==NULL) - ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; - if (ctx->callbacks.call_released==NULL) - ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub; - if (ctx->callbacks.call_updating==NULL) - ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; - if (ctx->callbacks.auth_requested==NULL) - ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; - if (ctx->callbacks.auth_success==NULL) - ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub; - if (ctx->callbacks.register_success==NULL) - ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; - if (ctx->callbacks.register_failure==NULL) - ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; - if (ctx->callbacks.dtmf_received==NULL) - ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; - if (ctx->callbacks.notify==NULL) - ctx->callbacks.notify=(SalOnNotify)unimplemented_stub; - if (ctx->callbacks.notify_presence==NULL) - ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; - if (ctx->callbacks.subscribe_received==NULL) - ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; - if (ctx->callbacks.text_received==NULL) - ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; - if (ctx->callbacks.ping_reply==NULL) - ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; -} - -int sal_unlisten_ports(Sal *ctx){ - if (ctx->running){ - eXosip_quit(); - eXosip_init(); - ctx->running=FALSE; - } - return 0; -} - -int sal_reset_transports(Sal *ctx){ -#ifdef HAVE_EXOSIP_RESET_TRANSPORTS - if (ctx->running){ - ms_message("Exosip transports reset."); - eXosip_reset_transports(); - } - return 0; -#else - ms_warning("sal_reset_transports() not implemented in this version."); - return -1; -#endif -} - - -static void set_tls_options(Sal *ctx){ - if (ctx->rootCa) { - eXosip_tls_ctx_t tlsCtx; - memset(&tlsCtx, 0, sizeof(tlsCtx)); - snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa); - eXosip_set_tls_ctx(&tlsCtx); - } -#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE - eXosip_tls_verify_certificate(ctx->verify_server_certs); -#endif -#ifdef HAVE_EXOSIP_TLS_VERIFY_CN - eXosip_tls_verify_cn(ctx->verify_server_cn); -#endif -} - -void sal_set_dscp(Sal *ctx, int dscp){ - ctx->dscp=dscp; -#ifdef HAVE_EXOSIP_DSCP - if (dscp!=-1) - eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp); -#endif -} - -int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ - int err; - bool_t ipv6; - int proto=IPPROTO_UDP; - int keepalive = ctx->keepalive_period; - - ctx->transport = tr; - switch (tr) { - case SalTransportUDP: - proto=IPPROTO_UDP; - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive); - break; - case SalTransportTCP: - case SalTransportTLS: - proto= IPPROTO_TCP; - if (!ctx->tcp_tls_keepalive) keepalive=-1; - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive); - set_tls_options(ctx); - break; - default: - ms_warning("unexpected proto, using datagram"); - } - /*see if it looks like an IPv6 address*/ - int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment - eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports); - int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment - eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101); - sal_set_dscp(ctx,ctx->dscp); - sal_use_dates(ctx,ctx->add_dates); - - ipv6=strchr(addr,':')!=NULL; - eXosip_enable_ipv6(ipv6); - - if (is_secure && tr == SalTransportUDP){ - ms_fatal("SIP over DTLS is not supported yet."); - return -1; - } - err=eXosip_listen_addr(proto, addr, port, ipv6 ? PF_INET6 : PF_INET, is_secure); - ctx->running=TRUE; - return err; -} - -ortp_socket_t sal_get_socket(Sal *ctx){ -#ifdef HAVE_EXOSIP_GET_SOCKET - return eXosip_get_socket(IPPROTO_UDP); -#else - ms_warning("Sorry, eXosip does not have eXosip_get_socket() method"); - return -1; -#endif -} - -void sal_set_user_agent(Sal *ctx, const char *user_agent){ - eXosip_set_user_agent(user_agent); -} - -void sal_append_stack_string_to_user_agent(Sal *ctx) { - /* Not implemented for eXosip */ -} - -void sal_use_session_timers(Sal *ctx, int expires){ - ctx->session_expires=expires; -} - -void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ctx->one_matching_codec=one_matching_codec; -} - -MSList *sal_get_pending_auths(Sal *sal){ - return ms_list_copy(sal->pending_auths); -} - -void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ctx->double_reg=enabled; -} - -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ - ctx->expire_old_contact=enabled; -} - -void sal_use_dates(Sal *ctx, bool_t enabled){ - ctx->add_dates=enabled; -#ifdef EXOSIP_OPT_REGISTER_WITH_DATE - { - int tmp=enabled; - eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp); - } -#else - if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option."); -#endif -} - -void sal_use_rport(Sal *ctx, bool_t use_rports){ - ctx->use_rports=use_rports; -} -void sal_use_101(Sal *ctx, bool_t use_101){ - ctx->use_101=use_101; -} - -void sal_set_root_ca(Sal* ctx, const char* rootCa) { - if (ctx->rootCa) - ms_free(ctx->rootCa); - ctx->rootCa = ms_strdup(rootCa); - set_tls_options(ctx); -} - -const char *sal_get_root_ca(Sal* ctx) { - return ctx->rootCa; -} - -void sal_verify_server_certificates(Sal *ctx, bool_t verify){ - ctx->verify_server_certs=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE - eXosip_tls_verify_certificate(verify); -#endif -} - -void sal_verify_server_cn(Sal *ctx, bool_t verify){ - ctx->verify_server_cn=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CN - eXosip_tls_verify_cn(verify); -#endif -} - -static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){ - osip_via_t *via=NULL; - osip_generic_param_t *param=NULL; - const char *rport=NULL; - - *rportval=5060; - *received=NULL; - osip_message_get_via(msg,0,&via); - if (!via) { - ms_warning("extract_received_rport(): no via."); - return -1; - } - - *transport = sal_transport_parse(via->protocol); - - if (via->port && via->port[0]!='\0') - *rportval=atoi(via->port); - - osip_via_param_get_byname(via,"rport",¶m); - if (param) { - rport=param->gvalue; - if (rport && rport[0]!='\0') *rportval=atoi(rport); - *received=via->host; - } - param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param) *received=param->gvalue; - - if (rport==NULL && *received==NULL){ - ms_warning("extract_received_rport(): no rport and no received parameters."); - return -1; - } - return 0; -} - -static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ - int sdplen; - char clen[10]; - char *sdp=NULL; - sdp_message_to_str(msg,&sdp); - sdplen=strlen(sdp); - snprintf(clen,sizeof(clen),"%i",sdplen); - osip_message_set_body(sip,sdp,sdplen); - osip_message_set_content_type(sip,"application/sdp"); - osip_message_set_content_length(sip,clen); - osip_free(sdp); -} - -static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ - sdp_message_t *msg=media_description_to_sdp(desc); - if (msg==NULL) { - ms_error("Fail to print sdp message !"); - return; - } - set_sdp(sip,msg); - sdp_message_free(msg); -} - -static void sdp_process(SalOp *h){ - ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); - if (h->result){ - sal_media_description_unref(h->result); - } - h->result=sal_media_description_new(); - if (h->sdp_offering){ - offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); - }else{ - int i; - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - } - offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result); - /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. - It should contains media parameters constraint from the remote offer, not our response*/ - strcpy(h->result->addr,h->base.remote_media->addr); - h->result->bandwidth=h->base.remote_media->bandwidth; - - for(i=0;iresult->n_active_streams;++i){ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } - } - } - -} - -int sal_call_is_offerer(const SalOp *h){ - return h->sdp_offering; -} - -int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ - if (desc) - sal_media_description_ref(desc); - if (h->base.local_media) - sal_media_description_unref(h->base.local_media); - h->base.local_media=desc; - if (h->base.remote_media){ - /*case of an incoming call where we modify the local capabilities between the time - * the call is ringing and it is accepted (for example if you want to accept without video*/ - /*reset the sdp answer so that it is computed again*/ - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - return 0; -} - -int sal_call(SalOp *h, const char *from, const char *to){ - int err; - const char *route; - osip_message_t *invite=NULL; - osip_call_id_t *callid; - sal_op_set_from(h,from); - sal_op_set_to(h,to); - sal_exosip_fix_route(h); - - h->terminated = FALSE; - - route = sal_op_get_route(h); - err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call"); - if (err!=0){ - ms_error("Could not create call. Error %d (from=%s to=%s route=%s)", - err, from, to, route); - return -1; - } - osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(invite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(invite, "Session-expires", "200"); - osip_message_set_supported(invite, "timer"); - } - sal_exosip_add_custom_headers(invite,h->base.custom_headers); - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(invite,h->base.local_media); - }else h->sdp_offering=FALSE; - if (h->replaces){ - osip_message_set_header(invite,"Replaces",h->replaces); - if (h->referred_by) - osip_message_set_header(invite,"Referred-By",h->referred_by); - } - - eXosip_lock(); - err=eXosip_call_send_initial_invite(invite); - eXosip_unlock(); - h->cid=err; - if (err<0){ - ms_error("Fail to send invite ! Error code %d", err); - return -1; - }else{ - char *tmp=NULL; - callid=osip_message_get_call_id(invite); - osip_call_id_to_str(callid,&tmp); - h->base.call_id=ms_strdup(tmp); - osip_free(tmp); - sal_add_call(h->base.root,h); - } - return 0; -} - -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - osip_message_t *msg; - - /*if early media send also 180 and 183 */ - if (early_media){ - msg=NULL; - eXosip_lock(); - eXosip_call_build_answer(h->tid,183,&msg); - if (msg){ - sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - eXosip_call_send_answer(h->tid,183,msg); - } - eXosip_unlock(); - }else{ - eXosip_lock(); - eXosip_call_send_answer(h->tid,180,NULL); - eXosip_unlock(); - } - return 0; -} - -int sal_call_accept(SalOp * h){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - /* sends a 200 OK */ - int err=eXosip_call_build_answer(h->tid,200,&msg); - if (err<0 || msg==NULL){ - ms_error("Fail to build answer for call: err=%i",err); - return -1; - } - if (h->base.root->session_expires!=0){ - if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); - } - - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - - if (h->base.local_media){ - /*this is the case where we received an invite without SDP*/ - if (h->sdp_offering) { - set_sdp_from_desc(msg,h->base.local_media); - }else{ - if (h->sdp_answer==NULL) sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - }else{ - ms_error("You are accepting a call but not defined any media capabilities !"); - } - eXosip_call_send_answer(h->tid,200,msg); - return 0; -} - -int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){ - if (reason==SalReasonBusy){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,486,NULL); - eXosip_unlock(); - } - else if (reason==SalReasonTemporarilyUnavailable){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,480,NULL); - eXosip_unlock(); - }else if (reason==SalReasonDoNotDisturb){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,600,NULL); - eXosip_unlock(); - }else if (reason==SalReasonMedia){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,415,NULL); - eXosip_unlock(); - }else if (redirect!=NULL && reason==SalReasonRedirect){ - osip_message_t *msg; - int code; - if (strstr(redirect,"sip:")!=0) code=302; - else code=380; - eXosip_lock(); - eXosip_call_build_answer(h->tid,code,&msg); - osip_message_set_contact(msg,redirect); - eXosip_call_send_answer(h->tid,code,msg); - eXosip_unlock(); - }else sal_call_terminate(h); - return 0; -} - -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - return h->base.remote_media; -} - -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - if (h->base.local_media && h->base.remote_media && !h->result){ - sdp_process(h); - } - return h->result; -} - -int sal_call_set_referer(SalOp *h, SalOp *refered_call){ - if (refered_call->replaces) - h->replaces=ms_strdup(refered_call->replaces); - if (refered_call->referred_by) - h->referred_by=ms_strdup(refered_call->referred_by); - return 0; -} - -static int send_notify_for_refer(int did, const char *sipfrag){ - osip_message_t *msg; - eXosip_lock(); - eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Could not build NOTIFY for refer."); - return -1; - } - osip_message_set_content_type(msg,"message/sipfrag"); - osip_message_set_header(msg,"Event","refer"); - osip_message_set_body(msg,sipfrag,strlen(sipfrag)); - eXosip_call_send_request(did,msg); - eXosip_unlock(); - return 0; -} - -/* currently only support to notify trying and 200Ok*/ -int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){ - if (newcall==NULL){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - else if (newcall->cid!=-1){ - if (newcall->did==-1){ - /* not yet established*/ - if (!newcall->terminated){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - }else{ - if (!newcall->terminated){ - if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){ - /* we need previous notify transaction to complete, so buffer the request for later*/ - h->sipfrag_pending="SIP/2.0 200 Ok\r\n"; - } - } - } - } - return 0; -} - -int sal_ping(SalOp *op, const char *from, const char *to){ - osip_message_t *options=NULL; - - sal_op_set_from(op,from); - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - - eXosip_options_build_request (&options, sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (options){ - if (op->base.root->session_expires!=0){ - osip_message_set_header(options, "Session-expires", "200"); - osip_message_set_supported(options, "timer"); - } - sal_add_other(sal_op_get_sal(op),op,options); - return eXosip_options_send_request(options); - } - return -1; -} - -int sal_call_refer(SalOp *h, const char *refer_to){ - osip_message_t *msg=NULL; - int err=0; - eXosip_lock(); - eXosip_call_build_refer(h->did,refer_to, &msg); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - osip_message_t *msg=NULL; - char referto[256]={0}; - int err=0; - eXosip_lock(); - if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){ - ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did); - eXosip_unlock(); - return -1; - } - eXosip_call_build_refer(h->did,referto, &msg); - osip_message_set_header(msg,"Referred-By",h->base.from); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - int cid; - eXosip_lock(); - cid=eXosip_call_find_by_replaces(h->replaces); - eXosip_unlock(); - if (cid>0){ - SalOp *ret=sal_find_call(h->base.root,cid); - return ret; - } - } - return NULL; -} - -int sal_call_send_dtmf(SalOp *h, char dtmf){ - osip_message_t *msg=NULL; - char dtmf_body[128]; - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf); - osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); - osip_message_set_content_type(msg,"application/dtmf-relay"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - } - eXosip_unlock(); - return 0; -} - -static void push_auth_to_exosip(const SalAuthInfo *info){ - const char *userid; - if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; - else userid=info->userid; - ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm); - eXosip_add_authentication_info (info->username,userid, - info->password, NULL,info->realm); -} -/* - * Just for symmetry ;-) - */ -static void pop_auth_from_exosip() { - eXosip_clear_authentication_info(); -} - -int sal_call_terminate(SalOp *h){ - int err; - if (h == NULL) return -1; - if (h->auth_info) push_auth_to_exosip(h->auth_info); - eXosip_lock(); - err=eXosip_call_terminate(h->cid,h->did); - eXosip_unlock(); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - if (err!=0){ - ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did); - } - h->terminated=TRUE; - return 0; -} - -void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ - bool_t terminating=FALSE; - if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) { - terminating=TRUE; - } - if (h->terminated && !terminating) return; - - if (h->pending_auth){ - push_auth_to_exosip(info); - - /*FIXME exosip does not take into account this update register message*/ - /* - if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) { - - }; - */ - update_contact_from_response(h,h->pending_auth->response); - eXosip_lock(); - eXosip_default_action(h->pending_auth); - eXosip_unlock(); - ms_message("eXosip_default_action() done"); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - - if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/ - h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/ - } -} -void sal_op_cancel_authentication(SalOp *h) { - if (h->rid >0) { - sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure"); - } else if (h->cid >0) { - sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0); - } else { - ms_warning("Auth failure not handled"); - } - -} -static void set_network_origin(SalOp *op, osip_message_t *req){ - const char *received=NULL; - int rport=5060; - char origin[64]={0}; - SalTransport transport; - if (extract_received_rport(req,&received,&rport,&transport)!=0){ - osip_via_t *via=NULL; - char *tmp; - osip_message_get_via(req,0,&via); - received=osip_via_get_host(via); - tmp=osip_via_get_port(via); - if (tmp) rport=atoi(tmp); - } - if (transport != SalTransportUDP) { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); - } else { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); - } - __sal_op_set_network_origin(op,origin); -} - -static void set_remote_ua(SalOp* op, osip_message_t *req){ - if (op->base.remote_ua==NULL){ - osip_header_t *h=NULL; - osip_message_get_user_agent(req,0,&h); - if (h){ - op->base.remote_ua=ms_strdup(h->hvalue); - } - } -} - -static void set_remote_contact(SalOp* op, osip_message_t *req){ - if (op->base.remote_contact==NULL){ - osip_contact_t *h=NULL; - osip_message_get_contact(req,0,&h); - if (h){ - char *tmp=NULL; - osip_contact_to_str(h,&tmp); - __sal_op_set_remote_contact(op,tmp); - osip_free(tmp); - } - } -} - -static void set_replaces(SalOp *op, osip_message_t *req){ - osip_header_t *h=NULL; - - if (op->replaces){ - ms_free(op->replaces); - op->replaces=NULL; - } - osip_message_header_get_byname(req,"replaces",0,&h); - if (h){ - if (h->hvalue && h->hvalue[0]!='\0'){ - op->replaces=ms_strdup(h->hvalue); - } - } -} - -static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ - if (ev->cid>0){ - return sal_find_call(sal,ev->cid); - } - if (ev->rid>0){ - return sal_find_register(sal,ev->rid); - } - if (ev->sid>0){ - return sal_find_out_subscribe(sal,ev->sid); - } - if (ev->nid>0){ - return sal_find_in_subscribe(sal,ev->nid); - } - if (ev->response) return sal_find_other(sal,ev->response); - else if (ev->request) return sal_find_other(sal,ev->request); - return NULL; -} - -static void inc_new_call(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - osip_from_t *from,*to; - osip_call_info_t *call_info; - char *tmp=NULL; - sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - - osip_call_id_t *callid=osip_message_get_call_id(ev->request); - - osip_call_id_to_str(callid,&tmp); - op->base.call_id=ms_strdup(tmp); - osip_free(tmp); - - set_network_origin(op,ev->request); - set_remote_contact(op,ev->request); - set_remote_ua(op,ev->request); - set_replaces(op,ev->request); - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - }else op->sdp_offering=TRUE; - - from=osip_message_get_from(ev->request); - to=osip_message_get_to(ev->request); - osip_from_to_str(from,&tmp); - sal_op_set_from(op,tmp); - osip_free(tmp); - osip_from_to_str(to,&tmp); - sal_op_set_to(op,tmp); - osip_free(tmp); - - osip_message_get_call_info(ev->request,0,&call_info); - if(call_info) - { - osip_call_info_to_str(call_info,&tmp); - if( strstr(tmp,"answer-after=") != NULL) - { - op->auto_answer_asked=TRUE; - ms_message("The caller asked to automatically answer the call(Emergency?)\n"); - } - osip_free(tmp); - } - - op->tid=ev->tid; - op->cid=ev->cid; - op->did=ev->did; - sal_add_call(op->base.root,op); - sal->callbacks.call_received(op); -} - -static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("Reinvite for non-existing operation !"); - return; - } - op->reinvite=TRUE; - op->tid=ev->tid; - sdp=eXosip_get_sdp_info(ev->request); - if (op->base.remote_media){ - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=NULL; - } - if (op->result){ - sal_media_description_unref(op->result); - op->result=NULL; - } - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - - }else { - op->sdp_offering=TRUE; - } - sal->callbacks.call_updating(op); -} - -static void handle_ack(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("ack for non-existing call !"); - return; - } - if (op->terminated) { - ms_warning("ack for terminated call, ignoring"); - return; - } - - if (op->sdp_offering){ - sdp=eXosip_get_sdp_info(ev->ack); - if (sdp){ - if (op->base.remote_media) - sal_media_description_unref(op->base.remote_media); - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_process(op); - sdp_message_free(sdp); - } - } - if (op->reinvite){ - op->reinvite=FALSE; - } - sal->callbacks.call_ack(op); -} - -static void update_contact_from_response(SalOp *op, osip_message_t *response){ - const char *received; - int rport; - SalTransport transport; - if (extract_received_rport(response,&received,&rport,&transport)==0){ - const char *contact=sal_op_get_contact(op); - if (!contact){ - /*no contact given yet, use from instead*/ - contact=sal_op_get_from(op); - } - if (contact){ - SalAddress *addr=sal_address_new(contact); - char *tmp; - sal_address_set_domain(addr,received); - sal_address_set_port_int(addr,rport); - if (transport!=SalTransportUDP) - sal_address_set_transport(addr,transport); - tmp=sal_address_as_string(addr); - ms_message("Contact address updated to %s",tmp); - sal_op_set_contact(op,tmp); - sal_address_destroy(addr); - ms_free(tmp); - } - } -} - -static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been canceled."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return -1; - } - if (ev->did>0) - op->did=ev->did; - op->tid=ev->tid; - - /* update contact if received and rport are set by the server - note: will only be used by remote for next INVITE, if any...*/ - update_contact_from_response(op,ev->response); - return 0; -} - -static void call_ringing(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - SalOp *op=find_op(sal,ev); - if (call_proceeding(sal, ev)==-1) return; - - set_remote_ua(op,ev->response); - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - sal->callbacks.call_ringing(op); -} - -static void call_accepted(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - osip_message_t *msg=NULL; - SalOp *op=find_op(sal,ev); - const char *contact; - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - - op->did=ev->did; - set_remote_ua(op,ev->response); - set_remote_contact(op,ev->response); - - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - eXosip_call_build_ack(ev->did,&msg); - if (msg==NULL) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - contact=sal_op_get_contact(op); - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - if (op->sdp_answer){ - set_sdp(msg,op->sdp_answer); - sdp_message_free(op->sdp_answer); - op->sdp_answer=NULL; - } - eXosip_call_send_ack(ev->did,msg); - sal->callbacks.call_accepted(op); -} - -static void call_terminated(Sal *sal, eXosip_event_t *ev){ - char *from=NULL; - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("Call terminated for already closed call ?"); - return; - } - if (ev->request){ - osip_from_to_str(ev->request->from,&from); - } - sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op)); - if (from) osip_free(from); - op->terminated=TRUE; -} - -static void call_released(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No op associated to this call_released()"); - return; - } - if (!op->terminated){ - /* no response received so far */ - call_failure(sal,ev); - } - sal->callbacks.call_released(op); -} - -static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){ - const char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authenticate_t *prx_auth; - osip_www_authenticate_t *www_auth; - - *username=osip_uri_get_username(resp->from->url); - prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); - www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authenticate_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_www_authenticate_get_realm(www_auth); - - if (prx_realm){ - *realm=prx_realm; - }else if (www_realm){ - *realm=www_realm; - }else{ - return -1; - } - return 0; -} - -static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){ - osip_authorization_t *auth=NULL; - osip_proxy_authorization_t *prx_auth=NULL; - - *username=osip_uri_get_username(msg->from->url); - osip_message_get_authorization(msg, 0, &auth); - if (auth){ - *realm=osip_authorization_get_realm(auth); - return 0; - } - osip_message_get_proxy_authorization(msg,0,&prx_auth); - if (prx_auth){ - *realm=osip_proxy_authorization_get_realm(prx_auth); - return 0; - } - return -1; -} - -static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ - if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0; - if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0; - return -1; -} - -int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ - if (op->pending_auth){ - return get_auth_data(op->pending_auth,realm,username); - } - return -1; -} - -static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication !"); - return TRUE; - } - if (get_auth_data(ev,&realm,&username)==0){ - if (op->pending_auth!=NULL){ - eXosip_event_free(op->pending_auth); - op->pending_auth=ev; - }else{ - op->pending_auth=ev; - sal_add_pending_auth(sal,op); - } - - sal->callbacks.auth_requested(op,realm,username); - return FALSE; - } - return TRUE; -} - -static void authentication_ok(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication_ok!"); - return ; - } - if (op->pending_auth){ - eXosip_event_free(op->pending_auth); - sal_remove_pending_auth(sal,op); - op->pending_auth=NULL; - } - if (get_auth_data(ev,&realm,&username)==0){ - sal->callbacks.auth_success(op,realm,username); - } -} - -static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - int code=0; - char* computedReason=NULL; - const char *reason=NULL; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - - - op=(SalOp*)find_op(sal,ev); - - if (op==NULL) { - ms_warning("Call failure reported for a closed call, ignored."); - return TRUE; - } - - if (ev->response){ - code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - osip_header_t *h=NULL; - if (!osip_message_header_get_byname( ev->response - ,"Reason" - ,0 - ,&h)) { - computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h)); - reason = computedReason; - - } - } - switch(code) - { - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 400: - error=SalErrorUnknown; - break; - case 404: - error=SalErrorFailure; - sr=SalReasonNotFound; - break; - case 415: - error=SalErrorFailure; - sr=SalReasonMedia; - break; - case 422: - eXosip_default_action(ev); - return TRUE; - break; - case 480: - error=SalErrorFailure; - sr=SalReasonTemporarilyUnavailable; - break; - case 486: - error=SalErrorFailure; - sr=SalReasonBusy; - break; - case 487: - break; - case 600: - error=SalErrorFailure; - sr=SalReasonDoNotDisturb; - break; - case 603: - error=SalErrorFailure; - sr=SalReasonDeclined; - break; - default: - if (code>0){ - error=SalErrorFailure; - sr=SalReasonUnknown; - }else error=SalErrorNoResponse; - } - op->terminated=TRUE; - sal->callbacks.call_failure(op,error,sr,reason,code); - if (computedReason != NULL){ - ms_free(computedReason); - } - return TRUE; -} - -/* Request remote side to send us VFU */ -void sal_call_send_vfu_request(SalOp *h){ - osip_message_t *msg=NULL; - char info_body[] = - "" - "" - " " - " " - " " - " " - " " - ""; - - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - osip_message_set_body(msg,info_body,strlen(info_body)); - osip_message_set_content_type(msg,"application/media_control+xml"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - ms_message("Sending VFU request !"); - } - eXosip_unlock(); -} - -static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media control xml received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL && - strstr(body->body,"picture_fast_update")){ - osip_message_t *ans=NULL; - ms_message("Receiving VFU request !"); - if (sal->callbacks.vfu_request){ - sal->callbacks.vfu_request(op); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - return; - } - } - /*in all other cases we must say it is not implemented.*/ - { - osip_message_t *ans=NULL; - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } -} - -static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media dtmf relay received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL){ - osip_message_t *ans=NULL; - const char *name=strstr(body->body,"Signal"); - if (name==NULL) name=strstr(body->body,"signal"); - if (name==NULL) { - ms_warning("Could not extract the dtmf name from the SIP INFO."); - }else{ - char tmp[2]; - name+=strlen("signal"); - if (sscanf(name," = %1s",tmp)==1){ - ms_message("Receiving dtmf %s via SIP INFO.",tmp); - if (sal->callbacks.dtmf_received != NULL) - sal->callbacks.dtmf_received(op, tmp[0]); - } - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } -} - -static void fill_options_answer(osip_message_t *options){ - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); -} - -static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){ - osip_header_t *h=NULL; - osip_message_t *ans=NULL; - ms_message("Receiving REFER request !"); - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - - if (h){ - osip_from_t *from=NULL; - char *tmp; - osip_from_init(&from); - - if (osip_from_parse(from,h->hvalue)==0){ - if (op ){ - osip_uri_header_t *uh=NULL; - osip_header_t *referred_by=NULL; - osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh); - if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){ - ms_message("Found replaces in Refer-To"); - if (op->replaces){ - ms_free(op->replaces); - } - op->replaces=ms_strdup(uh->gvalue); - } - osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by); - if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){ - if (op->referred_by) - ms_free(op->referred_by); - op->referred_by=ms_strdup(referred_by->hvalue); - } - } - osip_uri_header_freelist(&from->url->url_headers); - osip_from_to_str(from,&tmp); - sal->callbacks.refer_received(sal,op,tmp); - osip_free(tmp); - osip_from_free(from); - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,202,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,202,ans); - eXosip_unlock(); - } - else - { - ms_warning("cannot do anything with the refer without destination\n"); - } -} - -static void process_notify(Sal *sal, eXosip_event_t *ev){ - osip_header_t *h=NULL; - char *from=NULL; - SalOp *op=find_op(sal,ev); - osip_message_t *ans=NULL; - - ms_message("Receiving NOTIFY request !"); - osip_from_to_str(ev->request->from,&from); - osip_message_header_get_byname(ev->request,"Event",0,&h); - if(h){ - osip_body_t *body=NULL; - //osip_content_type_t *ct=NULL; - osip_message_get_body(ev->request,0,&body); - //ct=osip_message_get_content_type(ev->request); - if (h->hvalue && strncasecmp(h->hvalue,"refer",strlen("refer"))==0){ - /*special handling of refer events*/ - if (body && body->body){ - osip_message_t *msg; - osip_message_init(&msg); - if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){ - int code=osip_message_get_status_code(msg); - if (code==100){ - sal->callbacks.notify_refer(op,SalReferTrying); - }else if (code==200){ - sal->callbacks.notify_refer(op,SalReferSuccess); - }else if (code>=400){ - sal->callbacks.notify_refer(op,SalReferFailed); - } - } - osip_message_free(msg); - } - }else{ - /*generic handling*/ - sal->callbacks.notify(op,from,h->hvalue); - } - } - /*answer that we received the notify*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - osip_free(from); -} - -static void call_message_new(Sal *sal, eXosip_event_t *ev){ - osip_message_t *ans=NULL; - if (ev->request){ - if (MSG_IS_INFO(ev->request)){ - osip_content_type_t *ct; - ct=osip_message_get_content_type(ev->request); - if (ct && ct->subtype){ - if (strcmp(ct->subtype,"media_control+xml")==0) - process_media_control_xml(sal,ev); - else if (strcmp(ct->subtype,"dtmf-relay")==0) - process_dtmf_relay(sal,ev); - else { - ms_message("Unhandled SIP INFO."); - /*send an "Not implemented" answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } - }else{ - /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } - }else if(MSG_IS_MESSAGE(ev->request)){ - /* SIP messages could be received into call */ - text_received(sal, ev); - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - }else if(MSG_IS_REFER(ev->request)){ - SalOp *op=find_op(sal,ev); - - ms_message("Receiving REFER request !"); - process_refer(sal,op,ev); - }else if(MSG_IS_NOTIFY(ev->request)){ - process_notify(sal,ev); - }else if (MSG_IS_OPTIONS(ev->request)){ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans){ - fill_options_answer(ans); - eXosip_call_send_answer(ev->tid,200,ans); - } - eXosip_unlock(); - } - }else ms_warning("call_message_new: No request ?"); -} - -static void inc_update(Sal *sal, eXosip_event_t *ev){ - osip_message_t *msg=NULL; - ms_message("Processing incoming UPDATE"); - eXosip_lock(); - eXosip_message_build_answer(ev->tid,200,&msg); - if (msg!=NULL) - eXosip_message_send_answer(ev->tid,200,msg); - eXosip_unlock(); -} - -static bool_t comes_from_local_if(osip_message_t *msg){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - const char *host; - host=osip_via_get_host(via); - if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ - osip_generic_param_t *param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param==NULL) return TRUE; - if (param->gvalue && - (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ - return TRUE; - } - } - } - return FALSE; -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static int utc_offset() { - time_t ref = 24 * 60 * 60L; - struct tm * timeptr; - int gmtime_hours; - - /* get the local reference time for Jan 2, 1900 00:00 UTC */ - timeptr = localtime(&ref); - gmtime_hours = timeptr->tm_hour; - - /* if the local time is the "day before" the UTC, subtract 24 hours - from the hours to get the UTC offset */ - if (timeptr->tm_mday < 2) gmtime_hours -= 24; - - return gmtime_hours; -} - -time_t mktime_utc(struct tm *timeptr) { - return mktime(timeptr) + utc_offset() * 3600; -} - -static void text_received(Sal *sal, eXosip_event_t *ev){ - osip_body_t *body=NULL; - char *from=NULL,*msg=NULL; - osip_content_type_t* content_type; - osip_uri_param_t* external_body_url; - char unquoted_external_body_url [256]; - int external_body_size=0; - SalMessage salmsg; - char message_id[256]={0}; - osip_header_t *date=NULL; - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - SalOp *op=sal_op_new(sal); - - osip_message_get_date(ev->request,0,&date); - if(date!=NULL){ - int i,j; - sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2, - &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec); - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=0; - }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent."); - - content_type= osip_message_get_content_type(ev->request); - if (!content_type) { - ms_error("Could not get message because no content type"); - return; - } - osip_from_to_str(ev->request->from,&from); - if (content_type->type - && strcmp(content_type->type, "text")==0 - && content_type->subtype - && strcmp(content_type->subtype, "plain")==0 ) { - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - osip_free(from); - return; - } - msg=body->body; - }else if (content_type->type - && strcmp(content_type->type, "message")==0 - && content_type->subtype - && strcmp(content_type->subtype, "external-body")==0 ) { - - osip_content_type_param_get_byname(content_type, "URL", &external_body_url); - /*remove both first and last character*/ - strncpy(unquoted_external_body_url - ,&external_body_url->gvalue[1] - ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); - unquoted_external_body_url[external_body_size-1]='\0'; - } else { - ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); - osip_free(from); - return; - } - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number); - - salmsg.from=from; - salmsg.text=msg; - salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; - salmsg.message_id=message_id; - salmsg.time=date!=NULL ? mktime_utc(&ret) : time(NULL); - sal->callbacks.text_received(op,&salmsg); - sal_op_release(op); - osip_free(from); -} - -static void other_request(Sal *sal, eXosip_event_t *ev){ - ms_message("in other_request"); - if (ev->request==NULL) return; - if (strcmp(ev->request->sip_method,"MESSAGE")==0){ - text_received(sal,ev); - eXosip_message_send_answer(ev->tid,200,NULL); - }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ - osip_message_t *options=NULL; - eXosip_options_build_answer(ev->tid,200,&options); - fill_options_answer(options); - eXosip_options_send_answer(ev->tid,200,options); - }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ - ms_message("Receiving REFER request !"); - if (comes_from_local_if(ev->request)) { - process_refer(sal,NULL,ev); - }else ms_warning("Ignored REFER not coming from this local loopback interface."); - }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ - inc_update(sal,ev); - }else { - char *tmp=NULL; - size_t msglen=0; - osip_message_to_str(ev->request,&tmp,&msglen); - if (tmp){ - ms_message("Unsupported request received:\n%s",tmp); - osip_free(tmp); - } - /*answer with a 501 Not implemented*/ - eXosip_message_send_answer(ev->tid,501,NULL); - } -} - -static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - osip_free(via->port); - via->port=osip_strdup(port); - osip_free(via->host); - via->host=osip_strdup(ip); - } -} - - -static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) { - osip_contact_t *ctt=NULL; - const char *received; - int rport; - SalTransport transport; - char port[20]; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - osip_message_get_contact(request,0,&ctt); - if (ctt == NULL) { - ms_warning("fix_message_contact(): no contact to update"); - return FALSE; - } - if (expire_last_contact){ - osip_contact_t *oldct=NULL,*prevct; - osip_generic_param_t *param=NULL; - osip_contact_clone(ctt,&oldct); - while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){ - osip_contact_free(prevct); - osip_list_remove(&request->contacts,1); - } - osip_list_add(&request->contacts,oldct,1); - osip_contact_param_get_byname(oldct,"expires",¶m); - if (param){ - if (param->gvalue) osip_free(param->gvalue); - param->gvalue=osip_strdup("0"); - }else{ - osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0")); - } - } - if (ctt->url->host!=NULL){ - osip_free(ctt->url->host); - } - ctt->url->host=osip_strdup(received); - if (ctt->url->port!=NULL){ - osip_free(ctt->url->port); - } - snprintf(port,sizeof(port),"%i",rport); - ctt->url->port=osip_strdup(port); - if (op->masquerade_via) masquerade_via(request,received,port); - - if (transport != SalTransportUDP) { - sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); - } - return TRUE; -} - -static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ - osip_contact_t *ctt=NULL; - SalAddress* ori_contact_address=NULL; - const char *received; - int rport; - SalTransport transport; - char* tmp; - osip_message_t *msg=NULL; - Sal* sal=op->base.root; - int i=0; - bool_t found_valid_contact=FALSE; - bool_t from_request=FALSE; - - if (sal->double_reg==FALSE ) return FALSE; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - do{ - ctt=NULL; - osip_message_get_contact(last_answer,i,&ctt); - if (!from_request && ctt==NULL) { - osip_message_get_contact(orig_request,0,&ctt); - from_request=TRUE; - } - if (ctt){ - osip_contact_to_str(ctt,&tmp); - ori_contact_address = sal_address_new(tmp); - - /*check if contact is up to date*/ - if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 - && sal_address_get_port_int(ori_contact_address) == rport - && sal_address_get_transport(ori_contact_address) == transport) { - if (!from_request){ - ms_message("Register response has up to date contact, doing nothing."); - }else { - ms_warning("Register response does not have up to date contact, but last request had." - "Stupid registrar detected, giving up."); - } - found_valid_contact=TRUE; - } - osip_free(tmp); - sal_address_destroy(ori_contact_address); - }else break; - i++; - }while(!found_valid_contact); - if (!found_valid_contact) - ms_message("Contact do not match, resending register."); - else return FALSE; - - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Fail to create a contact updated register."); - return FALSE; - } - if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) { - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - ms_message("Resending new register with updated contact"); - update_contact_from_response(op,last_answer); - return TRUE; - } else { - ms_warning("Fail to send updated register."); - eXosip_unlock(); - return FALSE; - } - eXosip_unlock(); - return FALSE; -} - -static void registration_success(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_register(sal,ev->rid); - osip_header_t *h=NULL; - bool_t registered; - if (op==NULL){ - ms_error("Receiving register response for unknown operation"); - return; - } - osip_message_get_expires(ev->request,0,&h); - if (h!=NULL && atoi(h->hvalue)!=0){ - registered=TRUE; - if (!register_again_with_updated_contact(op,ev->request,ev->response)){ - sal->callbacks.register_success(op,registered); - } - }else { - sal->callbacks.register_success(op,FALSE); - } -} - -static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ - int status_code=0; - const char *reason=NULL; - SalOp *op=sal_find_register(sal,ev->rid); - SalReason sr=SalReasonUnknown; - SalError se=SalErrorUnknown; - - if (op==NULL){ - ms_error("Receiving register failure for unknown operation"); - return TRUE; - } - if (ev->response){ - status_code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - } - switch(status_code){ - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 423: /*interval too brief*/ - {/*retry with greater interval */ - osip_header_t *h=NULL; - osip_message_t *msg=NULL; - osip_message_header_get_byname(ev->response,"min-expires",0,&h); - if (h && h->hvalue && h->hvalue[0]!='\0'){ - int val=atoi(h->hvalue); - if (val>op->expires) - op->expires=val; - }else op->expires*=2; - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - } - break; - case 606: /*Not acceptable, workaround for proxies that don't like private addresses - in vias, such as ekiga.net - On the opposite, freephonie.net bugs when via are masqueraded. - */ - op->masquerade_via=TRUE; - default: - /* if contact is up to date, process the failure, otherwise resend a new register with - updated contact first, just in case the faillure is due to incorrect contact */ - if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response)) - return TRUE; /*we are retrying with an updated contact*/ - if (status_code==403){ - se=SalErrorFailure; - sr=SalReasonForbidden; - }else if (status_code==0){ - se=SalErrorNoResponse; - } - sal->callbacks.register_failure(op,se,sr,reason); - } - return TRUE; -} - -static void other_request_reply(Sal *sal,eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("other_request_reply(): Receiving response to unknown request."); - return; - } - if (ev->response){ - ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request)); - update_contact_from_response(op,ev->response); - if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0) - sal->callbacks.ping_reply(op); - } - if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) { - /*out of call message acknolegment*/ - SalTextDeliveryStatus status=SalTextDeliveryFailed; - if (ev->response){ - if (ev->response->status_code<200){ - status=SalTextDeliveryInProgress; - }else if (ev->response->status_code<300 && ev->response->status_code>=200){ - status=SalTextDeliveryDone; - } - } - sal->callbacks.text_delivery_update(op,status); - } -} - -static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (ev->response){ - if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){ - if (op->sipfrag_pending){ - send_notify_for_refer(op->did,op->sipfrag_pending); - op->sipfrag_pending=NULL; - } - } - } -} - -static bool_t process_event(Sal *sal, eXosip_event_t *ev){ - ms_message("linphone process event get a message %d\n",ev->type); - switch(ev->type){ - case EXOSIP_CALL_ANSWERED: - ms_message("CALL_ANSWERED\n"); - call_accepted(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_CLOSED: - case EXOSIP_CALL_CANCELLED: - ms_message("CALL_CLOSED or CANCELLED\n"); - call_terminated(sal,ev); - break; - case EXOSIP_CALL_TIMEOUT: - case EXOSIP_CALL_NOANSWER: - ms_message("CALL_TIMEOUT or NOANSWER\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_REQUESTFAILURE: - case EXOSIP_CALL_GLOBALFAILURE: - case EXOSIP_CALL_SERVERFAILURE: - ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_RELEASED: - ms_message("CALL_RELEASED\n"); - call_released(sal, ev); - break; - case EXOSIP_CALL_INVITE: - ms_message("CALL_NEW\n"); - inc_new_call(sal,ev); - break; - case EXOSIP_CALL_REINVITE: - handle_reinvite(sal,ev); - break; - case EXOSIP_CALL_ACK: - ms_message("CALL_ACK"); - handle_ack(sal,ev); - break; - case EXOSIP_CALL_REDIRECTED: - ms_message("CALL_REDIRECTED"); - eXosip_default_action(ev); - break; - case EXOSIP_CALL_PROCEEDING: - ms_message("CALL_PROCEEDING"); - call_proceeding(sal,ev); - break; - case EXOSIP_CALL_RINGING: - ms_message("CALL_RINGING"); - call_ringing(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_NEW: - ms_message("EXOSIP_CALL_MESSAGE_NEW"); - call_message_new(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: - if (ev->response && - (ev->response->status_code==407 || ev->response->status_code==401)){ - return process_authentication(sal,ev); - } - break; - case EXOSIP_CALL_MESSAGE_ANSWERED: - ms_message("EXOSIP_CALL_MESSAGE_ANSWERED "); - process_in_call_reply(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_IN_SUBSCRIPTION_NEW "); - sal_exosip_subscription_recv(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_RELEASED: - ms_message("CALL_SUBSCRIPTION_NEW "); - sal_exosip_in_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_UPDATE: - ms_message("CALL_SUBSCRIPTION_UPDATE"); - break; - case EXOSIP_SUBSCRIPTION_NOTIFY: - ms_message("CALL_SUBSCRIPTION_NOTIFY"); - sal_exosip_notify_recv(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did); - sal_exosip_subscription_answered(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_CLOSED: - ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /**< announce a request failure */ - if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ - return process_authentication(sal,ev); - } - case EXOSIP_SUBSCRIPTION_SERVERFAILURE: - case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_REGISTRATION_FAILURE: - ms_message("REGISTRATION_FAILURE\n"); - return registration_failure(sal,ev); - break; - case EXOSIP_REGISTRATION_SUCCESS: - authentication_ok(sal,ev); - registration_success(sal,ev); - break; - case EXOSIP_MESSAGE_NEW: - other_request(sal,ev); - break; - case EXOSIP_MESSAGE_PROCEEDING: - case EXOSIP_MESSAGE_ANSWERED: - case EXOSIP_MESSAGE_REDIRECTED: - case EXOSIP_MESSAGE_SERVERFAILURE: - case EXOSIP_MESSAGE_GLOBALFAILURE: - other_request_reply(sal,ev); - break; - case EXOSIP_MESSAGE_REQUESTFAILURE: - case EXOSIP_NOTIFICATION_REQUESTFAILURE: - if (ev->response) { - switch (ev->response->status_code) { - case 407: - case 401: - return process_authentication(sal,ev); - case 412: { - eXosip_automatic_action (); - return 1; - } - } - } - other_request_reply(sal,ev); - break; - default: - ms_message("Unhandled exosip event ! %i",ev->type); - break; - } - return TRUE; -} - -int sal_iterate(Sal *sal){ - eXosip_event_t *ev; - while((ev=eXosip_event_wait(0,0))!=NULL){ - if (process_event(sal,ev)) - eXosip_event_free(ev); - } -#ifdef HAVE_EXOSIP_TRYLOCK - if (eXosip_trylock()==0){ - eXosip_automatic_refresh(); - eXosip_unlock(); - }else{ - ms_warning("eXosip_trylock busy."); - } -#else - eXosip_lock(); - eXosip_automatic_refresh(); - eXosip_unlock(); -#endif - return 0; -} - -static void register_set_contact(osip_message_t *msg, const char *contact){ - osip_uri_param_t *param = NULL; - osip_contact_t *ct=NULL; - char *line=NULL; - /*we get the line parameter choosed by exosip, and add it to our own contact*/ - osip_message_get_contact(msg,0,&ct); - if (ct!=NULL){ - osip_uri_uparam_get_byname(ct->url, "line", ¶m); - if (param && param->gvalue) - line=osip_strdup(param->gvalue); - } - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - osip_message_get_contact(msg,0,&ct); - osip_uri_uparam_add(ct->url,osip_strdup("line"),line); -} - -void sal_message_add_route(osip_message_t *msg, const char *proxy){ - osip_route_t *route; - - osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free); - - osip_route_init(&route); - if (osip_route_parse(route,proxy)==0){ - osip_uri_param_t *lr_param = NULL; - osip_uri_uparam_get_byname(route->url, "lr", &lr_param); - if (lr_param == NULL){ - osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL); - } - osip_list_add(&msg->routes,route,0); - return; - } - osip_route_free(route); -} - - -int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - - sal_op_set_route(h,proxy); - if (h->rid==-1){ - SalAddress *from_parsed=sal_address_new(from); - char domain[256]; - char *uri, *domain_ptr = NULL; - if (from_parsed==NULL) { - ms_warning("sal_register() bad from %s",from); - return -1; - } - /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of - using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */ - uri = sal_address_as_string_uri_only(from_parsed); - if (uri) domain_ptr = strchr(uri, '@'); - if (domain_ptr) { - snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1); - } else { - snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed)); - } - if (uri) ms_free(uri); - sal_address_destroy(from_parsed); - eXosip_lock(); - h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg); - if (msg){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,proxy); - sal_add_register(h->base.root,h); - }else{ - ms_error("Could not build initial register."); - eXosip_unlock(); - return -1; - } - }else{ - eXosip_lock(); - eXosip_register_build_register(h->rid,expires,&msg); - sal_message_add_route(msg,proxy); - } - if (msg){ - eXosip_register_send_register(h->rid,msg); - } - eXosip_unlock(); - h->expires=expires; - return (msg != NULL) ? 0 : -1; -} - -int sal_register_refresh(SalOp *op, int expires){ - osip_message_t *msg=NULL; - const char *contact=sal_op_get_contact(op); - - if (op->rid==-1){ - ms_error("Unexistant registration context, not possible to refresh."); - return -1; - } -#ifdef HAVE_EXOSIP_TRYLOCK - { - int tries=0; - /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever. - * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take - * the exosip lock in a non blocking way, and give up if it takes too long*/ - while (eXosip_trylock()!=0){ - ms_usleep(100000); - tries++; - if (tries>30) {/*after 3 seconds, give up*/ - ms_warning("Could not obtain exosip lock in a reasonable time, giving up."); - return -1; - } - } - } -#else - eXosip_lock(); -#endif - eXosip_register_build_register(op->rid,expires,&msg); - if (msg!=NULL){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,sal_op_get_route(op)); - eXosip_register_send_register(op->rid,msg); - }else ms_error("Could not build REGISTER refresh message."); - eXosip_unlock(); - return (msg != NULL) ? 0 : -1; -} - - -int sal_unregister(SalOp *h){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_register_build_register(h->rid,0,&msg); - if (msg) eXosip_register_send_register(h->rid,msg); - else ms_warning("Could not build unREGISTER !"); - eXosip_unlock(); - return 0; -} - -SalAddress * sal_address_new(const char *uri){ - osip_from_t *from; - osip_from_init(&from); - - // Remove front spaces - while (uri[0]==' ') { - uri++; - } - - if (osip_from_parse(from,uri)!=0){ - osip_from_free(from); - return NULL; - } - if (from->displayname!=NULL && from->displayname[0]=='"'){ - char *unquoted=osip_strdup_without_quote(from->displayname); - osip_free(from->displayname); - from->displayname=unquoted; - } - return (SalAddress*)from; -} - -SalAddress * sal_address_clone(const SalAddress *addr){ - osip_from_t *ret=NULL; - osip_from_clone((osip_from_t*)addr,&ret); - return (SalAddress*)ret; -} - -#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL ) - -const char *sal_address_get_scheme(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->scheme); -} - -const char *sal_address_get_display_name(const SalAddress* addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->displayname); -} - -const char *sal_address_get_username(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->username); -} - -const char *sal_address_get_domain(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->host); -} - -void sal_address_set_display_name(SalAddress *addr, const char *display_name){ - osip_from_t *u=(osip_from_t*)addr; - if (u->displayname!=NULL){ - osip_free(u->displayname); - u->displayname=NULL; - } - if (display_name!=NULL && display_name[0]!='\0'){ - u->displayname=osip_strdup(display_name); - } -} - -void sal_address_set_username(SalAddress *addr, const char *username){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->username!=NULL){ - osip_free(uri->url->username); - uri->url->username=NULL; - } - if (username) - uri->url->username=osip_strdup(username); -} - -void sal_address_set_domain(SalAddress *addr, const char *host){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->host!=NULL){ - osip_free(uri->url->host); - uri->url->host=NULL; - } - if (host) - uri->url->host=osip_strdup(host); -} - -void sal_address_set_port(SalAddress *addr, const char *port){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->port!=NULL){ - osip_free(uri->url->port); - uri->url->port=NULL; - } - if (port) - uri->url->port=osip_strdup(port); -} - -void sal_address_set_port_int(SalAddress *uri, int port){ - char tmp[12]; - if (port==5060){ - /*this is the default, special case to leave the port field blank*/ - sal_address_set_port(uri,NULL); - return; - } - snprintf(tmp,sizeof(tmp),"%i",port); - sal_address_set_port(uri,tmp); -} - -void sal_address_clean(SalAddress *addr){ - osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params); - osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params); -} - -char *sal_address_as_string(const SalAddress *u){ - char *tmp,*ret; - osip_from_t *from=(osip_from_t *)u; - char *old_displayname=NULL; - /* hack to force use of quotes around the displayname*/ - if (from->displayname!=NULL - && from->displayname[0]!='"'){ - old_displayname=from->displayname; - from->displayname=osip_enquote(from->displayname); - } - osip_from_to_str(from,&tmp); - if (old_displayname!=NULL){ - ms_free(from->displayname); - from->displayname=old_displayname; - } - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} - -char *sal_address_as_string_uri_only(const SalAddress *u){ - char *tmp=NULL,*ret; - osip_uri_to_str(((osip_from_t*)u)->url,&tmp); - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} -void sal_address_set_param(SalAddress *u,const char* name,const char* value) { - osip_uri_param_t *param=NULL; - osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,¶m); - if (param == NULL){ - osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL); - } else { - osip_free(param->gvalue); - param->gvalue=value ? osip_strdup(value) : NULL; - } - -} - -void sal_address_destroy(SalAddress *u){ - osip_from_free((osip_from_t*)u); -} - -void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { - ctx->tcp_tls_keepalive = enabled; -} - -void sal_set_keepalive_period(Sal *ctx,unsigned int value) { - switch (ctx->transport) { - case SalTransportUDP: - ctx->keepalive_period = value; - break; - case SalTransportTCP: - case SalTransportTLS: - if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value; - else ctx->keepalive_period = -1; - break; - default: - break; - } - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period); -} -unsigned int sal_get_keepalive_period(Sal *ctx) { - return ctx->keepalive_period; -} - -const char * sal_address_get_port(const SalAddress *addr) { - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->port); -} - -int sal_address_get_port_int(const SalAddress *uri) { - const char* port = sal_address_get_port(uri); - if (port != NULL) { - return atoi(port); - } else { - return 5060; - } -} -SalTransport sal_address_get_transport(const SalAddress* addr) { - const osip_from_t *u=(const osip_from_t*)addr; - osip_uri_param_t *transport_param=NULL; - osip_uri_uparam_get_byname(u->url,"transport",&transport_param); - if (transport_param == NULL){ - return SalTransportUDP; - } else { - return sal_transport_parse(transport_param->gvalue); - } -} -void sal_address_set_transport(SalAddress* addr,SalTransport transport) { - sal_address_set_param(addr, "transport", sal_transport_to_string(transport)); -} - -/* sends a reinvite. Local media description may have changed by application since call establishment*/ -int sal_call_update(SalOp *h, const char *subject){ - int err=0; - osip_message_t *reinvite=NULL; - - eXosip_lock(); - if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){ - eXosip_unlock(); - return -1; - } - eXosip_unlock(); - osip_message_set_subject(reinvite,subject); - osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(reinvite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(reinvite, "Session-expires", "200"); - osip_message_set_supported(reinvite, "timer"); - } - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(reinvite,h->base.local_media); - }else h->sdp_offering=FALSE; - eXosip_lock(); - err = eXosip_call_send_request(h->did, reinvite); - eXosip_unlock(); - return err; -} - -void sal_reuse_authorization(Sal *ctx, bool_t value) { - ctx->reuse_authorization=value; -} - -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){ - MSList *elem=(MSList*)ch; - for (;elem!=NULL;elem=elem->next){ - SalCustomHeader *it=(SalCustomHeader*)elem; - osip_message_set_header(msg,it->header_name,it->header_value); - } -} - -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){ - int i=0; - osip_header_t *header; - SalCustomHeader *ret=NULL; - - while((header=osip_list_get(&msg->headers,i))!=NULL){ - ret=sal_custom_header_append(ret,header->hname,header->hvalue); - i++; - } - return ret; -} - diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h deleted file mode 100644 index e00dd64d9..000000000 --- a/coreapi/sal_eXosip2.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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. -*/ - -#ifndef sal_exosip2_h -#define sal_exosip2_h - -#include "sal.h" -#include - - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); -int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); - -struct Sal{ - SalCallbacks callbacks; - SalTransport transport; - MSList *calls; /*MSList of SalOp */ - MSList *registers;/*MSList of SalOp */ - MSList *out_subscribes;/*MSList of SalOp */ - MSList *in_subscribes;/*MSList of SalOp */ - MSList *pending_auths;/*MSList of SalOp */ - MSList *other_transactions; /*MSList of SalOp */ - int running; - int session_expires; - int keepalive_period; - void *up; /*user pointer*/ - char* rootCa; /* File _or_ folder containing root CA */ - int dscp; - bool_t one_matching_codec; - bool_t double_reg; - bool_t use_rports; - bool_t use_101; - bool_t reuse_authorization; - bool_t verify_server_certs; - bool_t verify_server_cn; - bool_t expire_old_contact; - bool_t add_dates; - bool_t tcp_tls_keepalive; -}; - -struct SalOp{ - SalOpBase base; - int cid; - int did; - int tid; - int rid; - int sid; - int nid; - int expires; - SalMediaDescription *result; - sdp_message_t *sdp_answer; - eXosip_event_t *pending_auth; - osip_call_id_t *call_id; /*used for out of calls transaction in order - to retrieve the operation when receiving a response*/ - char *replaces; - char *referred_by; - const SalAuthInfo *auth_info; - const char *sipfrag_pending; - bool_t supports_session_timers; - bool_t sdp_offering; - bool_t reinvite; - bool_t masquerade_via; - bool_t auto_answer_asked; - bool_t terminated; -}; - -void sal_remove_out_subscribe(Sal *sal, SalOp *op); -void sal_remove_in_subscribe(Sal *sal, SalOp *op); -void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request); - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); -void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev); -SalOp * sal_find_out_subscribe(Sal *sal, int sid); -SalOp * sal_find_in_subscribe(Sal *sal, int nid); -void sal_exosip_fix_route(SalOp *op); -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch); -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg); - -void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)); - -void sal_message_add_route(osip_message_t *msg, const char *proxy); - -#endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c deleted file mode 100644 index c99a48793..000000000 --- a/coreapi/sal_eXosip2_presence.c +++ /dev/null @@ -1,829 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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_eXosip2.h" - -typedef enum { - PIDF = 0, - RFCxxxx = 1, - MSOLDPRES = 2 -} presence_type_t; - -/* - * REVISIT: this static variable forces every dialog to use the same presence description type depending - * on what is received on a single dialog... - */ -static presence_type_t presence_style = PIDF; - -SalOp * sal_find_out_subscribe(Sal *sal, int sid){ - const MSList *elem; - SalOp *op; - for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->sid==sid) return op; - } - ms_message("No op for sid %i",sid); - return NULL; -} - -static void sal_add_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_append(sal->out_subscribes,op); -} - -void sal_remove_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_remove(sal->out_subscribes,op); -} - -SalOp * sal_find_in_subscribe(Sal *sal, int nid){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->nid==nid) return op; - } - return NULL; -} - -static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->call_id && osip_call_id_match(op->call_id,call_id)==0) - return op; - } - return NULL; -} - -static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){ - osip_call_id_clone(subs->call_id,&op->call_id); - sal->in_subscribes=ms_list_append(sal->in_subscribes,op); -} - -void sal_remove_in_subscribe(Sal *sal, SalOp *op){ - sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static void msg_add_current_date(osip_message_t *msg){ - char tmp[64]={0}; - time_t curtime=time(NULL); - struct tm *ret; -#ifndef WIN32 - struct tm gmt; - ret=gmtime_r(&curtime,&gmt); -#else - ret=gmtime(&curtime); -#endif - /*cannot use strftime because it is locale dependant*/ - snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", - days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); - osip_message_replace_header(msg,"Date",tmp); -} - - -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ - osip_message_t *sip=NULL; - - if(op->cid == -1) - { - /* we are not currently in communication with the destination */ - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (sip!=NULL){ - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - sal_add_other(op->base.root,op,sip); - eXosip_message_send_request(sip); - }else{ - ms_error("Could not build MESSAGE request !"); - } - eXosip_unlock(); - } - else - { - /* we are currently in communication with the destination */ - eXosip_lock(); - //First we generate an INFO message to get the current call_id and a good cseq - eXosip_call_build_request(op->did,"MESSAGE",&sip); - if(sip == NULL) - { - ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?"); - eXosip_unlock(); - return -1; - } - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - eXosip_call_send_request(op->did,sip); - eXosip_unlock(); - } - return 0; -} - -int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { - return sal_message_send(op,from,to,"text/plain",msg); -} -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ - osip_message_t *msg=NULL; - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), - sal_op_get_route(op),"presence",600); - if (msg==NULL){ - ms_error("Could not build subscribe request to %s",to); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - op->sid=eXosip_subscribe_send_initial_request(msg); - eXosip_unlock(); - if (op->sid==-1){ - osip_message_free(msg); - return -1; - } - sal_add_out_subscribe(op->base.root,op); - return 0; -} - -int sal_unsubscribe(SalOp *op){ - osip_message_t *msg=NULL; - if (op->did==-1){ - ms_error("cannot unsubscribe, no dialog !"); - return -1; - } - eXosip_lock(); - eXosip_subscribe_build_refresh_request(op->did,&msg); - if (msg){ - osip_message_set_expires(msg,"0"); - eXosip_subscribe_send_refresh_request(op->did,msg); - }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i", - op->sid,op->did); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_accept(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_answer(op->tid,202,&msg); - if (msg==NULL){ - ms_error("Fail to build answer to subscribe."); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - eXosip_insubscription_send_answer(op->tid,202,msg); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_decline(SalOp *op){ - eXosip_lock(); - eXosip_insubscription_send_answer(op->tid,401,NULL); - eXosip_unlock(); - return 0; -} - -static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info, - char *buf, size_t buflen, presence_type_t ptype) { - switch (ptype) { - case RFCxxxx: { - /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - case MSOLDPRES: { - /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence - * so messages format has been taken from Communigate that can send notify - * requests with this schema - */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */ - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceOnVacation) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"Out to lunch \n" -"\n" -"", -contact_info, contact_info); - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"closed\n" -"%s\n" -"\n" -"\n", contact_info, contact_info); - } - break; - } - } // switch - -} - -static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) -{ - char buf[1000]; - char *contact_info; - - osip_from_t *from=NULL; - from=osip_message_get_from(notify); - osip_uri_to_str(from->url,&contact_info); - - mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); - - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, - presence_style ? "application/xpidf+xml" : "application/pidf+xml"); - - osip_free(contact_info); -} - - -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ - osip_message_t *msg=NULL; - eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE; - if (op->nid==-1){ - ms_warning("Cannot notify, subscription was closed."); - return -1; - } - - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,identity); - add_presence_body(msg,status); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("could not create notify for incoming subscription."); - eXosip_unlock(); - return 0; -} - -int sal_notify_close(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - osip_message_set_contact(msg,identity); - add_presence_body(msg,SalPresenceOffline); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("sal_notify_close(): could not create notify for incoming subscription" - " did=%i, nid=%i",op->did,op->nid); - eXosip_unlock(); - return 0; -} - -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){ - osip_message_t *pub; - int i; - char buf[1024]; - const char *route=sal_op_get_route(op); - - mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - - i = eXosip_build_publish(&pub,to, from, NULL, "presence", "600", - presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); - if (i<0){ - ms_warning("Failed to build publish request."); - return -1; - } - if (route) - sal_message_add_route(pub,route); - - eXosip_lock(); - i = eXosip_publish(pub, to); /* should update the sip-if-match parameter - from sip-etag from last 200ok of PUBLISH */ - eXosip_unlock(); - if (i<0){ - ms_message("Failed to send publish request."); - return -1; - } - sal_add_other(sal_op_get_sal(op),op,pub); - return 0; -} - -static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - char *tmp; - op->did=ev->did; - op->tid=ev->tid; - op->nid=ev->nid; - osip_from_to_str(ev->request->from,&tmp); - sal_op_set_from(op,tmp); - ms_free(tmp); - osip_from_to_str(ev->request->to,&tmp); - sal_op_set_to(op,tmp); - ms_free(tmp); - sal_add_in_subscribe(sal,op,ev->request); - sal->callbacks.subscribe_received(op,sal_op_get_from(op)); -} - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are - recognized as new incoming subscribes*/ - SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id); - if (op){ - osip_header_t *h; - osip_message_header_get_byname(ev->request,"expires",0,&h); - if (h && h->hvalue && atoi(h->hvalue)==0){ - ms_warning("This susbscribe is not a new one but terminates an old one."); - ev->did=op->did; - ev->nid=op->nid; - sal_exosip_subscription_closed(sal,ev); - }else { - osip_message_t *msg=NULL; - ms_warning("Probably a refresh subscribe"); - eXosip_lock(); - eXosip_insubscription_build_answer(ev->tid,202,&msg); - eXosip_insubscription_send_answer(ev->tid,202,msg); - eXosip_unlock(); - } - }else _sal_exosip_subscription_recv(sal,ev); -} - -void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - char *tmp; - osip_from_t *from=NULL; - osip_body_t *body=NULL; - SalPresenceStatus estatus=SalPresenceOffline; - - ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); - - if (op==NULL){ - ms_error("No operation related to this notify !"); - return; - } - if (ev->request==NULL) return; - - from=ev->request->from; - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("No body in NOTIFY"); - return; - } - osip_from_to_str(from,&tmp); - if (strstr(body->body,"pending")!=NULL){ - estatus=SalPresenceOffline; - }else if (strstr(body->body,"busy")!=NULL){ - estatus=SalPresenceBusy; - }else if (strstr(body->body,"berightback")!=NULL - || strstr(body->body,"in-transit")!=NULL ){ - estatus=SalPresenceBerightback; - }else if (strstr(body->body,"away")!=NULL - || strstr(body->body,"idle")){ - estatus=SalPresenceAway; - }else if (strstr(body->body,"onthephone")!=NULL - || strstr(body->body,"on-the-phone")!=NULL){ - estatus=SalPresenceOnthephone; - }else if (strstr(body->body,"outtolunch")!=NULL - || strstr(body->body,"lunch") != NULL - || strstr(body->body,"meal")!=NULL){ - estatus=SalPresenceOuttolunch; - }else if (strstr(body->body,"closed")!=NULL){ - estatus=SalPresenceOffline; - }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { - estatus=SalPresenceOnline; - }else if(strstr(body->body,"vacation") != NULL) { - estatus = SalPresenceOnVacation; - }else{ - estatus=SalPresenceOffline; - } - ms_message("We are notified that %s has online status %i",tmp,estatus); - if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - ms_message("And outgoing subscription terminated by remote."); - } - sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL); - - /* try to detect presence message style used by server, - * and switch our presence messages to servers style */ - if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) { - presence_style = RFCxxxx; - } else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) { - presence_style = MSOLDPRES; - } - - osip_free(tmp); -} - -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription answered but no associated op !"); - return; - } - op->did=ev->did; -} - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_in_subscribe(sal,ev->nid); - char *tmp; - if (op==NULL){ - ms_error("Incoming subscription closed but no associated op !"); - return; - } - - - sal_remove_in_subscribe(sal,op); - op->nid=-1; - op->did=-1; - if (ev->request){ - osip_from_to_str(ev->request->from,&tmp); - sal->callbacks.subscribe_closed(op,tmp); - osip_free(tmp); - } -} - -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription closed but no associated op !"); - return; - } - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - sal->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); -} - - diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c deleted file mode 100644 index 54865aab6..000000000 --- a/coreapi/sal_eXosip2_sdp.c +++ /dev/null @@ -1,618 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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 "ortp/port.h" -#include "ortp/b64.h" -#include "ortp/ortp_srtp.h" -#include "sal.h" -#include - -#define keywordcmp(key,b) strcmp(key,b) - -#ifdef FOR_LATER - -static char *make_relay_session_id(const char *username, const char *relay){ - /*ideally this should be a hash of the parameters with a random part*/ - char tmp[128]; - int s1=(int)random(); - int s2=(int)random(); - long long int res=((long long int)s1)<<32 | (long long int) s2; - void *src=&res; - b64_encode(src, sizeof(long long int), tmp, sizeof(tmp)); - return osip_strdup(tmp); -} - - -static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){ - - if (relay) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-addr"),osip_strdup(relay)); - if (relay_session_id) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-session-id"), osip_strdup(relay_session_id)); -} - -#endif - -static char * int_2char(int a){ - char *p=osip_malloc(16); - snprintf(p,16,"%i",a); - return p; -} - -/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ -static const char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field) -{ - int i,tmppt=0,scanned=0; - char *tmp; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1 || nb==2 ){ - if (pt==tmppt){ - tmp=attr->a_att_value+scanned; - if (strlen(tmp)>0) - return tmp; - } - }else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); - } - } - return NULL; -} - -#ifdef FOR_LATER -/* return the value of attr "field" */ -static const char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field) -{ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - return attr->a_att_value; - } - } - return NULL; -} -#endif - -static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ - int i,ret; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("ptime",attr->a_att_field)==0){ - int nb = sscanf(attr->a_att_value,"%i",&ret); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1){ - return ret; - }else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value); - } - } - return 0; -} - -static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("sendrecv",attr->a_att_field)==0){ - return SalStreamSendRecv; - }else if (keywordcmp("sendonly",attr->a_att_field)==0){ - return SalStreamSendOnly; - }else if (keywordcmp("recvonly",attr->a_att_field)==0){ - return SalStreamRecvOnly; - }else if (keywordcmp("inactive",attr->a_att_field)==0){ - return SalStreamInactive; - } - } - return SalStreamSendRecv; -} - -static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) -{ - sdp_message_t *local; - int inet6; - char sessid[16]; - char sessver[16]; - const char *rtp_addr = desc->addr; - - snprintf(sessid,16,"%i",desc->session_id); - snprintf(sessver,16,"%i",desc->session_ver); - sdp_message_init (&local); - if (strchr(desc->addr,':')!=NULL){ - inet6=1; - }else inet6=0; - sdp_message_v_version_set (local, osip_strdup ("0")); - sdp_message_o_origin_set (local, osip_strdup (desc->username), - osip_strdup (sessid), osip_strdup (sessver), - osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), - osip_strdup (desc->addr)); - sdp_message_s_name_set (local, osip_strdup ("Talk")); - /* Do not set the c= line to 0.0.0.0 if there is an ICE session. */ - if((desc->ice_ufrag[0] != '\0') || !sal_media_description_has_dir (desc,SalStreamSendOnly)) - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - else - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL); - } - sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ice_completed == TRUE) sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - - return local; -} - - -static bool_t is_known_rtpmap(const PayloadType *pt){ - switch(payload_type_get_number(pt)){ - case 0: - case 8: - case 3: - case 34: - return TRUE; - } - return FALSE; -} - -static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, bool_t strip_well_known_rtpmaps) -{ - char attr[256]; - sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt))); - - if (!strip_well_known_rtpmaps || !is_known_rtpmap(pt)){ - if (pt->channels>1) - snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate,pt->channels); - else - snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate); - sdp_message_a_attribute_add (msg, line, - osip_strdup ("rtpmap"), osip_strdup(attr)); - } - - if (pt->recv_fmtp != NULL) - { - snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp); - sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"), - osip_strdup(attr)); - } -} - -static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - const SalIceCandidate *candidate; - int nb; - int i; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { - candidate = &desc->ice_candidates[i]; - if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; - nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", - candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - if (candidate->raddr[0] != '\0') { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - } - sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); - } -} - -static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - char *ptr = buffer; - const SalIceRemoteCandidate *candidate; - int offset = 0; - int i; - - buffer[0] = '\0'; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { - candidate = &desc->ice_remote_candidates[i]; - if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { - offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); - if (offset < 0) { - ms_error("Cannot add ICE remote-candidates attribute!"); - return; - } - ptr += offset; - } - } - if (buffer[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); -} - -static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ - const char *mt=NULL; - const MSList *elem; - const char *rtp_addr; - const char *rtcp_addr; - const char *dir="sendrecv"; - int rtp_port; - int rtcp_port; - bool_t strip_well_known_rtpmaps; - bool_t different_rtp_and_rtcp_addr; - - switch (desc->type) { - case SalAudio: - mt="audio"; - break; - case SalVideo: - mt="video"; - break; - case SalOther: - mt=desc->typeother; - break; - } - rtp_addr=desc->rtp_addr; - rtcp_addr=desc->rtcp_addr; - rtp_port=desc->rtp_port; - rtcp_port=desc->rtcp_port; - - if (desc->proto == SalProtoRtpSavp) { - int i; - - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/SAVP")); - - /* add crypto lines */ - for(i=0; icrypto[i].algo) { - case AES_128_SHA1_80: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_80", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_SHA1_32: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_32", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_NO_AUTH: - ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); - break; - case NO_CIPHER_SHA1_80: - ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); - break; - default: - i = SAL_CRYPTO_ALGO_MAX; - } - } - - } else { - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/AVP")); - - } - - /*only add a c= line within the stream description if address are differents*/ - if (rtp_addr[0]!='\0' && strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ - bool_t inet6; - if (strchr(rtp_addr,':')!=NULL){ - inet6=TRUE; - }else inet6=FALSE; - sdp_message_c_connection_add (msg, lineno, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), - int_2char(desc->ptime)); - strip_well_known_rtpmaps=ms_list_size(desc->payloads)>5; - if (desc->payloads){ - for(elem=desc->payloads;elem!=NULL;elem=elem->next){ - add_payload(msg, lineno, (PayloadType*)elem->data,strip_well_known_rtpmaps); - } - }else{ - /* to comply with SDP we cannot have an empty payload type number list */ - /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ - sdp_message_m_payload_add (msg,lineno, int_2char (0)); - } - switch(desc->dir){ - case SalStreamSendRecv: - /*dir="sendrecv";*/ - dir=NULL; - break; - case SalStreamRecvOnly: - dir="recvonly"; - break; - case SalStreamSendOnly: - dir="sendonly"; - break; - case SalStreamInactive: - dir="inactive"; - break; - } - if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - if (rtp_port != 0) { - different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); - if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { - if (different_rtp_and_rtcp_addr == TRUE) { - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); - } else { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); - } - } - } - if (desc->ice_completed == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("nortpproxy"), osip_strdup("yes")); - } - if (desc->ice_mismatch == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); - } else { - if (desc->rtp_port != 0) { - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - add_ice_candidates(msg, lineno, desc); - add_ice_remote_candidates(msg, lineno, desc); - } - } -} - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ - int i; - sdp_message_t *msg=create_generic_sdp(desc); - for(i=0;in_total_streams;++i){ - add_line(msg,i,&desc->streams[i]); - } - return msg; -} - -static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ - if (rtpmap==NULL){ - PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt)); - if (refpt){ - pt->mime_type=ms_strdup(refpt->mime_type); - pt->clock_rate=refpt->clock_rate; - }else{ - ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.", - payload_type_get_number(pt)); - return -1; - } - }else{ - char *mime=ms_strdup(rtpmap); - char *p=strchr(mime,'/'); - if (p){ - char *chans; - *p='\0'; - p++; - chans=strchr(p,'/'); - if (chans){ - *chans='\0'; - chans++; - pt->channels=atoi(chans); - }else pt->channels=1; - pt->clock_rate=atoi(p); - } - pt->mime_type=mime; - } - return 0; -} - -int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ - int i,j; - const char *mtype,*proto,*rtp_port,*rtp_addr,*number; - const char *sess; - sdp_bandwidth_t *sbw=NULL; - sdp_attribute_t *attr; - int nb_ice_candidates; - - /* Get session information. */ - sess = sdp_message_o_sess_id_get(msg); - if (sess) desc->session_id = strtoul(sess, NULL, 10); - sess = sdp_message_o_sess_version_get(msg); - if (sess) desc->session_ver = strtoul(sess, NULL, 10); - - rtp_addr=sdp_message_c_addr_get (msg, -1, 0); - if (rtp_addr) - strncpy(desc->addr,rtp_addr,sizeof(desc->addr)); - for(j=0;(sbw=sdp_message_bandwidth_get(msg,-1,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth); - } - - /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ - for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { - if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_ufrag, attr->a_att_value, sizeof(desc->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_pwd, attr->a_att_value, sizeof(desc->ice_pwd)); - } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { - desc->ice_lite = TRUE; - } - } - - desc->n_active_streams = 0; - - /* for each m= line */ - for (i=0; !sdp_message_endof_media (msg, i) && istreams[i]; - nb_ice_candidates = 0; - - memset(stream,0,sizeof(*stream)); - mtype = sdp_message_m_media_get(msg, i); - proto = sdp_message_m_proto_get (msg, i); - rtp_port = sdp_message_m_port_get(msg, i); - stream->proto=SalProtoUnknown; - if (proto){ - if (strcasecmp(proto,"RTP/AVP")==0) - stream->proto=SalProtoRtpAvp; - else if (strcasecmp(proto,"RTP/SAVP")==0){ - stream->proto=SalProtoRtpSavp; - } - } - rtp_addr = sdp_message_c_addr_get (msg, i, 0); - if (rtp_addr != NULL) - strncpy(stream->rtp_addr,rtp_addr,sizeof(stream->rtp_addr)); - if (rtp_port) - stream->rtp_port=atoi(rtp_port); - if (stream->rtp_port > 0) - desc->n_active_streams++; - - stream->ptime=_sdp_message_get_a_ptime(msg,i); - if (strcasecmp("audio", mtype) == 0){ - stream->type=SalAudio; - }else if (strcasecmp("video", mtype) == 0){ - stream->type=SalVideo; - }else { - stream->type=SalOther; - strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1); - } - for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); - } - stream->dir=_sdp_message_get_mline_dir(msg,i); - /* for each payload type */ - for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ - const char *rtpmap,*fmtp; - int ptn=atoi(number); - PayloadType *pt=payload_type_new(); - payload_type_set_number(pt,ptn); - /* get the rtpmap associated to this codec, if any */ - rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); - if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){ - /* get the fmtp, if any */ - fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); - payload_type_set_send_fmtp(pt,fmtp); - stream->payloads=ms_list_append(stream->payloads,pt); - ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, - pt->send_fmtp ? pt->send_fmtp : ""); - } - } - - /* Get media specific RTCP attribute */ - stream->rtcp_port = stream->rtp_port + 1; - snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); - for (j = 0; ((attr = sdp_message_attribute_get(msg, i, j)) != NULL); j++) { - if ((keywordcmp("rtcp", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - char tmp[256]; - int nb = sscanf(attr->a_att_value, "%d IN IP4 %s", &stream->rtcp_port, tmp); - if (nb == 1) { - /* SDP rtcp attribute only contains the port */ - } else if (nb == 2) { - strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); - } else { - ms_warning("sdp has a strange a= line (%s) nb=%i", attr->a_att_value, nb); - } - } - } - - /* read crypto lines if any */ - if (stream->proto == SalProtoRtpSavp) { - int k, valid_count = 0; - - memset(&stream->crypto, 0, sizeof(stream->crypto)); - for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){ - char tmp[256], tmp2[256]; - if (keywordcmp("crypto",attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value, "%d %255s inline:%255s", - &stream->crypto[valid_count].tag, - tmp, - tmp2); - ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - tmp2); - if (nb == 3) { - if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_80") == 0) - stream->crypto[valid_count].algo = AES_128_SHA1_80; - else if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_32") == 0) - stream->crypto[valid_count].algo = AES_128_SHA1_32; - else { - ms_warning("Failed to parse crypto-algo: '%s'", tmp); - stream->crypto[valid_count].algo = 0; - } - if (stream->crypto[valid_count].algo) { - strncpy(stream->crypto[valid_count].master_key, tmp2, 41); - stream->crypto[valid_count].master_key[40] = '\0'; - ms_message("Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - stream->crypto[valid_count].master_key); - valid_count++; - } - } else { - ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); - } - } - } - ms_message("Found: %d valid crypto lines", valid_count); - } - - /* Get ICE candidate attributes if any */ - for (j = 0; (attr = sdp_message_attribute_get(msg, i, j)) != NULL; j++) { - if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; - int nb = sscanf(attr->a_att_value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", - candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, - candidate->type, candidate->raddr, &candidate->rport); - if ((nb == 6) || (nb == 8)) nb_ice_candidates++; - else memset(candidate, 0, sizeof(*candidate)); - } else if ((keywordcmp("remote-candidates", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceRemoteCandidate candidate; - unsigned int componentID; - int offset; - char *ptr = attr->a_att_value; - while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { - if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { - SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; - strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); - remote_candidate->port = candidate.port; - } - ptr += offset; - if (ptr[offset] == ' ') ptr += 1; - } - } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_ufrag, attr->a_att_value, sizeof(stream->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_pwd, attr->a_att_value, sizeof(stream->ice_pwd)); - } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { - stream->ice_mismatch = TRUE; - } - } - } - desc->n_total_streams=i; - return 0; -}