nua_stack.h 13.1 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
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) 2005 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 26
#ifndef NUA_STACK_H
/** Defined when <nua_stack.h> has been included. */
27
#define NUA_STACK_H
Pekka Pessi's avatar
Pekka Pessi committed
28
/**@IFILE nua_stack.h 
29
 * @brief Sofia-SIP User Agent Engine - internal stack interface
Pekka Pessi's avatar
Pekka Pessi committed
30 31 32 33 34 35 36
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
 *
 * @date Created: Wed Feb 14 17:09:44 2001 ppessi
 */

37 38 39 40
#ifndef SU_CONFIG_H
#include <su_config.h>
#endif

41 42 43
#ifndef SU_OS_NW_H
#include <sofia-sip/su_os_nw.h>
#endif
44
#ifndef SOA_H
45
#include "sofia-sip/soa.h"
46 47
#endif
#ifndef NTA_H
48
#include <sofia-sip/nta.h>
49 50
#endif
#ifndef AUTH_CLIENT_H
51
#include <sofia-sip/auth_client.h>
52 53
#endif
#ifndef NEA_H
54
#include <sofia-sip/nea.h>
55 56
#endif
#ifndef NUA_H
57
#include <sofia-sip/nua.h>
Pekka Pessi's avatar
Pekka Pessi committed
58 59
#endif

60
#define SU_LOG (nua_log)
61
#include <sofia-sip/su_debug.h>
Pekka Pessi's avatar
Pekka Pessi committed
62

63 64
#ifndef NUA_DIALOG_H
#define NUA_OWNER_T struct nua_handle_s
65
#include "nua_dialog.h"
66 67
#endif

68 69 70 71 72
SOFIA_BEGIN_DECLS

#if HAVE_SIGCOMP
#include <sigcomp.h>
#endif
Martti Mela's avatar
Martti Mela committed
73

74
#ifndef NUA_PARAMS_H
75
#include "nua_params.h"
76 77
#endif

78
typedef struct event_s event_t, nua_signal_data_t;
Pekka Pessi's avatar
Pekka Pessi committed
79 80 81

#define       NONE ((void *)-1)

82
typedef struct register_usage nua_registration_t;
83

Pekka Pessi's avatar
Pekka Pessi committed
84 85 86
#define \
  NH_ACTIVE_MEDIA_TAGS(include, soa)					\
  TAG_IF((include) && (soa) && soa_is_audio_active(soa) >= 0,		\
Pekka Pessi's avatar
Pekka Pessi committed
87
	 SOATAG_ACTIVE_AUDIO(soa_is_audio_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
88
  TAG_IF((include) && (soa) && soa_is_video_active(soa) >= 0,		\
Pekka Pessi's avatar
Pekka Pessi committed
89
	 SOATAG_ACTIVE_VIDEO(soa_is_video_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
90
  TAG_IF((include) && (soa) && soa_is_image_active(soa) >= 0,		\
Pekka Pessi's avatar
Pekka Pessi committed
91
	 SOATAG_ACTIVE_IMAGE(soa_is_image_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
92
  TAG_IF((include) && (soa) && soa_is_chat_active(soa) >= 0,		\
Pekka Pessi's avatar
Pekka Pessi committed
93
	 SOATAG_ACTIVE_CHAT(soa_is_chat_active(soa)))
Pekka Pessi's avatar
Pekka Pessi committed
94 95 96 97

#define \
  NH_REMOTE_MEDIA_TAGS(include, soa)					\
  TAG_IF((include) && (soa) && soa_is_remote_audio_active(soa) >= 0,	\
Pekka Pessi's avatar
Pekka Pessi committed
98
	 SOATAG_ACTIVE_AUDIO(soa_is_remote_audio_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
99
  TAG_IF((include) && (soa) && soa_is_remote_video_active(soa) >= 0,	\
Pekka Pessi's avatar
Pekka Pessi committed
100
	 SOATAG_ACTIVE_VIDEO(soa_is_remote_video_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
101
  TAG_IF((include) && (soa) && soa_is_remote_image_active(soa) >= 0,	\
Pekka Pessi's avatar
Pekka Pessi committed
102
	 SOATAG_ACTIVE_IMAGE(soa_is_remote_image_active(soa))),		\
Pekka Pessi's avatar
Pekka Pessi committed
103
  TAG_IF((include) && (soa) && soa_is_remote_chat_active(soa) >= 0,	\
Pekka Pessi's avatar
Pekka Pessi committed
104
	 SOATAG_ACTIVE_CHAT(soa_is_remote_chat_active(soa)))
Pekka Pessi's avatar
Pekka Pessi committed
105

Pekka Pessi's avatar
Pekka Pessi committed
106 107 108 109 110
#if HAVE_NUA_HANDLE_DEBUG

#define nua_handle_ref(nh) nua_handle_ref_by((nh), __func__)
#define nua_handle_unref(nh) nua_handle_unref_by((nh), __func__)

111
su_inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
112
					  char const *by)
Pekka Pessi's avatar
Pekka Pessi committed
113
{
114 115 116 117
  if (nh)
    SU_DEBUG_0(("nua_handle_ref(%p) => "MOD_ZU" by %s\n", nh, 
		su_home_refcount((su_home_t *)nh) + 1,
		by));
Pekka Pessi's avatar
Pekka Pessi committed
118 119 120
  return (nua_handle_t *)su_home_ref((su_home_t *)nh);
}

121
su_inline int nua_handle_unref_by(nua_handle_t *nh, char const *by)
Pekka Pessi's avatar
Pekka Pessi committed
122
{
123 124 125 126 127 128 129 130 131 132
  if (nh) {
    size_t refcount = su_home_refcount((su_home_t *)nh) - 1;
    int freed =  su_home_unref((su_home_t *)nh);
    if (freed) refcount = 0;
    SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n",
		nh, refcount, by));
    return freed;
  }

  return 0; 
Pekka Pessi's avatar
Pekka Pessi committed
133 134 135 136
}

#endif

Pekka Pessi's avatar
Pekka Pessi committed
137
/** @internal @brief NUA handle. 
Pekka Pessi's avatar
Pekka Pessi committed
138 139 140 141 142 143 144 145 146
 *
 */
struct nua_handle_s 
{
  su_home_t       nh_home[1];	/**< Memory home  */
  nua_handle_t   *nh_next;
  nua_handle_t  **nh_prev;

  nua_t        	 *nh_nua;	/**< Pointer to NUA object  */
147 148
  void           *nh_valid;	/**< Cookie */
#define nua_valid_handle_cookie ((void *)(intptr_t)nua_handle)
Pekka Pessi's avatar
Pekka Pessi committed
149 150
  nua_hmagic_t 	 *nh_magic;	/**< Application context */

151 152
  tagi_t         *nh_tags;	/**< Initial tags */
  tagi_t         *nh_ptags;	/**< Initial parameters */
Pekka Pessi's avatar
Pekka Pessi committed
153

154 155
  nua_handle_t   *nh_identity;	/**< Identity */

156 157
  nua_handle_preferences_t *nh_prefs; /**< Preferences */

158
  /* Handle type is determined by special event and flags. */
159
  nua_event_t     nh_special;	/**< Special event */
Pekka Pessi's avatar
Pekka Pessi committed
160 161 162 163
  unsigned        nh_has_invite:1;     /**< Has call */
  unsigned        nh_has_subscribe:1;  /**< Has watcher */
  unsigned        nh_has_notify:1;     /**< Has notifier */
  unsigned        nh_has_register:1;   /**< Has registration */
164 165 166 167

  /* Call status */
  unsigned        nh_active_call:1;
  unsigned        nh_hold_remote:1;
Pekka Pessi's avatar
Pekka Pessi committed
168

169 170 171 172
  unsigned        nh_ref_by_stack:1;	/**< Has stack used the handle? */
  unsigned        nh_ref_by_user:1;	/**< Has user used the handle? */
  unsigned        nh_init:1;	        /**< Handle has been initialized */
  unsigned        nh_used_ptags:1;	/**< Ptags has been used */
173
  unsigned :0;
174

Pekka Pessi's avatar
Pekka Pessi committed
175 176 177 178
  nua_dialog_state_t nh_ds[1];

  auth_client_t  *nh_auth;	/**< Authorization objects */

Pekka Pessi's avatar
Pekka Pessi committed
179
  soa_session_t  *nh_soa;	/**< Media session */
Pekka Pessi's avatar
Pekka Pessi committed
180 181

  struct nua_referral {
182
    nua_handle_t  *ref_handle;	/**< Referring handle */
Pekka Pessi's avatar
Pekka Pessi committed
183 184 185 186 187 188
    sip_event_t   *ref_event;	/**< Event used with NOTIFY */
  } nh_referral[1];

  nea_server_t   *nh_notifier;	/**< SIP notifier */
};

189 190
#define NH_IS_VALID(nh) \
  ((nh) && (nh)->nh_valid == nua_valid_handle_cookie)
Pekka Pessi's avatar
Pekka Pessi committed
191 192 193 194 195 196

#define NH_STATUS(nh) \
  (nh)->nh_status, \
  (nh)->nh_phrase, \
  SIPTAG_WARNING_STR(nh->nh_warning)

197 198
#define NH_IS_DEFAULT(nh) ((nh) == (nh)->nh_nua->nua_handles)

199
su_inline
200 201 202 203 204
int nh_is_special(nua_handle_t *nh)
{
  return nh == NULL || nh->nh_special;
}

205 206
typedef struct nua_event_frame_s nua_event_frame_t;

207
extern char const nua_internal_error[];
Pekka Pessi's avatar
Pekka Pessi committed
208

209
#define NUA_INTERNAL_ERROR 900, nua_internal_error
Pekka Pessi's avatar
Pekka Pessi committed
210
#define NUA_ERROR_AT(file, line) 900, "Internal error at " file ":" #line
Pekka Pessi's avatar
Pekka Pessi committed
211 212 213 214 215 216 217 218

struct nua_s {
  su_home_t            nua_home[1];

  /* API (client) side */
  su_root_t    	      *nua_api_root;
  su_clone_r   	       nua_clone;
  su_task_r            nua_client;
219

Pekka Pessi's avatar
Pekka Pessi committed
220 221 222
  nua_callback_f       nua_callback;
  nua_magic_t         *nua_magic;

223
  nua_event_frame_t   *nua_current;
224
  nua_saved_event_t    nua_signal[1];
Pekka Pessi's avatar
Pekka Pessi committed
225

226 227 228
  /**< Used by stop-and-wait args calls */
  tagi_t const        *nua_args;

229
  /* Engine state flags */
230 231
  sip_time_t           nua_shutdown;

232 233
  unsigned             nua_shutdown_started:1; /**< Shutdown initiated */
  unsigned             nua_shutdown_final:1; /**< Shutdown is complete */
234 235

  unsigned             nua_from_is_set;
236 237
  unsigned :0;
  
238
  /**< Local SIP address. Contents are kept around for ever. */
239 240 241
  sip_from_t           nua_from[1];

  /* ---------------------------------------------------------------------- */
Pekka Pessi's avatar
Pekka Pessi committed
242 243

  /* Protocol (server) side */
244
  su_network_changed_t *nua_nw_changed;
245 246 247

  nua_registration_t *nua_registrations; /**< Active registrations */

248
  /* Constants */
Pekka Pessi's avatar
Pekka Pessi committed
249
  sip_accept_t       *nua_invite_accept; /* What we accept for invite */
250

Pekka Pessi's avatar
Pekka Pessi committed
251 252 253
  su_root_t          *nua_root;
  su_task_r           nua_server;
  nta_agent_t        *nua_nta;
254
  su_timer_t         *nua_timer;
Pekka Pessi's avatar
Pekka Pessi committed
255

256
  /* User-agent parameters */
257
  nua_global_preferences_t nua_prefs[1];
Pekka Pessi's avatar
Pekka Pessi committed
258 259 260 261 262

  nua_handle_t        *nua_handles;
  nua_handle_t       **nua_handles_tail;
};

263
#define nua_dhandle    nua_handles
Pekka Pessi's avatar
Pekka Pessi committed
264 265 266 267 268 269 270

#if HAVE_FUNC
#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __func__))
#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __func__, nh))
#elif HAVE_FUNCTION
#define enter (void)SU_DEBUG_9(("nua: %s: entering\n", __FUNCTION__))
#define nh_enter (void)SU_DEBUG_9(("nua %s(%p): entering\n", __FUNCTION__, nh))
Pekka Pessi's avatar
Pekka Pessi committed
271
#define __func__ __FUNCTION__
Pekka Pessi's avatar
Pekka Pessi committed
272 273 274
#else
#define enter ((void)0)
#define nh_enter ((void)0)
Pekka Pessi's avatar
Pekka Pessi committed
275
#define __func__ "nua"
Pekka Pessi's avatar
Pekka Pessi committed
276 277
#endif

278 279 280 281 282 283 284 285 286 287
su_inline nua_t *nua_stack_ref(nua_t *nua)
{ 
  return (nua_t *)su_home_ref(nua->nua_home);
}

su_inline void nua_stack_unref(nua_t *nua)
{ 
  su_home_unref(nua->nua_home);
}

Pekka Pessi's avatar
Pekka Pessi committed
288
/* Internal prototypes */
289 290 291
int  nua_stack_init(su_root_t *root, nua_t *nua);
void nua_stack_deinit(su_root_t *root, nua_t *nua);

Pekka Pessi's avatar
Pekka Pessi committed
292 293 294
int nua_stack_init_transport(nua_t *nua, tagi_t const *tags);

int nua_stack_init_registrations(nua_t *nua);
295

296 297 298 299
nua_registration_t *nua_registration_by_aor(nua_registration_t const *list,
					    sip_from_t const *aor,
					    url_t const *remote_uri,
					    int only_default);
300

301 302 303
sip_contact_t const *nua_registration_contact(nua_registration_t const *nr);

int nua_registration_process_request(nua_registration_t *nr,
304 305
				     nta_incoming_t *irq,
				     sip_t const *sip);
306

307 308 309 310 311 312 313 314
void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event, 
			   tag_type_t tag, tag_value_t value, ...);

typedef int nua_stack_signal_handler(nua_t *, 
				     nua_handle_t *, 
				     nua_event_t, 
				     tagi_t const *);

315 316 317 318
void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]);
nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]);
void nua_destroy_signal(nua_saved_signal_t saved[1]);

319 320 321 322
nua_stack_signal_handler 
  nua_stack_set_params, nua_stack_get_params,
  nua_stack_register, 
  nua_stack_invite, nua_stack_ack, nua_stack_cancel, 
323 324
  nua_stack_bye, nua_stack_info, nua_stack_update,
  nua_stack_prack,
325 326 327 328 329
  nua_stack_options, nua_stack_publish, nua_stack_message, 
  nua_stack_subscribe, nua_stack_notify, nua_stack_refer,
  nua_stack_method;

#define UA_EVENT1(e, statusphrase) \
330
  nua_stack_event(nua, nh, NULL, e, statusphrase, NULL)
331 332

#define UA_EVENT2(e, status, phrase)			\
333
  nua_stack_event(nua, nh, NULL, e, status, phrase, NULL)
334 335

#define UA_EVENT3(e, status, phrase, tag)			\
336 337 338 339 340
  nua_stack_event(nua, nh, NULL, e, status, phrase, tag, NULL)

int nua_stack_tevent(nua_t *nua, nua_handle_t *nh, msg_t *msg,
		     nua_event_t event, int status, char const *phrase,
		     tag_type_t tag, tag_value_t value, ...);
341 342 343

int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
		    nua_event_t event, int status, char const *phrase,
344
		    tagi_t const *tags);
Pekka Pessi's avatar
Pekka Pessi committed
345

346 347
void nua_move_event(nua_saved_event_t a[1], nua_saved_event_t b[1]);

348
nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, tagi_t *tags);
Pekka Pessi's avatar
Pekka Pessi committed
349

350
nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
351 352 353 354
					nta_incoming_t *irq,
					sip_t const *sip,
					int create_dialog);

355
int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags);
356

357 358 359 360 361 362 363 364 365
enum nh_kind {
  nh_has_nothing,
  nh_has_invite,
  nh_has_subscribe,
  nh_has_notify,
  nh_has_register,
  nh_has_streaming
};

366 367 368 369
int nua_stack_set_handle_special(nua_handle_t *nh,
				 enum nh_kind kind,
				 nua_event_t special);

370 371
int nua_handle_save_tags(nua_handle_t *h, tagi_t *tags);

372 373 374 375
void nh_destroy(nua_t *nua, nua_handle_t *nh);

nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe);

376 377 378 379 380 381 382 383 384
sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *handle, 
					       su_home_t *home,
					       int early_only);

nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
					   sip_replaces_t const *r);

/* ---------------------------------------------------------------------- */

385 386
int nua_stack_set_defaults(nua_handle_t *nh, nua_handle_preferences_t *nhp);

Pekka Pessi's avatar
Pekka Pessi committed
387
int nua_stack_set_from(nua_t *, int initial, tagi_t const *tags);
388 389 390

int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags);

391 392 393 394 395
int nua_stack_process_request(nua_handle_t *nh,
			      nta_leg_t *leg,
			      nta_incoming_t *irq,
			      sip_t const *sip);

396 397
int nua_stack_launch_network_change_detector(nua_t *nua);

398
sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr);
399

400 401 402 403 404 405 406 407 408 409 410
int nua_registration_add_contact_to_request(nua_handle_t *nh,
					    msg_t *msg, 
					    sip_t *sip,
					    int add_contact,
					    int add_service_route);

int nua_registration_add_contact_to_response(nua_handle_t *nh,
					     msg_t *msg,
					     sip_t *sip,
					     sip_record_route_t const *,
					     sip_contact_t const *remote);
411

412 413
/* ---------------------------------------------------------------------- */

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
#ifndef SDP_MIME_TYPE
#define SDP_MIME_TYPE nua_application_sdp
#endif

extern char const nua_application_sdp[];

/* ---------------------------------------------------------------------- */

#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL

/* Private tags */
#define NUTAG_ADD_CONTACT(v) _nutag_add_contact, tag_bool_v(v)
extern tag_typedef_t _nutag_add_contact;

/* ---------------------------------------------------------------------- */

typedef unsigned longlong ull;

#define SET_STATUS(_status, _phrase) status = _status, phrase = _phrase

434 435
#define SET_STATUS2(_status, _phrase) status = _status, phrase = _phrase

436 437 438 439 440 441 442 443 444 445 446
/* This is an "interesting" macro:
 * x is a define expanding to <i>num, str</i>.
 * @a num is assigned to variable status, @a str to variable phrase.
 * Macro SET_STATUS1 expands to two comma-separated expressions that are
 * also usable as function arguments.
 */
#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))

/* ---------------------------------------------------------------------- */
/* Application side prototypes */

447 448 449
int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
	       nua_event_t event, int status, char const *phrase,
	       tag_type_t tag, tag_value_t value, ...);
Pekka Pessi's avatar
Pekka Pessi committed
450

451 452
SOFIA_END_DECLS

Pekka Pessi's avatar
Pekka Pessi committed
453
#endif /* NUA_STACK_H */