Commit 68804fee authored by Pekka Pessi's avatar Pekka Pessi

Updated msg module interfaces.

Added msg_header_free(), msg_header_free_all().
Removed msg_dup_all() and msg_copy_all().

darcs-hash:20051107202157-65a35-ad6eabf68c592e4928b908fd4feea5038548158a.gz
parent 6cf78ac8
......@@ -43,7 +43,7 @@ msg_t *msg_create(msg_mclass_t const *mc, int flags);
void msg_destroy(msg_t *);
msg_t *msg_copy(msg_t *);
msg_t *msg_dup(msg_t *);
msg_t *msg_dup(msg_t const *);
void msg_set_parent(msg_t *kid, msg_t *dad);
......@@ -58,7 +58,7 @@ int msg_extract(msg_t *msg);
unsigned msg_extract_errors(msg_t const *msg);
int msg_is_complete(msg_t const *msg);
int msg_has_error(msg_t const *msg);
msg_header_t **msg_chain_head(msg_t *msg);
msg_header_t **msg_chain_head(msg_t const *msg);
int msg_serialize(msg_t *msg, msg_pub_t *mo);
int msg_prepare(msg_t *msg);
......
......@@ -52,9 +52,9 @@ msg_header_t *msg_header_alloc(su_home_t *, msg_hclass_t *hc, int extra)
__attribute__((__malloc__));
int msg_header_size(msg_header_t const *h);
msg_header_t **msg_header_offset(msg_t *, msg_pub_t *, msg_header_t const *);
msg_header_t **msg_header_offset(msg_t const *, msg_pub_t const *, msg_header_t const *);
msg_header_t **msg_hclass_offset(msg_mclass_t const *,
msg_pub_t *, msg_hclass_t *);
msg_pub_t const *, msg_hclass_t *);
msg_header_t *msg_header_access(msg_pub_t const *pub, msg_hclass_t *hc);
msg_header_t *msg_header_copy_as(su_home_t *home,
......@@ -80,7 +80,7 @@ int msg_object_e(char b[], int size, msg_pub_t const *mo, int flags);
int msg_header_field_e(char b[], int bsiz, msg_header_t const *h, int flags);
int msg_copy_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src);
int msg_dup_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src);
int msg_header_remove(msg_t *msg, msg_pub_t *mo, msg_header_t *h);
int msg_header_remove_all(msg_t *msg, msg_pub_t *mo, msg_header_t *h);
......@@ -130,6 +130,11 @@ msg_header_t *msg_header_vformat(su_home_t *home,
va_list ap)
__attribute__((__malloc__));
void msg_header_free(su_home_t *home, msg_header_t *h);
void msg_header_free_all(su_home_t *home, msg_header_t *h);
msg_payload_t *msg_payload_create(su_home_t *home, void const *data, int len)
__attribute__((__malloc__));
......
......@@ -45,6 +45,7 @@
#include <su.h>
#include "msg_internal.h"
#include "msg.h"
#include "msg_parser.h"
#include "msg_header.h"
......@@ -345,3 +346,161 @@ char *msg_default_dup_one(msg_header_t *h,
return b;
}
/* ====================================================================== */
/* Copying or duplicating all headers in a message */
static int msg_copy_chain(msg_t *msg, msg_t const *copied);
static int msg_dup_or_copy_all(msg_t *msg,
msg_t const *original,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *));
/**Copy a message shallowly.
*
* @relates msg_s
*
* The copied message will share all the strings with the original message.
* The original message is not destroyed until all the copies have been
* destroyed.
*
* @param original message to be copied
*/
msg_t *msg_copy(msg_t *original)
{
if (original) {
msg_t *copy = msg_create(original->m_class, original->m_object->msg_flags);
if (copy) {
if (original->m_chain
? msg_copy_chain(copy, original) < 0
: msg_dup_or_copy_all(copy, original, msg_header_copy_one) < 0) {
msg_destroy(copy), copy = NULL;
}
if (copy)
msg_set_parent(copy, original);
return copy;
}
}
return NULL;
}
static
int msg_copy_chain(msg_t *msg, msg_t const *original)
{
su_home_t *home = msg_home(msg);
msg_pub_t *dst = msg->m_object;
msg_header_t **tail;
msg_header_t *dh;
msg_header_t const *sh;
msg_header_t **hh;
tail = msg->m_tail;
for (sh = original->m_chain; sh; sh = (msg_header_t const *)sh->sh_succ) {
hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
if (!hh)
break;
while (*hh)
hh = &(*hh)->sh_next;
dh = msg_header_copy_one(home, sh);
if (!dh)
break;
dh->sh_prev = tail, *tail = dh, tail = &dh->sh_succ;
*hh = dh;
}
msg->m_tail = tail;
if (sh)
return -1;
return 0;
}
/**Deep copy a message.
*
* @relates msg_s
*
* The duplicated message does not share any (non-const) data with original.
*
* @param original message to be duplicated
*/
msg_t *msg_dup(msg_t const *original)
{
if (original) {
msg_t *dup = msg_create(original->m_class, original->m_object->msg_flags);
if (dup && msg_dup_or_copy_all(dup, original, msg_header_dup_one) < 0) {
msg_destroy(dup), dup = NULL;
}
return dup;
}
return NULL;
}
/** Copy a complete message, not keeping the header chain structure. */
static
int msg_dup_or_copy_all(msg_t *msg,
msg_t const *original,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *))
{
su_home_t *home = msg_home(msg);
msg_pub_t *dst = msg->m_object;
msg_pub_t const *src = original->m_object;
msg_header_t * const *ssh;
msg_header_t * const *end;
msg_header_t const *sh;
msg_header_t **hh;
msg_header_t *h;
assert(copy_one);
end = (msg_header_t**)((char *)src + src->msg_size);
for (ssh = &src->msg_request; ssh < end; ssh++) {
sh = *ssh;
if (!sh)
continue;
hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
if (hh == NULL)
return -1;
for (; sh; sh = sh->sh_next) {
h = copy_one(home, sh);
if (h == NULL)
return -1;
if (*hh) {
/* If there is multiple instances of single headers,
put the extra headers into the list of erroneous headers */
if (msg_is_single(h))
hh = (msg_header_t**)&dst->msg_error;
while (*hh)
hh = &(*hh)->sh_next;
}
*hh = h;
if (msg_is_list(sh))
/* Copy only first list entry */
break;
}
}
return 0;
}
......@@ -26,8 +26,7 @@
#define MSG_INTERNAL_H
/**@ingroup msg
* @IFILE msg_internal.h
/**@IFILE msg_internal.h
* @brief Abstract messages - internal interface
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
......@@ -95,4 +94,31 @@ struct msg_s {
int m_errno; /**< Errno */
};
static inline int msg_is_single(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_single;
}
static inline int msg_is_prepend(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_prepend;
}
static inline int msg_is_append(msg_header_t const *h)
{
return
h->sh_class->hc_kind == msg_kind_append ||
h->sh_class->hc_kind == msg_kind_apndlist;
}
static inline int msg_is_list(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_list;
}
static inline int msg_is_special(msg_header_t const *h)
{
return h->sh_class->hc_hash < 0;
}
#endif /* MSG_INTERNAL_H */
This diff is collapsed.
......@@ -117,36 +117,11 @@ void msg_set_streaming(msg_t *msg, enum msg_streaming_status what)
msg->m_streaming = what != 0;
}
/* ---------------------------------------------------------------------- */
/** Test if header is not in the chain */
#define msg_header_is_removed(h) ((h)->sh_prev == NULL)
static inline int msg_is_single(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_single;
}
static inline int msg_is_prepend(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_prepend;
}
static inline int msg_is_append(msg_header_t const *h)
{
return
h->sh_class->hc_kind == msg_kind_append ||
h->sh_class->hc_kind == msg_kind_apndlist;
}
static inline int msg_is_list(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_list;
}
static inline int msg_is_special(msg_header_t const *h)
{
return h->sh_class->hc_hash < 0;
}
static inline int msg_is_request(msg_header_t const *h)
{
return h->sh_class->hc_hash == msg_request_hash;
......@@ -458,6 +433,7 @@ int msg_recv_iovec(msg_t *msg, msg_iovec_t vec[], int veclen,
#endif
}
/** Obtain a buffer for receiving data */
int msg_recv_buffer(msg_t *msg, void **return_buffer)
{
......@@ -1216,7 +1192,7 @@ int msg_extract_separator(msg_t *msg, msg_pub_t *mo,
return l;
}
static inline msg_header_t **msg_chain_tail(msg_t *msg);
static inline msg_header_t **msg_chain_tail(msg_t const *msg);
/** Extract a message body of @a body_len bytes.
*/
......@@ -1678,18 +1654,18 @@ static msg_header_t **serialize_one(msg_t *msg, msg_header_t *h,
msg_header_t **prev);
/** Return head of the fragment chain */
msg_header_t **msg_chain_head(msg_t *msg)
msg_header_t **msg_chain_head(msg_t const *msg)
{
return msg ? &msg->m_chain : NULL;
return msg ? (msg_header_t **)&msg->m_chain : NULL;
}
static inline msg_header_t **_msg_chain_head(msg_t *msg)
static inline msg_header_t **_msg_chain_head(msg_t const *msg)
{
return msg ? &msg->m_chain : NULL;
return msg ? (msg_header_t **)&msg->m_chain : NULL;
}
/** Return tail of the fragment chain */
static inline msg_header_t **msg_chain_tail(msg_t *msg)
static inline msg_header_t **msg_chain_tail(msg_t const *msg)
{
return msg ? msg->m_tail : NULL;
}
......@@ -2258,7 +2234,7 @@ int msg_header_prepend(msg_t *msg,
/** Find place to insert header of the class @a hc. */
msg_header_t **
msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t *mo, msg_hclass_t *hc)
msg_hclass_offset(msg_mclass_t const *mc, msg_pub_t const *mo, msg_hclass_t *hc)
{
int i;
......@@ -2749,7 +2725,7 @@ int msg_header_replace(msg_t *msg,
replaced->sh_succ = NULL;
if (replaced->sh_data) {
/* Remove cached encoding if it is shared with two header fragments */
/* Remove cached encoding if it is shared with more than one header fragments */
int cleared = 0;
void const *data = (char *)replaced->sh_data + replaced->sh_len;
......@@ -2766,175 +2742,22 @@ int msg_header_replace(msg_t *msg,
return 0;
}
/* ====================================================================== */
/* Copying or duplicating all headers in a message */
static inline int append_copied(msg_t *msg, msg_pub_t *mo, msg_header_t *h);
static
int msg_dup_or_copy_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *));
/**Shallow copy a message.
*
* @relates msg_s
*
* The copied message will share all the strings with its parent message.
* The parent message is not destroyed until all the clones and copies have
* been destroyed.
*
* @param parent parent message
*/
msg_t *msg_copy(msg_t *parent)
{
if (parent) {
msg_t *copy = msg_create(parent->m_class, parent->m_object->msg_flags);
if (copy && msg_copy_all(copy, copy->m_object, parent->m_object) != -1) {
msg_clone(copy, parent);
return copy;
}
msg_destroy(copy);
}
return NULL;
}
/** Copy a complete message shallowly, keeping the header chain structure. */
int msg_copy_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src)
{
su_home_t *home = msg_home(msg);
msg_header_t *dh;
msg_header_t const *sh;
if (src->msg_request)
sh = (msg_header_t const *)src->msg_request;
else
sh = (msg_header_t const *)src->msg_status;
if (sh && sh->sh_prev) {
for (; sh; sh = (msg_header_t const *)sh->sh_succ) {
dh = msg_header_copy_one(home, sh);
if (dh) {
msg_header_t **hh = msg_hclass_offset(msg->m_class, dst, dh->sh_class);
if (!hh)
return -1;
append_parsed(msg, dst, hh, dh, 1);
}
else
return -1;
}
return 0;
}
else {
return msg_dup_or_copy_all(msg, dst, src, msg_header_copy_one);
}
}
/**Deep copy a message.
*
* @relates msg_s
*
* The duplicated message does not share any (non-const) data with parent.
*
* @param parent parent message
*/
msg_t *msg_dup(msg_t *parent)
{
if (parent) {
msg_t *dup = msg_create(parent->m_class, parent->m_object->msg_flags);
if (dup && msg_dup_all(dup, dup->m_object, parent->m_object) != -1)
return dup;
msg_destroy(dup);
}
return NULL;
}
/** Duplicate a complete message, not keeping the header chain structure. */
int msg_dup_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src)
/** Free a header structure */
void msg_header_free(su_home_t *home, msg_header_t *h)
{
return msg_dup_or_copy_all(msg, dst, src, msg_header_dup_one);
su_free(home, h);
}
/** Append a header to the msg_pub_t */
static
int append_copied(msg_t *msg, msg_pub_t *mo, msg_header_t *h)
/** Free a (list of) header structures */
void msg_header_free_all(su_home_t *home, msg_header_t *h)
{
msg_header_t **hh = msg_hclass_offset(msg->m_class, mo, h->sh_class);
msg_header_t *h_next;
if (hh == NULL)
return -1;
if (*hh) {
/* If there is multiple instances of single headers,
put the extra headers into the list of unknown and extra headers */
if (msg_is_single(h))
hh = (msg_header_t**)&mo->msg_error;
while (*hh)
hh = &(*hh)->sh_next;
while (h) {
h_next = h->sh_next;
su_free(home, h);
h = h_next;
}
*hh = h;
return 0;
}
/** Copy a complete message, not keeping the header chain structure. */
static
int msg_dup_or_copy_all(msg_t *msg, msg_pub_t *dst, msg_pub_t const *src,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *))
{
su_home_t *home = msg_home(msg);
msg_header_t const *sh;
msg_header_t * const *ssh;
msg_header_t * const *end;
msg_header_t * const *separator;
msg_header_t * const *payload;
msg_mclass_t const *mc = msg->m_class;
assert(copy_one);
if (src->msg_request)
if (append_copied(msg, dst, copy_one(home, src->msg_request)) < 0)
return -1;
if (src->msg_status)
if (append_copied(msg, dst, copy_one(home, src->msg_status)) < 0)
return -1;
ssh = src->msg_headers;
separator = (msg_header_t **)((char *)src + mc->mc_separator->hr_offset);
payload = (msg_header_t **)((char *)src + mc->mc_payload->hr_offset);
end = (msg_header_t**)((char *)src + src->msg_size);
for (; ssh < end; ssh++) {
if (ssh == separator || ssh == payload)
continue;
for (sh = *ssh; sh; sh = sh->sh_next) {
if (append_copied(msg, dst, copy_one(home, sh)) < 0)
return -1;
if (msg_is_list(sh))
/* Copy only first list entry */
break;
}
}
/* Separator and payload(s) are copied last */
if ((sh = *separator))
if (append_copied(msg, dst, copy_one(home, sh)) < 0)
return -1;
for (sh = *payload; sh; sh = sh->sh_next)
if (append_copied(msg, dst, copy_one(home, sh)) < 0)
return -1;
return 0;
}
......@@ -762,174 +762,6 @@ int msg_hostport_d(char **ss,
return 0;
}
/**Parse @e name-addr.
*
* The function @c msg_name_addr_d() is used to parse @e name-addr
* construction on @b From, @b To, @b Contact, @b Route, and @b Route-Record
* headers. It splits the argument string in four parts:
*
* @par
* @e [display-name] @e addr-spec @e [parameters] @e [comment] @e [ss]
*
* @param home pointer to memory home
* @param ss pointer to pointer to string to be parsed
* @param return_display value-result parameter for @e display-name
* @param return_url value-result parameter for @e addr-spec
* @param return_params value-result paramater for @e parameters
* @param return_comment value-result parameter for @e comment
*
* @note After succesful call to the function @c msg_name_addr_d(), *ss
* contains pointer to the first character not beloging to @e name-addr. If
* that character is a separator, the last parameter may not be NUL
* terminated. So, after examining value of @a **ss, the calling function
* @b MUST set it to NUL.
*
* @return
* The function @c msg_name_addr_d() returns 0 if successful, and -1 upon an
* error.
*/
int msg_name_addr_d(su_home_t *home,
char **ss,
char const **return_display,
url_t *return_url,
msg_param_t const **return_params,
char const **return_comment)
{
char c, *s = *ss;
char *display = NULL, *addr_spec = NULL;
int n;
if (return_display && *s == '"') {
/* Quoted string */
if (msg_quoted_d(&s, &display) == -1)
return -1;
/* Now, we should have a '<' in s[0] */
if (s[0] != '<')
return -1;
s++[0] = '\0'; /* NUL terminate quoted string... */
n = strcspn(s, ">");
addr_spec = s; s += n;
if (*s) *s++ = '\0'; else return -1;
}
else {
if (return_display)
n = span_token_lws(s);
else
n = 0;
if (s[n] == '<') {
/* OK, we got a display name */
display = s; s += n + 1;
/* NUL terminate display name */
while (n > 0 && IS_LWS(display[n - 1]))
n--;
if (n > 0)
display[n] = '\0';
else
display = "";
n = strcspn(s, ">");
addr_spec = s; s += n; if (*s) *s++ = '\0'; else return -1;
}
else {
/* No display name */
addr_spec = s;
n = strcspn(s, " ,;?"); /* we DO NOT accept ? in URL */
s += n;
if (IS_LWS(*s))
*s++ = '\0';
}
}
skip_lws(&s);
*ss = s;
if (return_display)
*return_display = display;
/* Now, url may still not be NUL terminated, e.g., if
* it is like "Route: url:foo,sip:bar,sip:zunk"
*/
c = *s; *s = '\0';
if (url_d(return_url, addr_spec) == -1)
return -1;
*s = c;
if (**ss == ';' && return_params)
if (msg_params_d(home, ss, return_params) == -1)
return -1;
if (**ss == '(' && return_comment)
if (msg_comment_d(ss, return_comment) == -1)
return -1;
return 0;
}
/**Encode @e name-addr and parameter list.
*
* Encodes @e name-addr headers, like From, To, Call-Info, Error-Info,
* Route, and Record-Route.
*
* @param b buffer to store the encoding result
* @param bsiz size of the buffer @a b
* @param flags encoding flags
* @param display display name encoded before the @a url (may be NULL)
* @param brackets if true, use always brackets around @a url
* @param url pointer to URL structure
* @param params pointer to parameter list (may be NULL)
* @param comment comment string encoded after others (may be NULL)
*
* @return
* Returns number of characters in encoding result, excluding the
* final NUL.
*
* @note
* The encoding result may be incomplete if the buffer size is not large
* enough to store the whole encoding result.
*/
int msg_name_addr_e(char b[], int bsiz,
int flags,
char const *display,
int brackets, url_t const url[],
msg_param_t const params[],
char const *comment)
{
int const compact = MSG_IS_COMPACT(flags);
char const *u;
char *b0 = b, *end = b + bsiz;
brackets = brackets || display ||
(url && (url->url_params ||
url->url_headers ||
((u = url->url_user) && u[strcspn(u, ";,?")]) ||
((u = url->url_password) && u[strcspn(u, ",")])));
if (display && display[0]) {
MSG_STRING_E(b, end, display);
if (!compact) MSG_CHAR_E(b, end, ' ');
}
if (url) {
if (brackets) MSG_CHAR_E(b, end, '<');
URL_E(b, end, url);
if (brackets) MSG_CHAR_E(b, end, '>');
}
MSG_PARAMS_E(b, end, params, flags);
if (comment) {
if (!compact) MSG_CHAR_E(b, end, ' ');
MSG_CHAR_E(b, end, '(');
MSG_STRING_E(b, end, comment);
MSG_CHAR_E(b, end, ')');
}
MSG_TERM_E(b, end);
return b - b0;
}
/** Find a parameter from a parameter list.