Commit d4c2c25c authored by smorlat's avatar smorlat

- stun improvements (untested)

- support for one relay (work in progress)



git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@18 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
parent d9e7d7b3
......@@ -436,7 +436,8 @@ int linphone_set_audio_offer(sdp_context_t *ctx)
sdp_payload_init(&payload);
payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate);
payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap);
payload.localport=lc->rtp_conf.audio_rtp_port;
payload.localport=call->audio_params.natd_port > 0 ?
call->audio_params.natd_port : lc->rtp_conf.audio_rtp_port;
if (strcasecmp(codec->mime_type,"iLBC")==0){
/* prefer the 30 ms mode */
payload.a_fmtp="ptime=30";
......@@ -511,7 +512,8 @@ int linphone_set_video_offer(sdp_context_t *ctx)
sdp_payload_init(&payload);
payload.line=1;
payload.a_rtpmap=ortp_strdup_printf("%s/%i",codec->mime_type,codec->clock_rate);
payload.localport=lc->rtp_conf.video_rtp_port;
payload.localport=call->video_params.natd_port>0 ?
call->video_params.natd_port : lc->rtp_conf.video_rtp_port;
payload.pt=find_payload_type_number(lc->local_profile,codec);
payload.a_fmtp=codec->recv_fmtp;
if(firsttime){
......@@ -628,7 +630,9 @@ int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload)
params=&call->audio_params;
if (params->initialized==0){
/* this is the first codec we accept, it is going to be used*/
params->localport=payload->localport=lc->rtp_conf.audio_rtp_port;
params->localport=lc->rtp_conf.audio_rtp_port;
payload->localport=params->natd_port>0 ?
params->natd_port : lc->rtp_conf.audio_rtp_port;
params->line=payload->line;
params->pt=payload->pt; /* remember the first payload accepted */
if (payload->relay_host!=NULL){
......@@ -678,7 +682,8 @@ int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload)
params=&call->video_params;
if (params->initialized==0){
/* this is the first codec we may accept*/
params->localport=payload->localport=lc->rtp_conf.video_rtp_port;
params->localport=lc->rtp_conf.video_rtp_port;
payload->localport=params->natd_port>0 ? params->natd_port : lc->rtp_conf.video_rtp_port;
params->line=payload->line;
params->pt=payload->pt; /* remember the first payload accepted */
if (payload->relay_host!=NULL){
......
......@@ -25,7 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sdphandler.h"
#include <ortp/telephonyevents.h>
#include <ortp/stun.h>
#include "exevents.h"
......@@ -81,6 +80,8 @@ static void linphone_call_init_common(LinphoneCall *call, char *from, char *to)
call->start_time=time(NULL);
call->log=linphone_call_log_new(call, from, to);
linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE);
if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN)
linphone_core_run_stun_tests(call->core,call);
}
void linphone_call_init_media_params(LinphoneCall *call){
......@@ -112,10 +113,12 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const osip_f
call->tid=-1;
call->core=lc;
linphone_core_get_local_ip(lc,to->url->host,localip);
call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,localip,from->url->username,NULL);
osip_from_to_str(from,&fromstr);
osip_to_to_str(to,&tostr);
linphone_call_init_common(call,fromstr,tostr);
call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,
call->audio_params.natd_port>0 ? call->audio_params.natd_addr : localip,
from->url->username,NULL);
discover_mtu(lc,to->url->host);
return call;
}
......@@ -135,8 +138,10 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const char *from, co
osip_from_init(&from_url);
osip_from_parse(from_url, from);
linphone_core_get_local_ip(lc,from_url->url->host,localip);
call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,localip,me->url->username,NULL);
linphone_call_init_common(call, osip_strdup(from), osip_strdup(to));
call->sdpctx=sdp_handler_create_context(&linphone_sdphandler,
call->audio_params.natd_port>0 ? call->audio_params.natd_addr : localip,
me->url->username,NULL);
discover_mtu(lc,from_url->url->host);
osip_from_free(me);
osip_from_free(from_url);
......@@ -733,35 +738,6 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
return 0;
}
static bool_t stun_get_localip(LinphoneCore *lc, char *result, int *port){
const char *server=linphone_core_get_stun_server(lc);
StunAddress4 addr;
StunAddress4 mapped;
StunAddress4 changed;
if (server!=NULL){
if (stunParseServerName((char*)server,&addr)){
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
if (stunTest(&addr,1,TRUE,NULL,&mapped,&changed)==0){
struct in_addr inaddr;
char *tmp;
inaddr.s_addr=ntohl(mapped.addr);
tmp=inet_ntoa(inaddr);
*port=ntohs(mapped.port);
strncpy(result,tmp,LINPHONE_IPADDR_SIZE);
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Stun lookup done..."));
ms_message("Stun server says we have address %s:i",result,*port);
return TRUE;
}else{
ms_warning("stun lookup failed.");
}
}else{
ms_warning("Fail to resolv or parse %s",server);
}
}
return FALSE;
}
/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */
void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){
......@@ -777,14 +753,17 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
}else{
/* we no more use stun for sip socket*/
#if 0
int mport=0;
ms_message("doing stun lookup for local address...");
if (stun_get_localip(lc,result,&mport)){
if (stun_get_localip(lc,sock,linphone_core_get_sip_port(lc),result,&mport)){
if (!lc->net_conf.nat_sdp_only)
eXosip_masquerade_contact(result,mport);
return;
}
ms_warning("stun lookup failed, falling back to a local interface...");
#endif
}
}
......
......@@ -25,6 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "ortp/payloadtype.h"
#include "mediastreamer2/mscommon.h"
#define LINPHONE_IPADDR_SIZE 64
#ifdef __cplusplus
extern "C" {
#endif
......@@ -145,6 +147,8 @@ typedef struct _StreamParams
char *remoteaddr;
int pt;
char *relay_session_id;
char natd_addr[LINPHONE_IPADDR_SIZE];
int natd_port;
} StreamParams;
typedef enum _LCState{
......@@ -486,7 +490,7 @@ typedef struct _LinphoneCore
#endif
} LinphoneCore;
#define LINPHONE_IPADDR_SIZE 64
/* THE main API */
......
......@@ -27,7 +27,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <ortp/stun.h>
#ifndef WIN32
......@@ -448,3 +450,165 @@ bool_t host_has_ipv6_network()
#endif
static ortp_socket_t create_socket(int local_port){
struct sockaddr_in laddr;
ortp_socket_t sock;
int optval;
sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
if (sock<0) {
ms_error("Fail to create socket");
return -1;
}
memset (&laddr,0,sizeof(laddr));
laddr.sin_family=AF_INET;
laddr.sin_addr.s_addr=INADDR_ANY;
laddr.sin_port=htons(local_port);
if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
ms_error("Bind to 0.0.0.0:%i failed: %s",local_port,strerror(errno));
close_socket(sock);
return -1;
}
optval=1;
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
(SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
ms_warning("Fail to set SO_REUSEADDR");
}
set_non_blocking_socket(sock);
return sock;
}
static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id){
char buf[STUN_MAX_MESSAGE_SIZE];
int len = STUN_MAX_MESSAGE_SIZE;
StunAtrString username;
StunAtrString password;
StunMessage req;
int err;
memset(&req, 0, sizeof(StunMessage));
memset(&username,0,sizeof(username));
memset(&password,0,sizeof(password));
stunBuildReqSimple( &req, &username, FALSE , FALSE , id);
len = stunEncodeMessage( &req, buf, len, &password, FALSE);
if (len<=0){
ms_error("Fail to encode stun message.");
return -1;
}
err=sendto(sock,buf,len,0,server,addrlen);
if (err<0){
ms_error("sendto failed: %s",strerror(errno));
return -1;
}
return 0;
}
static int parse_stun_server_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
struct addrinfo hints,*res=NULL;
int ret;
const char *port;
char host[NI_MAXHOST];
char *p;
host[NI_MAXHOST-1]='\0';
strncpy(host,server,sizeof(host)-1);
p=strchr(server,':');
if (p) {
*p='\0';
port=p+1;
}else port="3478";
memset(&hints,0,sizeof(hints));
hints.ai_family=PF_INET;
hints.ai_socktype=SOCK_DGRAM;
hints.ai_protocol=IPPROTO_UDP;
ret=getaddrinfo(host,port,&hints,&res);
if (ret!=0){
ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
return -1;
}
if (!res) return -1;
memcpy(ss,res->ai_addr,res->ai_addrlen);
*socklen=res->ai_addrlen;
freeaddrinfo(res);
return 0;
}
static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port){
char buf[STUN_MAX_MESSAGE_SIZE];
int len = STUN_MAX_MESSAGE_SIZE;
StunMessage resp;
len=recv(sock,buf,len,0);
if (len>0){
struct in_addr ia;
stunParseMessage(buf,len, &resp,FALSE );
*port = resp.changedAddress.ipv4.port;
ia.s_addr=htonl(resp.changedAddress.ipv4.addr);
strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
}
return len;
}
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
const char *server=linphone_core_get_stun_server(lc);
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
return;
}
if (server!=NULL){
struct sockaddr_storage ss;
socklen_t ss_len;
ortp_socket_t sock1=-1, sock2=-1;
bool_t video_enabled=linphone_core_video_enabled(lc);
bool_t got_audio,got_video;
struct timeval init,cur;
if (parse_stun_server_addr(server,&ss,&ss_len)<0){
return;
}
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
sock1=create_socket(linphone_core_get_audio_port(lc));
if (sock1<0) return;
if (video_enabled){
sock2=create_socket(linphone_core_get_video_port(lc));
if (sock2<0) return ;
}
sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1);
if (sock2>=0)
sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2);
got_audio=FALSE;
got_video=FALSE;
gettimeofday(&init,NULL);
do{
double elapsed;
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
if (recvStunResponse(sock1,call->audio_params.natd_addr,
&call->audio_params.natd_port)>0){
ms_message("STUN test result: local audio port maps to %s:%i",
call->audio_params.natd_addr,
call->audio_params.natd_port);
got_audio=TRUE;
}
if (recvStunResponse(sock2,call->video_params.natd_addr,
&call->video_params.natd_port)>0){
ms_message("STUN test result: local video port maps to %s:%i",
call->video_params.natd_addr,
call->video_params.natd_port);
got_video=TRUE;
}
gettimeofday(&cur,NULL);
elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
if (elapsed>2000) break;
}while(!(got_audio && (got_video||sock2<0) ) );
close_socket(sock1);
if (sock2>=0) close_socket(sock2);
}
}
......@@ -117,5 +117,6 @@ LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid);
LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid);
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc, const PayloadType *pt);
void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
#endif /* _PRIVATE_H */
......@@ -2067,6 +2067,8 @@ stunTest( StunAddress4 *dest, int testNum, bool_t verbose, StunAddress4* sAddr ,
}
NatType
stunNatType( StunAddress4 *dest,
bool_t verbose,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment