tport_type_stun.c 5.44 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2006 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

25
/**@CFILE tport_type_stun.c Transport using stun.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
 *
 * See tport.docs for more detailed description of tport interface.
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 * @author Martti Mela <Martti.Mela@nokia.com>
 *
 * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
 */

#include "config.h"

#define STUN_DISCOVERY_MAGIC_T  struct tport_primary

#include "tport_internal.h"

#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>

/* ---------------------------------------------------------------------- */
/* STUN */

Pekka Pessi's avatar
Pekka Pessi committed
50
#include <sofia-sip/stun.h>
51

Pekka Pessi's avatar
Pekka Pessi committed
52 53 54 55 56
static int tport_udp_init_stun(tport_primary_t *,
			       tp_name_t tpn[1], 
			       su_addrinfo_t *, 
			       tagi_t const *,
			       char const **return_culprit);
57

Pekka Pessi's avatar
Pekka Pessi committed
58
static void tport_udp_deinit_stun(tport_primary_t *pri);
59 60

static
Pekka Pessi's avatar
Pekka Pessi committed
61 62 63 64 65
void tport_stun_bind_cb(tport_primary_t *pri,
			stun_handle_t *sh,
			stun_discovery_t *sd,
			stun_action_t action,
			stun_state_t event);
66 67 68 69 70
static
void tport_stun_bind_done(tport_primary_t *pri,
			  stun_handle_t *sh,
			  stun_discovery_t *sd);
static
Pekka Pessi's avatar
Pekka Pessi committed
71 72
int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
			 tagi_t const *taglist);
73

74 75 76 77
static int tport_stun_response(tport_t const *self,
			       void *dgram, size_t n,
			       void *from, socklen_t fromlen);

78
tport_vtable_t const tport_stun_vtable =
79 80
{
  "UDP", tport_type_stun,
81
  sizeof (tport_primary_t),
82 83
  tport_udp_init_stun,
  tport_udp_deinit_stun,
84 85 86 87 88 89 90 91 92 93
  NULL,
  NULL,
  sizeof (tport_t),
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  tport_recv_dgram,
  tport_send_dgram,
Pekka Pessi's avatar
Pekka Pessi committed
94 95 96
  NULL,
  NULL,
  tport_stun_keepalive,
97
  tport_stun_response
98 99 100
};

static int tport_udp_init_stun(tport_primary_t *pri,
Pekka Pessi's avatar
Pekka Pessi committed
101
			       tp_name_t tpn[1], 
102
			       su_addrinfo_t *ai, 
Pekka Pessi's avatar
Pekka Pessi committed
103
			       tagi_t const *tags,
104 105
			       char const **return_culprit)
{
Pekka Pessi's avatar
Pekka Pessi committed
106
  stun_handle_t *sh;
107

108
#if 0
Pekka Pessi's avatar
Pekka Pessi committed
109
  if (!stun_is_requested(TAG_NEXT(tags)))
110
    return -1;
111
#endif
112

Pekka Pessi's avatar
Pekka Pessi committed
113 114 115
  sh = stun_handle_init(pri->pri_master->mr_root, TAG_NEXT(tags));
  if (!sh)
    return *return_culprit = "stun_handle_init", -1;
116

117
  pri->pri_stun_handle = sh;
Pekka Pessi's avatar
Pekka Pessi committed
118
  tpn->tpn_canon = NULL;
119

Pekka Pessi's avatar
Pekka Pessi committed
120 121
  if (tport_udp_init_primary(pri, tpn, ai, tags, return_culprit) < 0)
    return -1;
122

Pekka Pessi's avatar
Pekka Pessi committed
123 124 125 126 127
#if 0
  if (stun_obtain_shared_secret(sh, tport_stun_tls_cb, pri, 
				TAG_NEXT(tags)) < 0) {
    return *return_culprit = "stun_request_shared_secret()", -1;
  }
128 129
#endif

Pekka Pessi's avatar
Pekka Pessi committed
130 131 132 133 134 135
  if (stun_bind(sh, tport_stun_bind_cb, pri,
		STUNTAG_SOCKET(pri->pri_primary->tp_socket),
		STUNTAG_REGISTER_EVENTS(0),
		TAG_NULL()) < 0) {
    return *return_culprit = "stun_bind()", -1;
  }
136

Pekka Pessi's avatar
Pekka Pessi committed
137
  pri->pri_updating = 1;
138 139 140 141

  return 0;
}

142

Pekka Pessi's avatar
Pekka Pessi committed
143
static void tport_udp_deinit_stun(tport_primary_t *pri)
144
{
145 146 147
  if (pri->pri_stun_handle) 
    stun_handle_destroy(pri->pri_stun_handle); 
  pri->pri_stun_handle = NULL;
148 149 150
}


151 152 153 154
static int tport_stun_response(tport_t const *self,
			       void *dgram, size_t n,
			       void *from, socklen_t fromlen)
{
155
  stun_process_message(self->tp_pri->pri_stun_handle, self->tp_socket,
156 157 158 159 160 161
		       from, fromlen, (void *)dgram, n);

  return 3;
}


Pekka Pessi's avatar
Pekka Pessi committed
162 163
/**Callback for STUN bind */
static
164 165 166 167 168 169 170 171 172 173 174
void tport_stun_bind_cb(tport_primary_t *pri,
			stun_handle_t *sh,
			stun_discovery_t *sd,
			stun_action_t action,
			stun_state_t event)
{
  tport_master_t *mr;
  SU_DEBUG_3(("%s: %s\n", __func__, stun_str_state(event)));

  mr = pri->pri_master;

175
  if (event == stun_discovery_done) {
176
    tport_stun_bind_done(pri, sh, sd);
Pekka Pessi's avatar
Pekka Pessi committed
177
  }
178 179
}

180

181 182 183 184 185
static
void tport_stun_bind_done(tport_primary_t *pri,
			  stun_handle_t *sh,
			  stun_discovery_t *sd)
{
Pekka Pessi's avatar
Pekka Pessi committed
186 187
  tport_t *self = pri->pri_primary;
  su_socket_t socket;
188 189
  su_sockaddr_t *su = self->tp_addr;
  su_addrinfo_t *ai = self->tp_addrinfo;
190

Pekka Pessi's avatar
Pekka Pessi committed
191 192
  socket = stun_discovery_get_socket(sd);
  assert(pri->pri_primary->tp_socket == socket);
193

194 195 196
  if (stun_discovery_get_address(sd, su, &ai->ai_addrlen) == 0) {
    char ipname[SU_ADDRSIZE + 2] = { 0 };
    ai->ai_addr = (void *)su;
197

198 199 200 201
    SU_DEBUG_5(("%s: stun_bind() ok: local address NATed as %s:%u\n", 
		__func__,
		inet_ntop(su->su_family, SU_ADDR(su), ipname, sizeof(ipname)),
		(unsigned) ntohs(su->su_port)));
202 203
  }

Pekka Pessi's avatar
Pekka Pessi committed
204 205 206 207
  /* Send message to calling application indicating 
   * there's a new public address available 
   */
  tport_has_been_updated(self);
208
  
Pekka Pessi's avatar
Pekka Pessi committed
209
  return;
210 211
}

Pekka Pessi's avatar
Pekka Pessi committed
212
/** Initialize STUN keepalives.
213
 *
Pekka Pessi's avatar
Pekka Pessi committed
214
 *@retval 0
215 216
 */
static
Pekka Pessi's avatar
Pekka Pessi committed
217 218
int tport_stun_keepalive(tport_t *tp, su_addrinfo_t const *ai,
			 tagi_t const *taglist)
219
{
Pekka Pessi's avatar
Pekka Pessi committed
220 221
  tport_primary_t *pri = tp->tp_pri;
  int err;
222

223
  err = stun_keepalive(pri->pri_stun_handle, 
Pekka Pessi's avatar
Pekka Pessi committed
224 225 226 227 228 229 230
		       (su_sockaddr_t *)ai->ai_addr,
		       STUNTAG_SOCKET(tp->tp_socket),
		       STUNTAG_TIMEOUT(10000),
		       TAG_NEXT(taglist));
  
  if (err < 0)
    return -1;
231

Pekka Pessi's avatar
Pekka Pessi committed
232
  tp->tp_has_keepalive = 1;
233

Pekka Pessi's avatar
Pekka Pessi committed
234
  return 0;
235 236
}