msg.c 9.75 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3 4 5 6 7
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * 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
 *
 */

Pekka Pessi's avatar
Pekka Pessi committed
25
/**@internal @file msg.c Message object implementation.
Pekka Pessi's avatar
Pekka Pessi committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 *
 * @date Created: Thu Jun  8 19:28:55 2000 ppessi
 */

#include "config.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
Pekka Pessi's avatar
Pekka Pessi committed
40 41
#include <errno.h>

Pekka Pessi's avatar
Pekka Pessi committed
42 43
#include <assert.h>

44 45
#include <sofia-sip/su_alloc.h>		/* XXX */
#include <sofia-sip/su.h>
Pekka Pessi's avatar
Pekka Pessi committed
46 47

#include "msg_internal.h"
48 49
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_mclass.h"
Pekka Pessi's avatar
Pekka Pessi committed
50 51 52 53

/**
 * Create a message.
 *
54
 * @relatesalso msg_s
Pekka Pessi's avatar
Pekka Pessi committed
55 56 57 58 59 60
 *
 * @param mc    message class
 * @param flags message control flags
 */
msg_t *msg_create(msg_mclass_t const *mc, int flags)
{
Pekka Pessi's avatar
Pekka Pessi committed
61
  msg_t *msg = su_home_new(sizeof(*msg) + mc->mc_msize);
Pekka Pessi's avatar
Pekka Pessi committed
62 63 64 65

  if (msg) {
    if ((flags & MSG_FLG_THRDSAFE) &&
	su_home_threadsafe(msg->m_home) < 0) {
Pekka Pessi's avatar
Pekka Pessi committed
66
      su_home_unref(msg->m_home);
Pekka Pessi's avatar
Pekka Pessi committed
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
      return NULL;
    }

    msg->m_refs++;
    msg->m_tail = &msg->m_chain;
    msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
    msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
    msg->m_maxsize = 0;

    flags &= MSG_FLG_USERMASK;

    msg->m_class = mc;
    msg->m_oflags = flags;
    msg->m_object = (void *)(msg + 1);
    msg->m_object->msg_size = mc->mc_msize;
    msg->m_object->msg_flags = mc->mc_flags | flags;
    msg->m_object->msg_common->h_class = (void *)mc;
  }

  return msg;
}

/**Increment a message reference count.
 *
91
 * @relatesalso msg_s
Pekka Pessi's avatar
Pekka Pessi committed
92
 *
93
 * Creates a reference to a message.  The
Pekka Pessi's avatar
Pekka Pessi committed
94 95 96 97 98 99
 * referenced message is not freed until all the references have been
 * destroyed.
 *
 * @param msg   message of which a reference is created
 * 
 * @return
100
 * A pointer to a message.
Pekka Pessi's avatar
Pekka Pessi committed
101 102 103 104 105 106 107 108 109 110 111
 */
msg_t *msg_ref_create(msg_t *msg)
{
  if (msg) {
    su_home_mutex_lock(msg->m_home);
    msg->m_refs++;
    su_home_mutex_unlock(msg->m_home);
  }
  return msg;
}

112 113
/**Set a message parent.
 *
114
 * @relatesalso msg_s
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
 *
 * Set a parent for a message. The parent message is not destroyed until all
 * its kids have been destroyed - each kid keeps a reference to its parent
 * message.
 *
 * @param kid  child message
 * @param dad  parent message
 */
void msg_set_parent(msg_t *kid, msg_t *dad)
{
  if (kid) {
    msg_t *step_dad = kid->m_parent;

    if (dad && step_dad && step_dad != dad)
      msg_ref_destroy(step_dad);

    kid->m_parent = msg_ref_create(dad);
  }
}

Pekka Pessi's avatar
Pekka Pessi committed
135 136
/** Destroy a reference to a message.
 *
137
 * @relatesalso msg_s
138 139 140 141
 *
 * @param ref pointer to msg object
 * 
 * @deprecated Use msg_destroy() instead.
Pekka Pessi's avatar
Pekka Pessi committed
142 143 144 145 146 147 148 149
 */
void msg_ref_destroy(msg_t *ref)
{
  msg_destroy(ref);
}

/**Deinitialize and free a message.
 *
150
 * @relatesalso msg_s
Pekka Pessi's avatar
Pekka Pessi committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
 *
 * @param msg  message to be destroyed
 */
void msg_destroy(msg_t *msg)
{
  msg_t *parent;
  
  for (; msg; msg = parent) {
    int refs;
    su_home_mutex_lock(msg->m_home);
    parent = msg->m_parent;
    if (msg->m_refs)
      msg->m_refs--;
    refs = msg->m_refs;
    su_home_mutex_unlock(msg->m_home);
    if (refs)
      break;
    su_home_zap(msg->m_home);
  }
}

/* Message object routines */

/**Retrieve public message structure.
 *
176
 * Get a pointer to the public message structure.
Pekka Pessi's avatar
Pekka Pessi committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
 * 
 * @param msg pointer to msg object
 * 
 * @returns
 * A pointer to the public message structure, or NULL if none.
 */
msg_pub_t *msg_object(msg_t const *msg)
{
  if (msg)
    return msg->m_object;
  else
    return NULL;
}

/**Retrieve public message structure of given type.
 *
193
 * @relatesalso msg_s
Pekka Pessi's avatar
Pekka Pessi committed
194
 *
195
 * Get a pointer to the public message structure of the
Pekka Pessi's avatar
Pekka Pessi committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
 * given protocol.
 * 
 * @param msg pointer to msg object
 * @param tag tag of public message structure
 * 
 * @returns
 * A pointer to the public message structure, or NULL if there is none or
 * the message is not for desired protocol.
 */
msg_pub_t *msg_public(msg_t const *msg, void *tag)
{
  if (msg && msg->m_class->mc_tag == tag)
    return msg->m_object;
  else
    return NULL;
}

/**Retrieve message class.
 *
215
 * @relatesalso msg_s
Pekka Pessi's avatar
Pekka Pessi committed
216
 *
217
 * Get a pointer to the message class object
Pekka Pessi's avatar
Pekka Pessi committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
 * (factory object for the message).
 * 
 * @param msg pointer to msg object
 * 
 * @returns
 * A pointer to the message class, or NULL if none.
 */
msg_mclass_t const *msg_mclass(msg_t const *msg)
{
  if (msg)
    return msg->m_class;
  else
    return NULL;
}

/* Address management */

235 236
/** Zero the message address.
 *
237
 * @relatesalso msg_s
238 239 240 241 242
 *
 * Zero the address and addressinfo structures associated with the message.
 *
 * @sa msg_addrinfo(), msg_set_address(), msg_get_address(), msg_addr_copy().
 */ 
Pekka Pessi's avatar
Pekka Pessi committed
243 244 245 246 247 248 249 250 251
void msg_addr_zero(msg_t *msg)
{
  memset(&msg->m_addr, 0, sizeof(&msg->m_addr));
  memset(&msg->m_addrinfo, 0, sizeof(&msg->m_addrinfo));

  msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
  msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
}

252
/** Get pointer to socket address structure. 
253
 *
254
 * @relatesalso msg_s
255 256 257
 *
 * @deprecated Use msg_get_address() or msg_set_address() instead.
 */
Pekka Pessi's avatar
Pekka Pessi committed
258 259 260 261 262
su_sockaddr_t *msg_addr(msg_t *msg)
{
  return msg ? msg->m_addr : 0;
}

263 264
/** Get message address.
 *
265
 * @relatesalso msg_s
266 267 268 269 270 271 272 273 274 275 276
 *
 * Copy the socket address associated with the message to the supplied
 * socket address struture.
 *
 * @param msg pointer to msg object
 * @param su pointer to socket address structure
 * @param return_len return parameter value for length 
 *                    of socket address structure
 *
 * @sa msg_addrinfo(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
 */
277 278 279
int msg_get_address(msg_t *msg, su_sockaddr_t *su, socklen_t *return_len)
{
  if (msg && return_len && *return_len >= msg->m_addrinfo.ai_addrlen) {
280
    *return_len = (socklen_t)msg->m_addrinfo.ai_addrlen;
281
    if (su)
282
      memcpy(su, msg->m_addr, msg->m_addrinfo.ai_addrlen);
283 284 285 286 287 288 289
    return 0;
  }
  if (msg)
    msg->m_errno = EFAULT;
  return -1;
}

290 291
/** Set message address. 
 *
292
 * @relatesalso msg_s
293 294 295 296 297 298 299 300 301 302
 *
 * Copy the supplied socket address to the socket address structure
 * associated with the message.
 * 
 * @param msg pointer to msg object
 * @param su pointer to socket address structure
 * @param sulen length of socket address structure
 *
 * @sa msg_addrinfo(), msg_get_address(), msg_addr_zero(), msg_addr_copy().
 */
303 304 305 306 307 308 309 310 311 312 313 314
int msg_set_address(msg_t *msg, su_sockaddr_t const *su, socklen_t sulen)
{
  if (sulen < (sizeof msg->m_addr) && msg && su) {
    memcpy(msg->m_addr, su, msg->m_addrinfo.ai_addrlen = sulen);
    msg->m_addrinfo.ai_family = su->su_family;
    return 0;
  }
  if (msg)
    msg->m_errno = EFAULT;
  return -1;
}

315 316
/** Get addrinfo structure.
 *
317
 * @relatesalso msg_s
318 319 320 321 322 323 324 325 326 327
 *
 * Get pointer to the addrinfo structure associated with the message.
 *
 * @param msg pointer to msg object
 *
 * @retval pointer to addrinfo structure
 * @retval NULL if msg is NULL
 *
 * @sa msg_get_address(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
 */
Pekka Pessi's avatar
Pekka Pessi committed
328 329 330 331 332 333
su_addrinfo_t *msg_addrinfo(msg_t *msg)
{
  return msg ? &msg->m_addrinfo : 0;
}

/**Copy message address.
334
 *
335
 * @relatesalso msg_s
336 337 338 339 340 341 342 343
 *
 * Copy the addrinfo and socket address structures from @a src to the @a dst
 * message object.
 *
 * @param dst pointer to destination message object 
 * @param src pointer to source message object
 *
 * @sa msg_addrinfo(), msg_get_address(), msg_set_address(), msg_addr_zero().
Pekka Pessi's avatar
Pekka Pessi committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357
 */
void msg_addr_copy(msg_t *dst, msg_t const *src)
{
  dst->m_addrinfo = src->m_addrinfo;
  dst->m_addrinfo.ai_next = NULL;
  dst->m_addrinfo.ai_canonname = NULL;
  memcpy(dst->m_addrinfo.ai_addr = &dst->m_addr->su_sa, 
	 src->m_addr, src->m_addrinfo.ai_addrlen);
  if (dst->m_addrinfo.ai_addrlen < sizeof(dst->m_addr))
    memset((char *)dst->m_addr + dst->m_addrinfo.ai_addrlen, 0, 
	   sizeof(dst->m_addr) - dst->m_addrinfo.ai_addrlen);
}


358 359
/** Get error classification flags.
 *
360
 * @relatesalso msg_s
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
 *
 * If the message parser fails to parse certain headers in the message, it
 * sets the corresponding extract error flags. The flags corresponding to
 * each header are stored in the message parser (msg_mclass_t) structure. 
 * They are set when the header is added to the parser table. 
 * 
 * The SIP flags are defined in <sofia-sip/sip_headers.h>. For well-known
 * SIP headers, the flags for each header are listed in a separate text file
 * (sip_bad_mask) read by msg_parser.awk.
 *
 * The flags can be used directly by NTA (the mask triggering 400 response
 * is set with NTATAG_BAD_REQ_MASK(), the mask triggering response messages
 * to be dropped is set with NTATAG_BAD_RESP_MASK()). Alternatively the
 * application can check them based on the method or required SIP features.
 *
 * @sa msg_mclass_insert_with_mask(), NTATAG_BAD_REQ_MASK(),
 * NTATAG_BAD_RESP_MASK().
 */
Pekka Pessi's avatar
Pekka Pessi committed
379 380 381 382 383 384
unsigned msg_extract_errors(msg_t const *msg)
{
  return msg ? msg->m_extract_err : (unsigned)-1;
}


385 386
/** Get error number associated with message.
 *
387
 * @relatesalso msg_s
388 389 390 391
 *
 * @param msg pointer to msg object
 *
 */
Pekka Pessi's avatar
Pekka Pessi committed
392 393 394 395 396
int msg_errno(msg_t const *msg)
{
  return msg ? msg->m_errno : EINVAL;
}

397 398
/** Set error number associated with message.
 *
399
 * @relatesalso msg_s
400 401 402 403 404
 *
 * @param msg pointer to msg object
 * @param err error value (as defined in <sofia-sip/su_errno.h>).
 *
 */
Pekka Pessi's avatar
Pekka Pessi committed
405 406 407 408 409
void msg_set_errno(msg_t *msg, int err)
{
  if (msg)
    msg->m_errno = err;
}