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
static int tport_udp_init_stun(tport_primary_t *,
53 54
			       tp_name_t tpn[1],
			       su_addrinfo_t *,
Pekka Pessi's avatar
Pekka Pessi committed
55 56
			       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,
101 102
			       tp_name_t tpn[1],
			       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
#if 0
124
  if (stun_obtain_shared_secret(sh, tport_stun_tls_cb, pri,
Pekka Pessi's avatar
Pekka Pessi committed
125 126 127
				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
  if (pri->pri_stun_handle)
    stun_handle_destroy(pri->pri_stun_handle);
147
  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
    SU_DEBUG_5(("%s: stun_bind() ok: local address NATed as %s:%u\n",
199
		__func__,
200 201
		su_inet_ntop(su->su_family, SU_ADDR(su),
			     ipname, sizeof(ipname)),
202
		(unsigned) ntohs(su->su_port)));
203 204
  }

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

Pekka Pessi's avatar
Pekka Pessi committed
210
  return;
211 212
}

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

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

Pekka Pessi's avatar
Pekka Pessi committed
230 231
  if (err < 0)
    return -1;
232

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

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