anchor.diff:  handle_call({send, Ip, Port, Packet}, _From, #state{socket=Socket}=State) ->
       {reply, gen_udp:send(Socket, Ip, Port, Packet), State};
   
  -handle_call({send_stun, Ip, Port}, From, #state{
  -                                                app_id=AppId, 
  -                                                socket=Socket, 
  -                                                stuns=Stuns}=State) ->
  -    {Id, Packet} = nksip_stun:binding_request(),
  -    case gen_udp:send(Socket, Ip, Port, Packet) of
  -        ok -> 
  -            Now = nksip_lib:timestamp(),
  -            Stuns1 = [{I, T, F} || {I, T, F} <- Stuns, Now-T < 5],
  -            Stuns2 = [{Id, nksip_lib:timestamp(), From}|Stuns1],
  -            {noreply, State#state{stuns=Stuns2}};
  -        {error, Error} ->
  -            ?notice(AppId, "could not send UDP STUN request to ~p:~p: ~p", 
  -                  [Ip, Port, Error]),
  -            {reply, error, State}
  +handle_call({send_stun, Ip, Port}, From, State) ->
  +    case do_send_stun(Ip, Port, {srv, From}, State) of
  +        {ok, State1} -> {noreply, State1};
  +        {error, State1} -> {reply, error, State1}
       end;
   
   handle_call(get_port, _From, #state{transport=#transport{listen_port=Port}}=State) ->
       {reply, {ok, Port}, State};
   
  -handle_call({connect, Ip, Port, Timeout}, _From, State) ->
  -    #state{app_id=AppId, transport=Transp, conns=Conns} = State,
  -    Transp1 = Transp#transport{
  -        remote_ip = Ip,
  -        remote_port = Port
  -    },
  -    ?debug(AppId, "connected to ~s:~p (udp)", 
  -        [nksip_lib:to_host(Ip), Port]),
  -    nksip_proc:put({nksip_connection, {AppId, udp, Ip, Port}}, Transp1), 
  -    Ref = erlang:start_timer(Timeout, self(), check_connection),
  -    Conns1 = [{Ref, Ip, Port}|Conns],
  -    {reply, ok, State#state{conns=Conns1}};
  +handle_call({connect, Ip, Port}, _From, State) ->
  +    {reply, ok, do_connect_create(Ip, Port, State)};
   
   handle_call(Msg, _Form, State) -> 
       lager:warning("Module ~p received unexpected call: ~p", [?MODULE, Msg]),
  
positive.code:             ?debug(AppId, "sent STUN Bind to ~p:~p", [Ip, Port]),
              {noreply, State};
          {response, binding, TransId, Attrs} ->
              case lists:keytake(TransId, 1, Stuns) of
                  false ->
                      ?debug(AppId, "received unexpected STUN response", []),
                      {noreply, State};
                  {value, {TransId, _, From}, Stuns1} ->
                      gen_server:reply(From, {ok, Attrs}),
                      {noreply, State#state{stuns=Stuns1}}
              end;
          error ->
              ?notice(AppId, "received unrecognized UDP Packet: ~p", [Packet]),
              {noreply, State}
  
negative.code:     end.
  
  
  %% @private
  start_timer(Time, Msg) ->
      erlang:start_timer(Time, self(), Msg).
  
  
  %% @private
  do_send_stun(Ip, Port, From, State) ->
      #state{app_id=AppId, timer_t1=T1, stuns=Stuns, socket=Socket} = State,
      {Id, Packet} = nksip_stun:binding_request(),
      case gen_udp:send(Socket, Ip, Port, Packet) of
          ok -> 
              Stun = #stun{
                  dest = {Ip, Port},
                  id = Id,
                  packet = Packet,
                  retrans_ref = start_timer(T1, stun_retrans),
                  next_retrans = 2*T1,
                  from = From
              },
              {ok, State#state{stuns=[Stun|Stuns]}};
          {error, Error} ->
              ?notice(AppId, "could not send UDP STUN request to ~p:~p: ~p", 
                    [Ip, Port, Error]),
              {error, State}
      end.
  
  
  %% @private
  do_stun_retrans(Ref, State) ->
      #state{app_id=AppId, stuns=Stuns, timer_t1=T1, socket=Socket} = State,
      {value, Stun, Stuns1} = lists:keytake(Ref, #stun.retrans_ref, Stuns),
      #stun{
          dest = {Ip, Port},
          packet = Packet,
          next_retrans = Next
      } = Stun,
      case Next < (7*T1) of
          true ->
              case gen_udp:send(Socket, Ip, Port, Packet) of
                  ok -> 
                      Stun1 = Stun#stun{
                          retrans_ref = start_timer(Next, stun_retrans),
                          next_retrans = 2*Next
                      },
                      State#state{stuns=[Stun1|Stuns1]};
                  {error, Error} ->
                      ?notice(AppId, "could not send UDP STUN request to ~p:~p: ~p", 
                            [Ip, Port, Error]),
                      do_stun_timeout(Stun, State#state{stuns=Stuns1})
              end;
          false ->
              do_stun_timeout(Stun, State#state{stuns=Stuns1})
      end.
  
  
  %% @private
  do_stun_reply(TransId, Attrs, #state{app_id=AppId, stuns=Stuns}=State) ->
      case lists:keytake(TransId, #stun.id, Stuns) of
          {value, #stun{dest={Ip, Port}, retrans_ref=Retrans, from=From}, Stuns1} ->
              erlang:cancel_timer(Retrans),
              State1 = State#state{stuns=Stuns1},
              case From of
                  {srv, SrvFrom} -> 
                      gen_server:reply(SrvFrom, {ok, Attrs}),
                      State1;
                  conn -> 
                      case nksip_lib:get_value(xor_mapped_address, Attrs) of
                          {StunIp, StunPort} -> 
                              ok;
                          _ ->
                              case nksip_lib:get_value(mapped_address, Attrs) of
                                  {StunIp, StunPort} -> ok;
                                  _ -> StunIp = StunPort = undefined
                              end
                      end,
                      do_connect_reply(Ip, Port, StunIp, StunPort, State1)
              end;
          false ->
              ?notice(AppId, "received unexpected STUN response", []),
              State
      end.
  
  
  %% @private
  do_stun_timeout(#stun{dest={Ip, Port}, from=From}, State) ->
      case From of
          {srv, SrvFrom} -> 
              gen_server:reply(SrvFrom, error),
              State;
          conn -> 
              do_connect_timeout(Ip, Port, State)
      end.
      
  
  %% @private
  do_connect_create(Ip, Port, State) ->
      #state{app_id=AppId, transport=Transp, conns=Conns, timer_t1=T1} = State,
      Transp1 = Transp#transport{
          remote_ip = Ip,
          remote_port = Port
      },
      ?debug(AppId, "connected to ~s:~p (udp)", [nksip_lib:to_host(Ip), Port]),
      nksip_proc:put({nksip_connection, {AppId, udp, Ip, Port}}, Transp1), 
      Conn = #conn{
          dest = {Ip, Port},
          timeout_ref = erlang:start_timer(64*T1, self(), conn_timeout),
          time = undefined
      },
      State#state{conns=[Conn|Conns]}.
  
  
  %% @private
  do_connect_start(Ip, Port, Secs, #state{app_id=AppId, conns=Conns}=State) ->
      Time = 1000*Secs,
      case lists:keytake({Ip, Port}, #conn.dest, Conns) of
          {value, #conn{timeout_ref=TimeoutRef}=Conn, Conns1} ->
              erlang:cancel_timer(TimeoutRef),
              Conn1 = Conn#conn{
                  refresh_ref = erlang:start_timer(Time, self(), conn_refresh),
                  time = Time
              },
              State#state{conns=[Conn1|Conns1]};
          false ->
              ?warning(AppId, "Could not start UDP refresh: no connection", []),
              State
      end.
  
  
  %% @private
  do_connect_refresh(Ref, #state{conns=Conns}=State) ->
       case lists:keytake(Ref, #conn.refresh_ref, Conns) of
          {value, Conn, Conns1} ->
              #conn{dest={Ip, Port}} = Conn,
              case do_send_stun(Ip, Port, conn, State) of
                  {ok, State1} -> State1;
                  {error, State1} -> State1#state{conns=Conns1}
              end;
          false ->
              {noreply, State}
      end.
  
  
  %% @private
  do_connect_reply(Ip, Port, StunIp, StunPort, #state{conns=Conns}=State) ->
      case lists:keytake({Ip, Port}, #conn.dest, Conns) of
          {value, #conn{stun=StunDest, time=Time}=Conn, Conns1} ->
              case StunDest of
                  {StunIp, StunPort} ->
                      Conn1 = Conn#conn{
                          refresh_ref = erlang:start_timer(Time, self(), conn_refresh)
                      },
                      State#state{conns=[Conn1|Conns1]};
                  _ ->
                      do_connect_timeout(Ip, Port, State#state{conns=Conns1})
              end;
          false ->
              State
      end.
  
  do_connect_timeout(_Ip, _Port, State) ->
      State.
  
  
  
  
  