From 0b9e388f7f10dac01d5134ed6c1b24695810874e Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 11 Nov 2005 19:01:31 +0000 Subject: First clean compile of pjsip git-svn-id: http://svn.pjsip.org/repos/pjproject/main@43 74dad513-b988-da41-8d7b-12977e46ad98 --- RELNOTES.txt | 17 + pjlib-util/include/pjlib-util/scanner.h | 235 +++-- pjlib-util/src/pjlib-util/scanner.c | 121 ++- pjlib/build/pjlib.dsw | 12 +- pjlib/include/pj++/file.hpp | 342 +++---- pjlib/include/pj++/hash.hpp | 276 +++--- pjlib/include/pj++/list.hpp | 619 ++++++------ pjlib/include/pj++/lock.hpp | 263 +++--- pjlib/include/pj++/os.hpp | 1573 ++++++++++++++++--------------- pjlib/include/pj++/pool.hpp | 505 +++++----- pjlib/include/pj++/proactor.hpp | 1000 ++++++++++---------- pjlib/include/pj++/scanner.hpp | 344 +++---- pjlib/include/pj++/sock.hpp | 851 ++++++++--------- pjlib/include/pj++/string.hpp | 815 ++++++++-------- pjlib/include/pj++/timer.hpp | 359 +++---- pjlib/include/pj++/tree.hpp | 222 ++--- pjlib/include/pj++/types.hpp | 286 +++--- pjlib/include/pj/compat/string.h | 9 + pjlib/include/pj/config.h | 9 +- pjlib/include/pj/errno.h | 5 + pjlib/include/pj/except.h | 1 + pjlib/include/pj/hash.h | 15 + pjlib/include/pj/ioqueue.h | 14 +- pjlib/include/pj/string.h | 3 + pjlib/src/pj/errno.c | 3 +- pjlib/src/pj/hash.c | 14 + pjlib/src/pj/ioqueue_common_abs.c | 8 + pjlib/src/pj/ioqueue_winnt.c | 5 + pjsip/build/TODO.txt | 21 - pjsip/build/pjsip_core.dsp | 66 +- pjsip/build/pjsip_ua.dsp | 10 +- pjsip/build/tounix | 5 - pjsip/include/pjsip/print_util.h | 99 ++ pjsip/include/pjsip/sip_auth.h | 5 +- pjsip/include/pjsip/sip_auth_msg.h | 5 +- pjsip/include/pjsip/sip_auth_parser.h | 7 +- pjsip/include/pjsip/sip_config.h | 2 - pjsip/include/pjsip/sip_endpoint.h | 76 +- pjsip/include/pjsip/sip_errno.h | 86 ++ pjsip/include/pjsip/sip_event.h | 241 ++++- pjsip/include/pjsip/sip_misc.h | 58 +- pjsip/include/pjsip/sip_module.h | 1 - pjsip/include/pjsip/sip_msg.h | 35 +- pjsip/include/pjsip/sip_parser.h | 52 +- pjsip/include/pjsip/sip_private.h | 11 +- pjsip/include/pjsip/sip_resolve.h | 1 - pjsip/include/pjsip/sip_transaction.h | 175 ++-- pjsip/include/pjsip/sip_transport.h | 55 +- pjsip/include/pjsip/sip_types.h | 27 +- pjsip/include/pjsip/sip_uri.h | 1 - pjsip/include/pjsip_core.h | 1 - pjsip/src/pjsip/print.h | 100 -- pjsip/src/pjsip/sip_auth.c | 15 +- pjsip/src/pjsip/sip_auth_msg.c | 18 +- pjsip/src/pjsip/sip_auth_parser.c | 137 +-- pjsip/src/pjsip/sip_endpoint.c | 256 ++--- pjsip/src/pjsip/sip_misc.c | 184 ++-- pjsip/src/pjsip/sip_msg.c | 5 +- pjsip/src/pjsip/sip_parser.c | 977 +++++++++++-------- pjsip/src/pjsip/sip_resolve.c | 18 +- pjsip/src/pjsip/sip_transaction.c | 708 ++++++++------ pjsip/src/pjsip/sip_transport.c | 679 +++++++------ pjsip/src/pjsip/sip_uri.c | 10 +- pjsip/src/pjsua/getopt.c | 4 +- pjsip/src/pjsua/main.c | 8 +- pjsip/src/pjsua/misc.c | 4 +- 66 files changed, 6517 insertions(+), 5572 deletions(-) delete mode 100644 pjsip/build/TODO.txt delete mode 100644 pjsip/build/tounix create mode 100644 pjsip/include/pjsip/print_util.h create mode 100644 pjsip/include/pjsip/sip_errno.h delete mode 100644 pjsip/src/pjsip/print.h diff --git a/RELNOTES.txt b/RELNOTES.txt index 1e884e38..e2baeb97 100644 --- a/RELNOTES.txt +++ b/RELNOTES.txt @@ -1,3 +1,20 @@ +Version 0.3 +PJLIB + - Correct error reporting in the whole library. No more vague -1 errors! + - New super portable socket abstraction. + - Other headers were made super portable too. + - Ioqueue supports multiple pending operations in a single socket! + - No more floating point. + - Ported to new platforms: + - i386/linux kernel (!) + - Sparc/Solaris + - Alpha/Linux +PJSIP + - Correct error reporting in the whole library. No more -1 errors! + - Rewrote event, now much more readable. + - Per object tracing. + + Version 0.2.9 - 2005/06/19 Core: - Moved authentication stuff to core. diff --git a/pjlib-util/include/pjlib-util/scanner.h b/pjlib-util/include/pjlib-util/scanner.h index f1b0b133..711eeed7 100644 --- a/pjlib-util/include/pjlib-util/scanner.h +++ b/pjlib-util/include/pjlib-util/scanner.h @@ -1,9 +1,7 @@ /* $Id$ - * */ - -#ifndef __PJ_PARSER_H__ -#define __PJ_PARSER_H__ +#ifndef __PJ_SCANNER_H__ +#define __PJ_SCANNER_H__ /** * @file scanner.h @@ -18,115 +16,175 @@ PJ_BEGIN_DECL * @defgroup PJ_SCAN Text Scanning * @ingroup PJ_MISC * @brief - * Text scanning utility. - */ - -/** - * @defgroup PJ_CHARSPEC Character Filter Specification - * @ingroup PJ_SCAN - * @brief - * The type pj_char_spec is a specification of character set used in - * scanner. Application can define multiple character specs, such as to - * scan alpha numerics, numbers, tokens, etc. + * Text scanning utility. + * * @{ */ +/** + * This describes the type of individual character specification in + * #pj_cis_buf_t. Basicly the number of bits here + */ +#ifndef PJ_CIS_ELEM_TYPE +# define PJ_CIS_ELEM_TYPE pj_uint32_t +#endif + /** * This describes the type of individual character specification in - * #pj_char_spec. + * #pj_cis_buf_t. */ -typedef pj_uint8_t pj_char_spec_element_t; +typedef PJ_CIS_ELEM_TYPE pj_cis_elem_t; + +/** + * Maximum number of input specification in a buffer. + * Effectively this means the number of bits in pj_cis_elem_t. + */ +#define PJ_CIS_MAX_INDEX (sizeof(pj_cis_elem_t) << 3) /** - * The character specification is implemented as array of boolean flags. Each - * flag indicates the membership of the character in the spec. If the flag - * at one position is non-zero, then the character at that position belongs - * to the specification, and vice versa. - */ -typedef pj_char_spec_element_t pj_char_spec[256]; -// Note: it's got to be 256 (not 128) to cater for extended character in input. + * The scanner input specification buffer. + */ +typedef struct pj_cis_buf_t +{ + pj_cis_elem_t cis_buf[256]; /**< Must be 256 (not 128)! */ + pj_cis_elem_t use_mask; /**< To keep used indexes. */ +} pj_cis_buf_t; + +/** + * Character input specification. + */ +typedef struct pj_cis_t +{ + pj_cis_elem_t *cis_buf; /**< Pointer to buffer. */ + int cis_id; /**< Id. */ +} pj_cis_t; /** - * Initialize character spec. - * @param cs the scanner character specification. - */ -PJ_DECL(void) pj_cs_init( pj_char_spec cs); + * Initialize scanner input specification buffer. + * + * @param cs_buf The scanner character specification. + */ +PJ_DECL(void) pj_cis_buf_init(pj_cis_buf_t *cs_buf); + +/** + * Create a new input specification. + * + * @param cs_buf Specification buffer. + * @param cis Character input specification to be initialized. + * + * @return PJ_SUCCESS if new specification has been successfully + * created, or PJ_ETOOMANY if there are already too many + * specifications in the buffer. + */ +PJ_DECL(pj_status_t) pj_cis_init(pj_cis_buf_t *cs_buf, pj_cis_t *cis); + +/** + * Create a new input specification based on an existing specification. + * + * @param new_cis The new specification to be initialized. + * @param existing The existing specification, from which the input + * bitmask will be copied to the new specification. + * + * @return PJ_SUCCESS if new specification has been successfully + * created, or PJ_ETOOMANY if there are already too many + * specifications in the buffer. + */ +PJ_DECL(pj_status_t) pj_cis_dup(pj_cis_t *new_cis, pj_cis_t *existing); /** - * Set the membership of the specified character to TRUE. - * @param cs the scanner character specification. - * @param c the character. - */ -PJ_DECL(void) pj_cs_set( pj_char_spec cs, int c); + * Set the membership of the specified character. + * Note that this is a macro, and arguments may be evaluated more than once. + * + * @param cis Pointer to character input specification. + * @param c The character. + */ +#define PJ_CIS_SET(cis,c) ((cis)->cis_buf[(c)] |= (1 << (cis)->cis_id)) + +/** + * Remove the membership of the specified character. + * Note that this is a macro, and arguments may be evaluated more than once. + * + * @param cis Pointer to character input specification. + * @param c The character to be removed from the membership. + */ +#define PJ_CIS_CLR(cis,c) ((cis)->cis_buf[c] &= ~(1 << (cis)->cis_id)) + +/** + * Check the membership of the specified character. + * Note that this is a macro, and arguments may be evaluated more than once. + * + * @param cis Pointer to character input specification. + * @param c The character. + */ +#define PJ_CIS_ISSET(cis,c) ((cis)->cis_buf[c] & (1 << (cis)->cis_id)) /** * Add the characters in the specified range '[cstart, cend)' to the - * specification (the last character itself ('cend') is not added). - * @param cs the scanner character specification. - * @param cstart the first character in the range. - * @param cend the next character after the last character in the range. + * specification (the last character itself ('cend') is not added). + * + * @param cis The scanner character specification. + * @param cstart The first character in the range. + * @param cend The next character after the last character in the range. */ -PJ_DECL(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend); +PJ_DECL(void) pj_cis_add_range( pj_cis_t *cis, int cstart, int cend); /** - * Add alphabetic characters to the specification. - * @param cs the scanner character specification. + * Add alphabetic characters to the specification. + * + * @param cis The scanner character specification. */ -PJ_DECL(void) pj_cs_add_alpha( pj_char_spec cs); +PJ_DECL(void) pj_cis_add_alpha( pj_cis_t *cis); /** - * Add numeric characters to the specification. - * @param cs the scanner character specification. + * Add numeric characters to the specification. + * + * @param cis The scanner character specification. */ -PJ_DECL(void) pj_cs_add_num( pj_char_spec cs); +PJ_DECL(void) pj_cis_add_num( pj_cis_t *cis); /** - * Add the characters in the string to the specification. - * @param cs the scanner character specification. - * @param str the string. + * Add the characters in the string to the specification. + * + * @param cis The scanner character specification. + * @param str The string. */ -PJ_DECL(void) pj_cs_add_str( pj_char_spec cs, const char *str); +PJ_DECL(void) pj_cis_add_str( pj_cis_t *cis, const char *str); /** - * Delete characters in the specified range from the specification. - * @param cs the scanner character specification. - * @param cstart the first character in the range. - * @param cend the next character after the last character in the range. + * Delete characters in the specified range from the specification. + * + * @param cis The scanner character specification. + * @param cstart The first character in the range. + * @param cend The next character after the last character in the range. */ -PJ_DECL(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend); +PJ_DECL(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend); /** - * Delete characters in the specified string from the specification. - * @param cs the scanner character specification. - * @param str the string. + * Delete characters in the specified string from the specification. + * + * @param cis The scanner character specification. + * @param str The string. */ -PJ_DECL(void) pj_cs_del_str( pj_char_spec cs, const char *str); +PJ_DECL(void) pj_cis_del_str( pj_cis_t *cis, const char *str); /** - * Invert specification. - * @param cs the scanner character specification. + * Invert specification. + * + * @param cis The scanner character specification. */ -PJ_DECL(void) pj_cs_invert( pj_char_spec cs ); +PJ_DECL(void) pj_cis_invert( pj_cis_t *cis ); /** - * Check whether the specified character belongs to the specification. - * @param cs the scanner character specification. - * @param c the character to check for matching. + * Check whether the specified character belongs to the specification. + * + * @param cis The scanner character specification. + * @param c The character to check for matching. */ -PJ_INLINE(int) pj_cs_match( const pj_char_spec cs, int c ) +PJ_INLINE(int) pj_cis_match( const pj_cis_t *cis, int c ) { - return cs[c]; + return PJ_CIS_ISSET(cis, c); } -/** - * @} - */ - -/** - * @defgroup PJ_SCANNER Text Scanner - * @ingroup PJ_SCAN - * @{ - */ /** * Flags for scanner. @@ -155,8 +213,9 @@ struct pj_scanner; /** * The callback function type to be called by the scanner when it encounters - * syntax error. - * @param scanner The scanner instance that calls the callback . + * syntax error. + * + * @param scanner The scanner instance that calls the callback . */ typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner); @@ -244,7 +303,7 @@ PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner) * no more characters. */ PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); + const pj_cis_t *spec, pj_str_t *out); /** @@ -261,7 +320,7 @@ PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, * no more characters. */ PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, - pj_size_t len, pj_str_t *out); + pj_size_t len, pj_str_t *out); /** @@ -277,8 +336,8 @@ PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, * @return the character right after the peek-ed position. */ PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_char_spec spec, - pj_str_t *out); + const pj_cis_t *spec, + pj_str_t *out); /** @@ -293,7 +352,7 @@ PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, * @param out String to store the result. */ PJ_DECL(void) pj_scan_get( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); + const pj_cis_t *spec, pj_str_t *out); /** @@ -317,7 +376,7 @@ PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner, * @param out String to store the result. */ PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, - unsigned N, pj_str_t *out); + unsigned N, pj_str_t *out); /** @@ -325,7 +384,7 @@ PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, * * @param scanner The scanner. * - * @return (unknown) + * @return The character. */ PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner ); @@ -348,7 +407,7 @@ PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner ); * @param out String to store the result. */ PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out); + const pj_cis_t *spec, pj_str_t *out); /** @@ -360,7 +419,7 @@ PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, * @param out String to store the result. */ PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, - int until_char, pj_str_t *out); + int until_char, pj_str_t *out); /** @@ -372,7 +431,7 @@ PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, * @param out String to store the result. */ PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, - const char *until_spec, pj_str_t *out); + const char *until_spec, pj_str_t *out); /** * Advance the scanner N characters, and skip whitespace @@ -384,7 +443,7 @@ PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, * after skipping the characters. */ PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner, - unsigned N, pj_bool_t skip); + unsigned N, pj_bool_t skip); /** @@ -445,10 +504,6 @@ PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, * @} */ -#if PJ_FUNCTIONS_ARE_INLINED -# include "scanner_i.h" -#endif - PJ_END_DECL diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c index 65e3f351..0e753dfb 100644 --- a/pjlib-util/src/pjlib-util/scanner.c +++ b/pjlib-util/src/pjlib-util/scanner.c @@ -4,6 +4,7 @@ #include #include #include +#include #define PJ_SCAN_IS_SPACE(c) ((c)==' ' || (c)=='\t') #define PJ_SCAN_IS_NEWLINE(c) ((c)=='\r' || (c)=='\n') @@ -15,67 +16,99 @@ static void pj_scan_syntax_err(pj_scanner *scanner) (*scanner->callback)(scanner); } -PJ_DEF(void) pj_cs_init( pj_char_spec cs) +PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf) { - PJ_CHECK_STACK(); - memset(cs, 0, sizeof(cs)); + pj_memset(cis_buf->cis_buf, 0, sizeof(cis_buf->cis_buf)); + cis_buf->use_mask = 0; } - -PJ_DEF(void) pj_cs_set( pj_char_spec cs, int c) + +PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis) +{ + unsigned i; + + cis->cis_buf = cis_buf->cis_buf; + + for (i=0; iuse_mask & (1 << i)) == 0) { + cis->cis_index = i; + return PJ_SUCCESS; + } + } + + cis->cis_index = PJ_CIS_MAX_INDEX; + return PJ_ETOOMANY; +} + +PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing) +{ + pj_status_t status; + unsigned i; + + status = pj_cis_init(existing->cis_buf, new_cis); + if (status != PJ_SUCCESS) + return status; + + for (i=0; i<256; ++i) { + if (PJ_CIS_ISSET(existing, i)) + PJ_CIS_SET(new_cis, i); + else + PJ_CIS_CLR(new_cis, i); + } + + return PJ_SUCCESS; +} + +PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend) { - PJ_CHECK_STACK(); - cs[c] = 1; -} - -PJ_DEF(void) pj_cs_add_range( pj_char_spec cs, int cstart, int cend) -{ - PJ_CHECK_STACK(); - while (cstart != cend) - cs[cstart++] = 1; + while (cstart != cend) { + PJ_CIS_SET(cis, cstart); + ++cstart; + } } -PJ_DEF(void) pj_cs_add_alpha( pj_char_spec cs) +PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis) { - pj_cs_add_range( cs, 'a', 'z'+1); - pj_cs_add_range( cs, 'A', 'Z'+1); + pj_cis_add_range( cis, 'a', 'z'+1); + pj_cis_add_range( cis, 'A', 'Z'+1); } -PJ_DEF(void) pj_cs_add_num( pj_char_spec cs) +PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis) { - pj_cs_add_range( cs, '0', '9'+1); + pj_cis_add_range( cis, '0', '9'+1); } -PJ_DEF(void) pj_cs_add_str( pj_char_spec cs, const char *str) +PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str) { - PJ_CHECK_STACK(); while (*str) { - cs[(int)*str] = 1; + PJ_CIS_SET(cis, *str); ++str; } } -PJ_DEF(void) pj_cs_del_range( pj_char_spec cs, int cstart, int cend) +PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend) { - PJ_CHECK_STACK(); - while (cstart != cend) - cs[cstart++] = 0; + while (cstart != cend) { + PJ_CIS_CLR(cis, cstart); + cstart++; + } } -PJ_DEF(void) pj_cs_del_str( pj_char_spec cs, const char *str) +PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str) { - PJ_CHECK_STACK(); while (*str) { - cs[(int)*str] = 0; + PJ_CIS_CLR(cis, *str); ++str; } } -PJ_DEF(void) pj_cs_invert( pj_char_spec cs ) +PJ_DEF(void) pj_cis_invert( pj_cis_t *cis ) { unsigned i; - PJ_CHECK_STACK(); - for (i=0; icurptr; register char *end = scanner->end; @@ -177,7 +210,7 @@ PJ_DEF(int) pj_scan_peek( pj_scanner *scanner, return -1; } - while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)) + while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)) ++s; pj_strset3(out, scanner->curptr, s); @@ -203,8 +236,8 @@ PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner, PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_char_spec spec, - pj_str_t *out) + const pj_cis_t *spec, + pj_str_t *out) { register char *s = scanner->curptr; register char *end = scanner->end; @@ -216,7 +249,7 @@ PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, return -1; } - while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match( spec, *s)) + while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s)) ++s; pj_strset3(out, scanner->curptr, s); @@ -225,7 +258,7 @@ PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, PJ_DEF(void) pj_scan_get( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out) + const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; register char *end = scanner->end; @@ -233,14 +266,14 @@ PJ_DEF(void) pj_scan_get( pj_scanner *scanner, PJ_CHECK_STACK(); - if (pj_scan_is_eof(scanner) || !pj_cs_match(spec, *s)) { + if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) { pj_scan_syntax_err(scanner); return; } do { ++s; - } while (PJ_SCAN_CHECK_EOF(s) && pj_cs_match(spec, *s)); + } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)); pj_strset3(out, scanner->curptr, s); @@ -395,7 +428,7 @@ PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner ) PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, - const pj_char_spec spec, pj_str_t *out) + const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; register char *end = scanner->end; @@ -408,7 +441,7 @@ PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, return; } - while (PJ_SCAN_CHECK_EOF(s) && !pj_cs_match(spec, *s)) { + while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) { ++s; } @@ -424,7 +457,7 @@ PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, - int until_char, pj_str_t *out) + int until_char, pj_str_t *out) { register char *s = scanner->curptr; register char *end = scanner->end; diff --git a/pjlib/build/pjlib.dsw b/pjlib/build/pjlib.dsw index 41d8c9e0..aa45adf6 100644 --- a/pjlib/build/pjlib.dsw +++ b/pjlib/build/pjlib.dsw @@ -27,7 +27,7 @@ Package=<4> ############################################################################### -Project: "pjlib_samples"=.\pjlib_samples.dsp - Package Owner=<4> +Project: "pjlib++_test"=".\pjlib++-test.dsp" - Package Owner=<4> Package=<5> {{{ @@ -38,11 +38,14 @@ Package=<4> Begin Project Dependency Project_Dep_Name pjlib End Project Dependency + Begin Project Dependency + Project_Dep_Name pjlib++ + End Project Dependency }}} ############################################################################### -Project: "pjlib_test"=.\pjlib_test.dsp - Package Owner=<4> +Project: "pjlib_samples"=.\pjlib_samples.dsp - Package Owner=<4> Package=<5> {{{ @@ -57,7 +60,7 @@ Package=<4> ############################################################################### -Project: "pjlib++_test"=.\pjlib++-test.dsp - Package Owner=<4> +Project: "pjlib_test"=.\pjlib_test.dsp - Package Owner=<4> Package=<5> {{{ @@ -68,9 +71,6 @@ Package=<4> Begin Project Dependency Project_Dep_Name pjlib End Project Dependency - Begin Project Dependency - Project_Dep_Name pjlib++ - End Project Dependency }}} ############################################################################### diff --git a/pjlib/include/pj++/file.hpp b/pjlib/include/pj++/file.hpp index dfd78d51..e45810c5 100644 --- a/pjlib/include/pj++/file.hpp +++ b/pjlib/include/pj++/file.hpp @@ -1,171 +1,171 @@ -/* $Id$ */ - -#ifndef __PJPP_FILE_HPP__ -#define __PJPP_FILE_HPP__ - -#include -#include -#include -#include - -// -// File API. -// -class Pj_File_API -{ -public: - // - // Check file existance. - // - static bool file_exists(const char *filename) - { - return pj_file_exists(filename) != 0; - } - - // - // Get file size. - // - static pj_off_t file_size(const char *filename) - { - return pj_file_size(filename); - } - - // - // Delete file. - // - static pj_status_t file_delete(const char *filename) - { - return pj_file_delete(filename); - } - - // - // Move/rename file. - // - static pj_status_t file_move(const char *oldname, const char *newname) - { - return pj_file_move(oldname, newname); - } - - // - // Get stat. - // - static pj_status_t file_stat(const char *filename, pj_file_stat *buf) - { - return pj_file_getstat(filename, buf); - } -}; - - -// -// File. -// -class Pj_File : public Pj_Object -{ -public: - // - // Offset type to be used in setpos. - // - enum Offset_Type - { - SEEK_SET = PJ_SEEK_SET, - SEEK_CUR = PJ_SEEK_CUR, - SEEK_END = PJ_SEEK_END, - }; - - // - // Default constructor. - // - Pj_File() - : hnd_(0) - { - } - - // - // Construct and open a file. - // - Pj_File(Pj_Pool *pool, const char *filename, - unsigned access = PJ_O_RDONLY) - : hnd_(NULL) - { - open(pool, filename, access); - } - - // - // Destructor closes the file. - // - ~Pj_File() - { - close(); - } - - // - // Open a file. - // - pj_status_t open(Pj_Pool *pool, const char *filename, - unsigned access = PJ_O_RDONLY ) - { - close(); - return pj_file_open(pool->pool_(), filename, access, &hnd_); - } - - // - // Close a file. - // - void close() - { - if (hnd_ != 0) { - pj_file_close(hnd_); - hnd_ = 0; - } - } - - // - // Write data. - // - pj_ssize_t write(const void *buff, pj_size_t size) - { - pj_ssize_t bytes = size; - if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // Read data. - // - pj_ssize_t read(void *buf, pj_size_t size) - { - pj_ssize_t bytes = size; - if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // Set file position. - // - pj_status_t setpos(pj_off_t offset, Offset_Type whence) - { - return pj_file_setpos(hnd_, offset, - (enum pj_file_seek_type)whence); - } - - // - // Get file position. - // - pj_off_t getpos() - { - pj_off_t pos; - if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS) - return -1; - return pos; - } - -private: - pj_oshandle_t hnd_; -}; - - - -#endif /* __PJPP_FILE_HPP__ */ - +/* $Id$ + */ +#ifndef __PJPP_FILE_HPP__ +#define __PJPP_FILE_HPP__ + +#include +#include +#include +#include + +// +// File API. +// +class Pj_File_API +{ +public: + // + // Check file existance. + // + static bool file_exists(const char *filename) + { + return pj_file_exists(filename) != 0; + } + + // + // Get file size. + // + static pj_off_t file_size(const char *filename) + { + return pj_file_size(filename); + } + + // + // Delete file. + // + static pj_status_t file_delete(const char *filename) + { + return pj_file_delete(filename); + } + + // + // Move/rename file. + // + static pj_status_t file_move(const char *oldname, const char *newname) + { + return pj_file_move(oldname, newname); + } + + // + // Get stat. + // + static pj_status_t file_stat(const char *filename, pj_file_stat *buf) + { + return pj_file_getstat(filename, buf); + } +}; + + +// +// File. +// +class Pj_File : public Pj_Object +{ +public: + // + // Offset type to be used in setpos. + // + enum Offset_Type + { + SEEK_SET = PJ_SEEK_SET, + SEEK_CUR = PJ_SEEK_CUR, + SEEK_END = PJ_SEEK_END, + }; + + // + // Default constructor. + // + Pj_File() + : hnd_(0) + { + } + + // + // Construct and open a file. + // + Pj_File(Pj_Pool *pool, const char *filename, + unsigned access = PJ_O_RDONLY) + : hnd_(NULL) + { + open(pool, filename, access); + } + + // + // Destructor closes the file. + // + ~Pj_File() + { + close(); + } + + // + // Open a file. + // + pj_status_t open(Pj_Pool *pool, const char *filename, + unsigned access = PJ_O_RDONLY ) + { + close(); + return pj_file_open(pool->pool_(), filename, access, &hnd_); + } + + // + // Close a file. + // + void close() + { + if (hnd_ != 0) { + pj_file_close(hnd_); + hnd_ = 0; + } + } + + // + // Write data. + // + pj_ssize_t write(const void *buff, pj_size_t size) + { + pj_ssize_t bytes = size; + if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS) + return -1; + return bytes; + } + + // + // Read data. + // + pj_ssize_t read(void *buf, pj_size_t size) + { + pj_ssize_t bytes = size; + if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS) + return -1; + return bytes; + } + + // + // Set file position. + // + pj_status_t setpos(pj_off_t offset, Offset_Type whence) + { + return pj_file_setpos(hnd_, offset, + (enum pj_file_seek_type)whence); + } + + // + // Get file position. + // + pj_off_t getpos() + { + pj_off_t pos; + if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS) + return -1; + return pos; + } + +private: + pj_oshandle_t hnd_; +}; + + + +#endif /* __PJPP_FILE_HPP__ */ + diff --git a/pjlib/include/pj++/hash.hpp b/pjlib/include/pj++/hash.hpp index 6d4a5e68..691ac3a8 100644 --- a/pjlib/include/pj++/hash.hpp +++ b/pjlib/include/pj++/hash.hpp @@ -1,139 +1,139 @@ /* $Id$ - */ -#ifndef __PJPP_HASH_H__ -#define __PJPP_HASH_H__ - -#include -#include -#include - -// -// Hash table. -// -class Pj_Hash_Table : public Pj_Object -{ -public: - // - // Hash table iterator. - // - class iterator - { - public: - iterator() - { - } - explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) - : ht_(h), it_(i) - { - } - iterator(const iterator &rhs) - : ht_(rhs.ht_), it_(rhs.it_) - { - } - void operator++() - { - it_ = pj_hash_next(ht_, it_); - } - bool operator==(const iterator &rhs) - { - return ht_ == rhs.ht_ && it_ == rhs.it_; - } - iterator & operator=(const iterator &rhs) - { - ht_=rhs.ht_; it_=rhs.it_; - return *this; - } - private: - pj_hash_table_t *ht_; - pj_hash_iterator_t it_val_; - pj_hash_iterator_t *it_; - - friend class Pj_Hash_Table; - }; - - // - // Construct hash table. - // - Pj_Hash_Table(Pj_Pool *pool, unsigned size) - { - table_ = pj_hash_create(pool->pool_(), size); - } - - // - // Destroy hash table. - // - ~Pj_Hash_Table() - { - } - - // - // Calculate hash value. - // - static pj_uint32_t calc( pj_uint32_t initial_hval, - const void *key, - unsigned keylen = PJ_HASH_KEY_STRING) - { - return pj_hash_calc(initial_hval, key, keylen); - } - - // - // Return pjlib compatible hash table object. - // - pj_hash_table_t *pj_hash_table_t_() - { - return table_; - } - - // - // Get the value associated with the specified key. - // - void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING) - { - return pj_hash_get(table_, key, keylen); - } - - // - // Associate a value with a key. - // Set the value to NULL to delete the key from the hash table. - // - void set(Pj_Pool *pool, - const void *key, - void *value, - unsigned keylen = PJ_HASH_KEY_STRING) - { - pj_hash_set(pool->pool_(), table_, key, keylen, value); - } - - // - // Get number of items in the hash table. - // - unsigned count() - { - return pj_hash_count(table_); - } - - // - // Iterate hash table. - // - iterator begin() - { - iterator it(table_, NULL); - it.it_ = pj_hash_first(table_, &it.it_val_); - return it; - } - - // - // End of items. - // - iterator end() - { - return iterator(table_, NULL); - } - -private: - pj_hash_table_t *table_; -}; - - -#endif /* __PJPP_HASH_H__ */ - + */ +#ifndef __PJPP_HASH_HPP__ +#define __PJPP_HASH_HPP__ + +#include +#include +#include + +// +// Hash table. +// +class Pj_Hash_Table : public Pj_Object +{ +public: + // + // Hash table iterator. + // + class iterator + { + public: + iterator() + { + } + explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) + : ht_(h), it_(i) + { + } + iterator(const iterator &rhs) + : ht_(rhs.ht_), it_(rhs.it_) + { + } + void operator++() + { + it_ = pj_hash_next(ht_, it_); + } + bool operator==(const iterator &rhs) + { + return ht_ == rhs.ht_ && it_ == rhs.it_; + } + iterator & operator=(const iterator &rhs) + { + ht_=rhs.ht_; it_=rhs.it_; + return *this; + } + private: + pj_hash_table_t *ht_; + pj_hash_iterator_t it_val_; + pj_hash_iterator_t *it_; + + friend class Pj_Hash_Table; + }; + + // + // Construct hash table. + // + Pj_Hash_Table(Pj_Pool *pool, unsigned size) + { + table_ = pj_hash_create(pool->pool_(), size); + } + + // + // Destroy hash table. + // + ~Pj_Hash_Table() + { + } + + // + // Calculate hash value. + // + static pj_uint32_t calc( pj_uint32_t initial_hval, + const void *key, + unsigned keylen = PJ_HASH_KEY_STRING) + { + return pj_hash_calc(initial_hval, key, keylen); + } + + // + // Return pjlib compatible hash table object. + // + pj_hash_table_t *pj_hash_table_t_() + { + return table_; + } + + // + // Get the value associated with the specified key. + // + void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING) + { + return pj_hash_get(table_, key, keylen); + } + + // + // Associate a value with a key. + // Set the value to NULL to delete the key from the hash table. + // + void set(Pj_Pool *pool, + const void *key, + void *value, + unsigned keylen = PJ_HASH_KEY_STRING) + { + pj_hash_set(pool->pool_(), table_, key, keylen, value); + } + + // + // Get number of items in the hash table. + // + unsigned count() + { + return pj_hash_count(table_); + } + + // + // Iterate hash table. + // + iterator begin() + { + iterator it(table_, NULL); + it.it_ = pj_hash_first(table_, &it.it_val_); + return it; + } + + // + // End of items. + // + iterator end() + { + return iterator(table_, NULL); + } + +private: + pj_hash_table_t *table_; +}; + + +#endif /* __PJPP_HASH_HPP__ */ + diff --git a/pjlib/include/pj++/list.hpp b/pjlib/include/pj++/list.hpp index 9895c1c2..c3a8f386 100644 --- a/pjlib/include/pj++/list.hpp +++ b/pjlib/include/pj++/list.hpp @@ -1,310 +1,311 @@ /* $Id$ - */ -#ifndef __PJPP_LIST_H__ -#define __PJPP_LIST_H__ - -#include -#include - - -// -// Linked-list. -// -// Note: -// List_Node must have public member next and prev. Normally -// it will be declared like: -// -// struct my_node -// { -// PJ_DECL_LIST_MEMBER(struct my_node); -// .. -// }; -// -// -template -class Pj_List : public Pj_Object -{ -public: - // - // List const_iterator. - // - class const_iterator - { - public: - const_iterator() - : node_(NULL) - {} - const_iterator(const List_Node *nd) - : node_((List_Node*)nd) - {} - const List_Node * operator *() - { - return node_; - } - const List_Node * operator -> () - { - return node_; - } - const_iterator operator++() - { - return const_iterator(node_->next); - } - bool operator==(const const_iterator &rhs) - { - return node_ == rhs.node_; - } - bool operator!=(const const_iterator &rhs) - { - return node_ != rhs.node_; - } - - protected: - List_Node *node_; - }; - - // - // List iterator. - // - class iterator : public const_iterator - { - public: - iterator() - {} - iterator(List_Node *nd) - : const_iterator(nd) - {} - List_Node * operator *() - { - return node_; - } - List_Node * operator -> () - { - return node_; - } - iterator operator++() - { - return iterator(node_->next); - } - bool operator==(const iterator &rhs) - { - return node_ == rhs.node_; - } - bool operator!=(const iterator &rhs) - { - return node_ != rhs.node_; - } - }; - - // - // Default constructor. - // - Pj_List() - { - pj_list_init(&root_); - if (0) compiletest(); - } - - // - // Check if list is empty. - // - bool empty() const - { - return pj_list_empty(&root_); - } - - // - // Get first element. - // - iterator begin() - { - return iterator(root_.next); - } - - // - // Get first element. - // - const_iterator begin() const - { - return const_iterator(root_.next); - } - - // - // Get end-of-element - // - const_iterator end() const - { - return const_iterator((List_Node*)&root_); - } - - // - // Get end-of-element - // - iterator end() - { - return iterator((List_Node*)&root_); - } - - // - // Insert node. - // - void insert_before (iterator &pos, List_Node *node) - { - pj_list_insert_before( *pos, node ); - } - - // - // Insert node. - // - void insert_after(iterator &pos, List_Node *node) - { - pj_list_insert_after(*pos, node); - } - - // - // Merge list. - // - void merge_first(List_Node *list2) - { - pj_list_merge_first(&root_, list2); - } - - // - // Merge list. - // - void merge_last(Pj_List *list) - { - pj_list_merge_last(&root_, &list->root_); - } - - // - // Insert list. - // - void insert_nodes_before(iterator &pos, Pj_List *list2) - { - pj_list_insert_nodes_before(*pos, &list2->root_); - } - - // - // Insert list. - // - void insert_nodes_after(iterator &pos, Pj_List *list2) - { - pj_list_insert_nodes_after(*pos, &list2->root_); - } - - // - // Erase an element. - // - void erase(iterator &it) - { - pj_list_erase(*it); - } - - // - // Get first element. - // - List_Node *front() - { - return root_.next; - } - - // - // Get first element. - // - const List_Node *front() const - { - return root_.next; - } - - // - // Remove first element. - // - void pop_front() - { - pj_list_erase(root_.next); - } - - // - // Get last element. - // - List_Node *back() - { - return root_.prev; - } - - // - // Get last element. - // - const List_Node *back() const - { - return root_.prev; - } - - // - // Remove last element. - // - void pop_back() - { - pj_list_erase(root_.prev); - } - - // - // Find a node. - // - iterator find(List_Node *node) - { - List_Node *n = pj_list_find_node(&root_, node); - return n ? iterator(n) : end(); - } - - // - // Find a node. - // - const_iterator find(List_Node *node) const - { - List_Node *n = pj_list_find_node(&root_, node); - return n ? const_iterator(n) : end(); - } - - // - // Insert a node in the back. - // - void push_back(List_Node *node) - { - pj_list_insert_after(root_.prev, node); - } - - // - // Insert a node in the front. - // - void push_front(List_Node *node) - { - pj_list_insert_before(root_.next, node); - } - - // - // Remove all elements. - // - void clear() - { - root_.next = &root_; - root_.prev = &root_; - } - -private: - struct RootNode - { - PJ_DECL_LIST_MEMBER(List_Node); - } root_; - - void compiletest() - { - // If you see error in this line, - // it's because List_Node is not derived from Pj_List_Node. - List_Node *n = (List_Node*)0; - n = n->next; n = n->prev; - } -}; - - -#endif /* __PJPP_LIST_H__ */ + */ +#ifndef __PJPP_LIST_HPP__ +#define __PJPP_LIST_HPP__ + +#include +#include + + +// +// Linked-list. +// +// Note: +// List_Node must have public member next and prev. Normally +// it will be declared like: +// +// struct my_node +// { +// PJ_DECL_LIST_MEMBER(struct my_node); +// .. +// }; +// +// +template +class Pj_List : public Pj_Object +{ +public: + // + // List const_iterator. + // + class const_iterator + { + public: + const_iterator() + : node_(NULL) + {} + const_iterator(const List_Node *nd) + : node_((List_Node*)nd) + {} + const List_Node * operator *() + { + return node_; + } + const List_Node * operator -> () + { + return node_; + } + const_iterator operator++() + { + return const_iterator(node_->next); + } + bool operator==(const const_iterator &rhs) + { + return node_ == rhs.node_; + } + bool operator!=(const const_iterator &rhs) + { + return node_ != rhs.node_; + } + + protected: + List_Node *node_; + }; + + // + // List iterator. + // + class iterator : public const_iterator + { + public: + iterator() + {} + iterator(List_Node *nd) + : const_iterator(nd) + {} + List_Node * operator *() + { + return node_; + } + List_Node * operator -> () + { + return node_; + } + iterator operator++() + { + return iterator(node_->next); + } + bool operator==(const iterator &rhs) + { + return node_ == rhs.node_; + } + bool operator!=(const iterator &rhs) + { + return node_ != rhs.node_; + } + }; + + // + // Default constructor. + // + Pj_List() + { + pj_list_init(&root_); + if (0) compiletest(); + } + + // + // Check if list is empty. + // + bool empty() const + { + return pj_list_empty(&root_); + } + + // + // Get first element. + // + iterator begin() + { + return iterator(root_.next); + } + + // + // Get first element. + // + const_iterator begin() const + { + return const_iterator(root_.next); + } + + // + // Get end-of-element + // + const_iterator end() const + { + return const_iterator((List_Node*)&root_); + } + + // + // Get end-of-element + // + iterator end() + { + return iterator((List_Node*)&root_); + } + + // + // Insert node. + // + void insert_before (iterator &pos, List_Node *node) + { + pj_list_insert_before( *pos, node ); + } + + // + // Insert node. + // + void insert_after(iterator &pos, List_Node *node) + { + pj_list_insert_after(*pos, node); + } + + // + // Merge list. + // + void merge_first(List_Node *list2) + { + pj_list_merge_first(&root_, list2); + } + + // + // Merge list. + // + void merge_last(Pj_List *list) + { + pj_list_merge_last(&root_, &list->root_); + } + + // + // Insert list. + // + void insert_nodes_before(iterator &pos, Pj_List *list2) + { + pj_list_insert_nodes_before(*pos, &list2->root_); + } + + // + // Insert list. + // + void insert_nodes_after(iterator &pos, Pj_List *list2) + { + pj_list_insert_nodes_after(*pos, &list2->root_); + } + + // + // Erase an element. + // + void erase(iterator &it) + { + pj_list_erase(*it); + } + + // + // Get first element. + // + List_Node *front() + { + return root_.next; + } + + // + // Get first element. + // + const List_Node *front() const + { + return root_.next; + } + + // + // Remove first element. + // + void pop_front() + { + pj_list_erase(root_.next); + } + + // + // Get last element. + // + List_Node *back() + { + return root_.prev; + } + + // + // Get last element. + // + const List_Node *back() const + { + return root_.prev; + } + + // + // Remove last element. + // + void pop_back() + { + pj_list_erase(root_.prev); + } + + // + // Find a node. + // + iterator find(List_Node *node) + { + List_Node *n = pj_list_find_node(&root_, node); + return n ? iterator(n) : end(); + } + + // + // Find a node. + // + const_iterator find(List_Node *node) const + { + List_Node *n = pj_list_find_node(&root_, node); + return n ? const_iterator(n) : end(); + } + + // + // Insert a node in the back. + // + void push_back(List_Node *node) + { + pj_list_insert_after(root_.prev, node); + } + + // + // Insert a node in the front. + // + void push_front(List_Node *node) + { + pj_list_insert_before(root_.next, node); + } + + // + // Remove all elements. + // + void clear() + { + root_.next = &root_; + root_.prev = &root_; + } + +private: + struct RootNode + { + PJ_DECL_LIST_MEMBER(List_Node); + } root_; + + void compiletest() + { + // If you see error in this line, + // it's because List_Node is not derived from Pj_List_Node. + List_Node *n = (List_Node*)0; + n = n->next; n = n->prev; + } +}; + + +#endif /* __PJPP_LIST_HPP__ */ + diff --git a/pjlib/include/pj++/lock.hpp b/pjlib/include/pj++/lock.hpp index 93a435e6..95ea63b6 100644 --- a/pjlib/include/pj++/lock.hpp +++ b/pjlib/include/pj++/lock.hpp @@ -1,131 +1,132 @@ -/* $Id$ */ -#ifndef __PJPP_LOCK_H__ -#define __PJPP_LOCK_H__ - -#include -#include -#include - -////////////////////////////////////////////////////////////////////////////// -// Lock object. -// -class Pj_Lock : public Pj_Object -{ -public: - // - // Constructor. - // - explicit Pj_Lock(pj_lock_t *lock) - : lock_(lock) - { - } - - // - // Destructor. - // - ~Pj_Lock() - { - if (lock_) - pj_lock_destroy(lock_); - } - - // - // Get pjlib compatible lock object. - // - pj_lock_t *pj_lock_t_() - { - return lock_; - } - - // - // acquire lock. - // - pj_status_t acquire() - { - return pj_lock_acquire(lock_); - } - - // - // release lock,. - // - pj_status_t release() - { - return pj_lock_release(lock_); - } - -protected: - pj_lock_t *lock_; -}; - - -////////////////////////////////////////////////////////////////////////////// -// Null lock object. -// -class Pj_Null_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_null_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Simple mutex lock object. -// -class Pj_Simple_Mutex_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_simple_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Recursive mutex lock object. -// -class Pj_Recursive_Mutex_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) - : Pj_Lock(NULL) - { - pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_); - } -}; - -////////////////////////////////////////////////////////////////////////////// -// Semaphore lock object. -// -class Pj_Semaphore_Lock : public Pj_Lock -{ -public: - // - // Default constructor. - // - explicit Pj_Semaphore_Lock(Pj_Pool *pool, - unsigned max=PJ_MAXINT32, - unsigned initial=0, - const char *name=NULL) - : Pj_Lock(NULL) - { - pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_); - } -}; - - - -#endif /* __PJPP_LOCK_H__ */ - +/* $Id$ + */ +#ifndef __PJPP_LOCK_HPP__ +#define __PJPP_LOCK_HPP__ + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// Lock object. +// +class Pj_Lock : public Pj_Object +{ +public: + // + // Constructor. + // + explicit Pj_Lock(pj_lock_t *lock) + : lock_(lock) + { + } + + // + // Destructor. + // + ~Pj_Lock() + { + if (lock_) + pj_lock_destroy(lock_); + } + + // + // Get pjlib compatible lock object. + // + pj_lock_t *pj_lock_t_() + { + return lock_; + } + + // + // acquire lock. + // + pj_status_t acquire() + { + return pj_lock_acquire(lock_); + } + + // + // release lock,. + // + pj_status_t release() + { + return pj_lock_release(lock_); + } + +protected: + pj_lock_t *lock_; +}; + + +////////////////////////////////////////////////////////////////////////////// +// Null lock object. +// +class Pj_Null_Lock : public Pj_Lock +{ +public: + // + // Default constructor. + // + explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL) + : Pj_Lock(NULL) + { + pj_lock_create_null_mutex(pool->pool_(), name, &lock_); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Simple mutex lock object. +// +class Pj_Simple_Mutex_Lock : public Pj_Lock +{ +public: + // + // Default constructor. + // + explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) + : Pj_Lock(NULL) + { + pj_lock_create_simple_mutex(pool->pool_(), name, &lock_); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Recursive mutex lock object. +// +class Pj_Recursive_Mutex_Lock : public Pj_Lock +{ +public: + // + // Default constructor. + // + explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL) + : Pj_Lock(NULL) + { + pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// Semaphore lock object. +// +class Pj_Semaphore_Lock : public Pj_Lock +{ +public: + // + // Default constructor. + // + explicit Pj_Semaphore_Lock(Pj_Pool *pool, + unsigned max=PJ_MAXINT32, + unsigned initial=0, + const char *name=NULL) + : Pj_Lock(NULL) + { + pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_); + } +}; + + + +#endif /* __PJPP_LOCK_HPP__ */ + diff --git a/pjlib/include/pj++/os.hpp b/pjlib/include/pj++/os.hpp index 1101daea..461a36e8 100644 --- a/pjlib/include/pj++/os.hpp +++ b/pjlib/include/pj++/os.hpp @@ -1,787 +1,788 @@ /* $Id$ - */ -#ifndef __PJPP_OS_H__ -#define __PJPP_OS_H__ - -#include -#include -#include - -class Pj_Thread; - -// -// Thread API. -// -class Pj_Thread_API -{ -public: - // - // Create a thread. - // - static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread, - pj_thread_proc *proc, void *arg, - unsigned flags = 0, - const char *name = NULL, - pj_size_t stack_size = 0 ) - { - return pj_thread_create(pool->pool_(), name, proc, arg, stack_size, - flags, thread); - } - - // - // Register a thread. - // - static pj_status_t register_this_thread( pj_thread_desc desc, - pj_thread_t **thread, - const char *name = NULL ) - { - return pj_thread_register( name, desc, thread ); - } - - // - // Get current thread. - // Will return pj_thread_t (sorry folks, not Pj_Thread). - // - static pj_thread_t *this_thread() - { - return pj_thread_this(); - } - - // - // Get thread name. - // - static const char *get_name(pj_thread_t *thread) - { - return pj_thread_get_name(thread); - } - - // - // Resume thread. - // - static pj_status_t resume(pj_thread_t *thread) - { - return pj_thread_resume(thread); - } - - // - // Sleep. - // - static pj_status_t sleep(unsigned msec) - { - return pj_thread_sleep(msec); - } - - // - // Join the specified thread. - // - static pj_status_t join(pj_thread_t *thread) - { - return pj_thread_join(thread); - } - - // - // Destroy thread - // - static pj_status_t destroy(pj_thread_t *thread) - { - return pj_thread_destroy(thread); - } -}; - - - -// -// Thread object. -// -// How to use: -// Derive a class from this class, then override main(). -// -class Pj_Thread : public Pj_Object -{ -public: - enum Flags - { - FLAG_SUSPENDED = PJ_THREAD_SUSPENDED - }; - - // - // Default constructor. - // - Pj_Thread() - : thread_(NULL) - { - } - - // - // Destroy thread. - // - ~Pj_Thread() - { - destroy(); - } - - // - // This is the main thread function. - // - virtual int main() = 0; - - // - // Start a thread. - // - pj_status_t create( Pj_Pool *pool, - unsigned flags = 0, - const char *thread_name = NULL, - pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE) - { - destroy(); - return Pj_Thread_API::create( pool, &thread_, &thread_proc, this, - flags, thread_name); - } - - // - // Get pjlib compatible thread object. - // - pj_thread_t *pj_thread_t_() - { - return thread_; - } - - // - // Get thread name. - // - const char *get_name() - { - return Pj_Thread_API::get_name(thread_); - } - - // - // Resume a suspended thread. - // - pj_status_t resume() - { - return Pj_Thread_API::resume(thread_); - } - - // - // Join this thread. - // - pj_status_t join() - { - return Pj_Thread_API::join(thread_); - } - - // - // Destroy thread. - // - pj_status_t destroy() - { - if (thread_) { - Pj_Thread_API::destroy(thread_); - thread_ = NULL; - } - } - -protected: - pj_thread_t *thread_; - - static int PJ_THREAD_FUNC thread_proc(void *obj) - { - Pj_Thread *thread_class = (Pj_Thread*)obj; - return thread_class->main(); - } -}; - - -// -// External Thread -// (threads that were started by external means, i.e. not -// with Pj_Thread::create). -// -// This class will normally be defined as local variable in -// external thread's stack, normally inside thread's main proc. -// But be aware that the handle will be destroyed on destructor! -// -class Pj_External_Thread : public Pj_Thread -{ -public: - Pj_External_Thread() - { - } - - // - // Register external thread so that pjlib functions can work - // in that thread. - // - pj_status_t register_this_thread( const char *name=NULL ) - { - return Pj_Thread_API::register_this_thread(desc_, &thread_,name); - } - -private: - pj_thread_desc desc_; -}; - - -// -// Thread specific data/thread local storage/TLS. -// -class Pj_Thread_Local_API -{ -public: - // - // Allocate thread local storage (TLS) index. - // - static pj_status_t alloc(long *index) - { - return pj_thread_local_alloc(index); - } - - // - // Free TLS index. - // - static void free(long index) - { - pj_thread_local_free(index); - } - - // - // Set thread specific data. - // - static pj_status_t set(long index, void *value) - { - return pj_thread_local_set(index, value); - } - - // - // Get thread specific data. - // - static void *get(long index) - { - return pj_thread_local_get(index); - } - -}; - -// -// Atomic variable -// -// How to use: -// Pj_Atomic_Var var(pool, 0); -// var.set(..); -// -class Pj_Atomic_Var : public Pj_Object -{ -public: - // - // Default constructor, initialize variable with NULL. - // - Pj_Atomic_Var() - : var_(NULL) - { - } - - // - // Construct atomic variable. - // - Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value) - : var_(NULL) - { - create(pool, value); - } - - // - // Destructor. - // - ~Pj_Atomic_Var() - { - destroy(); - } - - // - // Create atomic variable. - // - pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value) - { - destroy(); - return pj_atomic_create(pool->pool_(), value, &var_); - } - - // - // Destroy. - // - void destroy() - { - if (var_) { - pj_atomic_destroy(var_); - var_ = NULL; - } - } - - // - // Get pjlib compatible atomic variable. - // - pj_atomic_t *pj_atomic_t_() - { - return var_; - } - - // - // Set the value. - // - void set(pj_atomic_value_t val) - { - pj_atomic_set(var_, val); - } - - // - // Get the value. - // - pj_atomic_value_t get() - { - return pj_atomic_get(var_); - } - - // - // Increment. - // - void inc() - { - pj_atomic_inc(var_); - } - - // - // Increment and get the result. - // - pj_atomic_value_t inc_and_get() - { - return pj_atomic_inc_and_get(var_); - } - - // - // Decrement. - // - void dec() - { - pj_atomic_dec(var_); - } - - // - // Decrement and get the result. - // - pj_atomic_value_t dec_and_get() - { - return pj_atomic_dec_and_get(var_); - } - - // - // Add the variable. - // - void add(pj_atomic_value_t value) - { - pj_atomic_add(var_, value); - } - - // - // Add the variable and get the value. - // - pj_atomic_value_t add_and_get(pj_atomic_value_t value) - { - return pj_atomic_add_and_get(var_, value ); - } - -private: - pj_atomic_t *var_; -}; - - -// -// Mutex -// -class Pj_Mutex : public Pj_Object -{ -public: - // - // Mutex type. - // - enum Type - { - DEFAULT = PJ_MUTEX_DEFAULT, - SIMPLE = PJ_MUTEX_SIMPLE, - RECURSE = PJ_MUTEX_RECURSE, - }; - - // - // Default constructor will create default mutex. - // - explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT, - const char *name = NULL) - : mutex_(NULL) - { - create(pool, type, name); - } - - // - // Destructor. - // - ~Pj_Mutex() - { - destroy(); - } - - // - // Create mutex. - // - pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL) - { - destroy(); - return pj_mutex_create( pool->pool_(), name, type, - &mutex_ ); - } - - // - // Create simple mutex. - // - pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL) - { - return create(pool, SIMPLE, name); - } - - // - // Create recursive mutex. - // - pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL ) - { - return create(pool, RECURSE, name); - } - - // - // Get pjlib compatible mutex object. - // - pj_mutex_t *pj_mutex_t_() - { - return mutex_; - } - - // - // Destroy mutex. - // - void destroy() - { - if (mutex_) { - pj_mutex_destroy(mutex_); - mutex_ = NULL; - } - } - - // - // Lock mutex. - // - pj_status_t acquire() - { - return pj_mutex_lock(mutex_); - } - - // - // Unlock mutex. - // - pj_status_t release() - { - return pj_mutex_unlock(mutex_); - } - - // - // Try locking the mutex. - // - pj_status_t tryacquire() - { - return pj_mutex_trylock(mutex_); - } - -private: - pj_mutex_t *mutex_; -}; - - -// -// Semaphore -// -class Pj_Semaphore : public Pj_Object -{ -public: - // - // Construct semaphore - // - Pj_Semaphore(Pj_Pool *pool, unsigned max, - unsigned initial = 0, const char *name = NULL) - : sem_(NULL) - { - } - - // - // Destructor. - // - ~Pj_Semaphore() - { - destroy(); - } - - // - // Create semaphore - // - pj_status_t create( Pj_Pool *pool, unsigned max, - unsigned initial = 0, const char *name = NULL ) - { - destroy(); - return pj_sem_create( pool->pool_(), name, initial, max, &sem_); - } - - // - // Destroy semaphore. - // - void destroy() - { - if (sem_) { - pj_sem_destroy(sem_); - sem_ = NULL; - } - } - - // - // Get pjlib compatible semaphore object. - // - pj_sem_t *pj_sem_t_() - { - return (pj_sem_t*)this; - } - - // - // Wait semaphore. - // - pj_status_t wait() - { - return pj_sem_wait(this->pj_sem_t_()); - } - - // - // Wait semaphore. - // - pj_status_t acquire() - { - return wait(); - } - - // - // Try wait semaphore. - // - pj_status_t trywait() - { - return pj_sem_trywait(this->pj_sem_t_()); - } - - // - // Try wait semaphore. - // - pj_status_t tryacquire() - { - return trywait(); - } - - // - // Post semaphore. - // - pj_status_t post() - { - return pj_sem_post(this->pj_sem_t_()); - } - - // - // Post semaphore. - // - pj_status_t release() - { - return post(); - } - -private: - pj_sem_t *sem_; -}; - - -// -// Event object. -// -class Pj_Event -{ -public: - // - // Construct event object. - // - Pj_Event( Pj_Pool *pool, bool manual_reset = false, - bool initial = false, const char *name = NULL ) - : event_(NULL) - { - create(pool, manual_reset, initial, name); - } - - // - // Destructor. - // - ~Pj_Event() - { - destroy(); - } - - // - // Create event object. - // - pj_status_t create( Pj_Pool *pool, bool manual_reset = false, - bool initial = false, const char *name = NULL) - { - destroy(); - return pj_event_create(pool->pool_(), name, manual_reset, initial, - &event_); - } - - // - // Get pjlib compatible event object. - // - pj_event_t *pj_event_t_() - { - return event_; - } - - // - // Destroy event object. - // - void destroy() - { - if (event_) { - pj_event_destroy(event_); - event_ = NULL; - } - } - - // - // Wait. - // - pj_status_t wait() - { - return pj_event_wait(event_); - } - - // - // Try wait. - // - pj_status_t trywait() - { - return pj_event_trywait(event_); - } - - // - // Set event state to signalled. - // - pj_status_t set() - { - return pj_event_set(this->pj_event_t_()); - } - - // - // Release one waiting thread. - // - pj_status_t pulse() - { - return pj_event_pulse(this->pj_event_t_()); - } - - // - // Set a non-signalled. - // - pj_status_t reset() - { - return pj_event_reset(this->pj_event_t_()); - } - -private: - pj_event_t *event_; -}; - -// -// OS abstraction. -// -class Pj_OS_API -{ -public: - // - // Get current time. - // - static pj_status_t gettimeofday( Pj_Time_Val *tv ) - { - return pj_gettimeofday(tv); - } - - // - // Parse to time of day. - // - static pj_status_t time_decode( const Pj_Time_Val *tv, - pj_parsed_time *pt ) - { - return pj_time_decode(tv, pt); - } - - // - // Parse from time of day. - // - static pj_status_t time_encode( const pj_parsed_time *pt, - Pj_Time_Val *tv) - { - return pj_time_encode(pt, tv); - } - - // - // Convert to GMT. - // - static pj_status_t time_local_to_gmt( Pj_Time_Val *tv ) - { - return pj_time_local_to_gmt( tv ); - } - - // - // Convert time to local. - // - static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) - { - return pj_time_gmt_to_local( tv ); - } -}; - -// -// Timeval inlines. -// -inline pj_status_t Pj_Time_Val::gettimeofday() -{ - return Pj_OS_API::gettimeofday(this); -} - -inline pj_parsed_time Pj_Time_Val::decode() -{ - pj_parsed_time pt; - Pj_OS_API::time_decode(this, &pt); - return pt; -} - -inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt) -{ - return Pj_OS_API::time_encode(pt, this); -} - -inline pj_status_t Pj_Time_Val::to_gmt() -{ - return Pj_OS_API::time_local_to_gmt(this); -} - -inline pj_status_t Pj_Time_Val::to_local() -{ - return Pj_OS_API::time_gmt_to_local(this); -} - -#endif /* __PJPP_OS_H__ */ + */ +#ifndef __PJPP_OS_HPP__ +#define __PJPP_OS_HPP__ + +#include +#include +#include + +class Pj_Thread; + +// +// Thread API. +// +class Pj_Thread_API +{ +public: + // + // Create a thread. + // + static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread, + pj_thread_proc *proc, void *arg, + unsigned flags = 0, + const char *name = NULL, + pj_size_t stack_size = 0 ) + { + return pj_thread_create(pool->pool_(), name, proc, arg, stack_size, + flags, thread); + } + + // + // Register a thread. + // + static pj_status_t register_this_thread( pj_thread_desc desc, + pj_thread_t **thread, + const char *name = NULL ) + { + return pj_thread_register( name, desc, thread ); + } + + // + // Get current thread. + // Will return pj_thread_t (sorry folks, not Pj_Thread). + // + static pj_thread_t *this_thread() + { + return pj_thread_this(); + } + + // + // Get thread name. + // + static const char *get_name(pj_thread_t *thread) + { + return pj_thread_get_name(thread); + } + + // + // Resume thread. + // + static pj_status_t resume(pj_thread_t *thread) + { + return pj_thread_resume(thread); + } + + // + // Sleep. + // + static pj_status_t sleep(unsigned msec) + { + return pj_thread_sleep(msec); + } + + // + // Join the specified thread. + // + static pj_status_t join(pj_thread_t *thread) + { + return pj_thread_join(thread); + } + + // + // Destroy thread + // + static pj_status_t destroy(pj_thread_t *thread) + { + return pj_thread_destroy(thread); + } +}; + + + +// +// Thread object. +// +// How to use: +// Derive a class from this class, then override main(). +// +class Pj_Thread : public Pj_Object +{ +public: + enum Flags + { + FLAG_SUSPENDED = PJ_THREAD_SUSPENDED + }; + + // + // Default constructor. + // + Pj_Thread() + : thread_(NULL) + { + } + + // + // Destroy thread. + // + ~Pj_Thread() + { + destroy(); + } + + // + // This is the main thread function. + // + virtual int main() = 0; + + // + // Start a thread. + // + pj_status_t create( Pj_Pool *pool, + unsigned flags = 0, + const char *thread_name = NULL, + pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE) + { + destroy(); + return Pj_Thread_API::create( pool, &thread_, &thread_proc, this, + flags, thread_name); + } + + // + // Get pjlib compatible thread object. + // + pj_thread_t *pj_thread_t_() + { + return thread_; + } + + // + // Get thread name. + // + const char *get_name() + { + return Pj_Thread_API::get_name(thread_); + } + + // + // Resume a suspended thread. + // + pj_status_t resume() + { + return Pj_Thread_API::resume(thread_); + } + + // + // Join this thread. + // + pj_status_t join() + { + return Pj_Thread_API::join(thread_); + } + + // + // Destroy thread. + // + pj_status_t destroy() + { + if (thread_) { + Pj_Thread_API::destroy(thread_); + thread_ = NULL; + } + } + +protected: + pj_thread_t *thread_; + + static int PJ_THREAD_FUNC thread_proc(void *obj) + { + Pj_Thread *thread_class = (Pj_Thread*)obj; + return thread_class->main(); + } +}; + + +// +// External Thread +// (threads that were started by external means, i.e. not +// with Pj_Thread::create). +// +// This class will normally be defined as local variable in +// external thread's stack, normally inside thread's main proc. +// But be aware that the handle will be destroyed on destructor! +// +class Pj_External_Thread : public Pj_Thread +{ +public: + Pj_External_Thread() + { + } + + // + // Register external thread so that pjlib functions can work + // in that thread. + // + pj_status_t register_this_thread( const char *name=NULL ) + { + return Pj_Thread_API::register_this_thread(desc_, &thread_,name); + } + +private: + pj_thread_desc desc_; +}; + + +// +// Thread specific data/thread local storage/TLS. +// +class Pj_Thread_Local_API +{ +public: + // + // Allocate thread local storage (TLS) index. + // + static pj_status_t alloc(long *index) + { + return pj_thread_local_alloc(index); + } + + // + // Free TLS index. + // + static void free(long index) + { + pj_thread_local_free(index); + } + + // + // Set thread specific data. + // + static pj_status_t set(long index, void *value) + { + return pj_thread_local_set(index, value); + } + + // + // Get thread specific data. + // + static void *get(long index) + { + return pj_thread_local_get(index); + } + +}; + +// +// Atomic variable +// +// How to use: +// Pj_Atomic_Var var(pool, 0); +// var.set(..); +// +class Pj_Atomic_Var : public Pj_Object +{ +public: + // + // Default constructor, initialize variable with NULL. + // + Pj_Atomic_Var() + : var_(NULL) + { + } + + // + // Construct atomic variable. + // + Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value) + : var_(NULL) + { + create(pool, value); + } + + // + // Destructor. + // + ~Pj_Atomic_Var() + { + destroy(); + } + + // + // Create atomic variable. + // + pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value) + { + destroy(); + return pj_atomic_create(pool->pool_(), value, &var_); + } + + // + // Destroy. + // + void destroy() + { + if (var_) { + pj_atomic_destroy(var_); + var_ = NULL; + } + } + + // + // Get pjlib compatible atomic variable. + // + pj_atomic_t *pj_atomic_t_() + { + return var_; + } + + // + // Set the value. + // + void set(pj_atomic_value_t val) + { + pj_atomic_set(var_, val); + } + + // + // Get the value. + // + pj_atomic_value_t get() + { + return pj_atomic_get(var_); + } + + // + // Increment. + // + void inc() + { + pj_atomic_inc(var_); + } + + // + // Increment and get the result. + // + pj_atomic_value_t inc_and_get() + { + return pj_atomic_inc_and_get(var_); + } + + // + // Decrement. + // + void dec() + { + pj_atomic_dec(var_); + } + + // + // Decrement and get the result. + // + pj_atomic_value_t dec_and_get() + { + return pj_atomic_dec_and_get(var_); + } + + // + // Add the variable. + // + void add(pj_atomic_value_t value) + { + pj_atomic_add(var_, value); + } + + // + // Add the variable and get the value. + // + pj_atomic_value_t add_and_get(pj_atomic_value_t value) + { + return pj_atomic_add_and_get(var_, value ); + } + +private: + pj_atomic_t *var_; +}; + + +// +// Mutex +// +class Pj_Mutex : public Pj_Object +{ +public: + // + // Mutex type. + // + enum Type + { + DEFAULT = PJ_MUTEX_DEFAULT, + SIMPLE = PJ_MUTEX_SIMPLE, + RECURSE = PJ_MUTEX_RECURSE, + }; + + // + // Default constructor will create default mutex. + // + explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT, + const char *name = NULL) + : mutex_(NULL) + { + create(pool, type, name); + } + + // + // Destructor. + // + ~Pj_Mutex() + { + destroy(); + } + + // + // Create mutex. + // + pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL) + { + destroy(); + return pj_mutex_create( pool->pool_(), name, type, + &mutex_ ); + } + + // + // Create simple mutex. + // + pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL) + { + return create(pool, SIMPLE, name); + } + + // + // Create recursive mutex. + // + pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL ) + { + return create(pool, RECURSE, name); + } + + // + // Get pjlib compatible mutex object. + // + pj_mutex_t *pj_mutex_t_() + { + return mutex_; + } + + // + // Destroy mutex. + // + void destroy() + { + if (mutex_) { + pj_mutex_destroy(mutex_); + mutex_ = NULL; + } + } + + // + // Lock mutex. + // + pj_status_t acquire() + { + return pj_mutex_lock(mutex_); + } + + // + // Unlock mutex. + // + pj_status_t release() + { + return pj_mutex_unlock(mutex_); + } + + // + // Try locking the mutex. + // + pj_status_t tryacquire() + { + return pj_mutex_trylock(mutex_); + } + +private: + pj_mutex_t *mutex_; +}; + + +// +// Semaphore +// +class Pj_Semaphore : public Pj_Object +{ +public: + // + // Construct semaphore + // + Pj_Semaphore(Pj_Pool *pool, unsigned max, + unsigned initial = 0, const char *name = NULL) + : sem_(NULL) + { + } + + // + // Destructor. + // + ~Pj_Semaphore() + { + destroy(); + } + + // + // Create semaphore + // + pj_status_t create( Pj_Pool *pool, unsigned max, + unsigned initial = 0, const char *name = NULL ) + { + destroy(); + return pj_sem_create( pool->pool_(), name, initial, max, &sem_); + } + + // + // Destroy semaphore. + // + void destroy() + { + if (sem_) { + pj_sem_destroy(sem_); + sem_ = NULL; + } + } + + // + // Get pjlib compatible semaphore object. + // + pj_sem_t *pj_sem_t_() + { + return (pj_sem_t*)this; + } + + // + // Wait semaphore. + // + pj_status_t wait() + { + return pj_sem_wait(this->pj_sem_t_()); + } + + // + // Wait semaphore. + // + pj_status_t acquire() + { + return wait(); + } + + // + // Try wait semaphore. + // + pj_status_t trywait() + { + return pj_sem_trywait(this->pj_sem_t_()); + } + + // + // Try wait semaphore. + // + pj_status_t tryacquire() + { + return trywait(); + } + + // + // Post semaphore. + // + pj_status_t post() + { + return pj_sem_post(this->pj_sem_t_()); + } + + // + // Post semaphore. + // + pj_status_t release() + { + return post(); + } + +private: + pj_sem_t *sem_; +}; + + +// +// Event object. +// +class Pj_Event +{ +public: + // + // Construct event object. + // + Pj_Event( Pj_Pool *pool, bool manual_reset = false, + bool initial = false, const char *name = NULL ) + : event_(NULL) + { + create(pool, manual_reset, initial, name); + } + + // + // Destructor. + // + ~Pj_Event() + { + destroy(); + } + + // + // Create event object. + // + pj_status_t create( Pj_Pool *pool, bool manual_reset = false, + bool initial = false, const char *name = NULL) + { + destroy(); + return pj_event_create(pool->pool_(), name, manual_reset, initial, + &event_); + } + + // + // Get pjlib compatible event object. + // + pj_event_t *pj_event_t_() + { + return event_; + } + + // + // Destroy event object. + // + void destroy() + { + if (event_) { + pj_event_destroy(event_); + event_ = NULL; + } + } + + // + // Wait. + // + pj_status_t wait() + { + return pj_event_wait(event_); + } + + // + // Try wait. + // + pj_status_t trywait() + { + return pj_event_trywait(event_); + } + + // + // Set event state to signalled. + // + pj_status_t set() + { + return pj_event_set(this->pj_event_t_()); + } + + // + // Release one waiting thread. + // + pj_status_t pulse() + { + return pj_event_pulse(this->pj_event_t_()); + } + + // + // Set a non-signalled. + // + pj_status_t reset() + { + return pj_event_reset(this->pj_event_t_()); + } + +private: + pj_event_t *event_; +}; + +// +// OS abstraction. +// +class Pj_OS_API +{ +public: + // + // Get current time. + // + static pj_status_t gettimeofday( Pj_Time_Val *tv ) + { + return pj_gettimeofday(tv); + } + + // + // Parse to time of day. + // + static pj_status_t time_decode( const Pj_Time_Val *tv, + pj_parsed_time *pt ) + { + return pj_time_decode(tv, pt); + } + + // + // Parse from time of day. + // + static pj_status_t time_encode( const pj_parsed_time *pt, + Pj_Time_Val *tv) + { + return pj_time_encode(pt, tv); + } + + // + // Convert to GMT. + // + static pj_status_t time_local_to_gmt( Pj_Time_Val *tv ) + { + return pj_time_local_to_gmt( tv ); + } + + // + // Convert time to local. + // + static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) + { + return pj_time_gmt_to_local( tv ); + } +}; + +// +// Timeval inlines. +// +inline pj_status_t Pj_Time_Val::gettimeofday() +{ + return Pj_OS_API::gettimeofday(this); +} + +inline pj_parsed_time Pj_Time_Val::decode() +{ + pj_parsed_time pt; + Pj_OS_API::time_decode(this, &pt); + return pt; +} + +inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt) +{ + return Pj_OS_API::time_encode(pt, this); +} + +inline pj_status_t Pj_Time_Val::to_gmt() +{ + return Pj_OS_API::time_local_to_gmt(this); +} + +inline pj_status_t Pj_Time_Val::to_local() +{ + return Pj_OS_API::time_gmt_to_local(this); +} + +#endif /* __PJPP_OS_HPP__ */ + diff --git a/pjlib/include/pj++/pool.hpp b/pjlib/include/pj++/pool.hpp index c1991d5b..1fa75759 100644 --- a/pjlib/include/pj++/pool.hpp +++ b/pjlib/include/pj++/pool.hpp @@ -1,253 +1,254 @@ /* $Id$ - */ -#ifndef __PJPP_POOL_H__ -#define __PJPP_POOL_H__ - -#include - -class Pj_Pool; -class Pj_Caching_Pool; - -// -// Base class for all Pjlib objects -// -class Pj_Object -{ -public: - void *operator new(unsigned int class_size, Pj_Pool *pool); - void *operator new(unsigned int class_size, Pj_Pool &pool); - - void operator delete(void*) - { - } - - void operator delete(void*, Pj_Pool*) - { - } - - void operator delete(void*, Pj_Pool&) - { - } - - // - // Inline implementations at the end of this file. - // - -private: - // Can not use normal new operator; must use pool. - // e.g.: - // obj = new(pool) Pj_The_Object(pool, ...); - // - void *operator new(unsigned int) - {} -}; - - -// -// Pool. -// -class Pj_Pool : public Pj_Object -{ -public: - // - // Default constructor, initializes internal pool to NULL. - // Application must call attach() some time later. - // - Pj_Pool() - : p_(NULL) - { - } - - // - // Create pool. - // - Pj_Pool(Pj_Caching_Pool &caching_pool, - pj_size_t initial_size, - pj_size_t increment_size, - const char *name = NULL, - pj_pool_callback *callback = NULL); - - // - // Construct from existing pool. - // - explicit Pj_Pool(pj_pool_t *pool) - : p_(pool) - { - } - - // - // Attach existing pool. - // - void attach(pj_pool_t *pool) - { - p_ = pool; - } - - // - // Destructor. - // - // Release pool back to factory. Remember: if you delete pool, then - // make sure that all objects that have been allocated from this pool - // have been properly destroyed. - // - // This is where C++ is trickier than plain C!! - // - ~Pj_Pool() - { - if (p_) - pj_pool_release(p_); - } - - // - // Get name. - // - const char *getobjname() const - { - return pj_pool_getobjname(p_); - } - - // - // Get pjlib compatible pool object. - // - pj_pool_t *pool_() - { - return p_; - } - - // - // Get pjlib compatible pool object. - // - const pj_pool_t *pool_() const - { - return p_; - } - - // - // Get pjlib compatible pool object. - // - pj_pool_t *pj_pool_t_() - { - return p_; - } - - // - // Reset pool. - // - void reset() - { - pj_pool_reset(p_); - } - - // - // Get current capacity. - // - pj_size_t get_capacity() - { - pj_pool_get_capacity(p_); - } - - // - // Get current total bytes allocated from the pool. - // - pj_size_t get_used_size() - { - pj_pool_get_used_size(p_); - } - - // - // Allocate. - // - void *alloc(pj_size_t size) - { - return pj_pool_alloc(p_, size); - } - - // - // Allocate elements and zero fill the memory. - // - void *calloc(pj_size_t count, pj_size_t elem) - { - return pj_pool_calloc(p_, count, elem); - } - - // - // Allocate and zero fill memory. - // - void *zalloc(pj_size_t size) - { - return pj_pool_zalloc(p_, size); - } - -private: - pj_pool_t *p_; -}; - - -// -// Caching pool. -// -class Pj_Caching_Pool -{ -public: - // - // Construct caching pool. - // - Pj_Caching_Pool( pj_size_t cache_capacity = 0, - const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy) - { - pj_caching_pool_init(&cp_, pol, cache_capacity); - } - - // - // Destroy caching pool. - // - ~Pj_Caching_Pool() - { - pj_caching_pool_destroy(&cp_); - } - - // - // Create pool. - // - pj_pool_t *create_pool( pj_size_t initial_size, - pj_size_t increment_size, - const char *name = NULL, - pj_pool_callback *callback = NULL) - { - return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, - initial_size, - increment_size, - callback); - } - -private: - pj_caching_pool cp_; -}; - -// -// Inlines for Pj_Object -// -inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool) -{ - return pool->alloc(class_size); -} -inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool) -{ - return pool.alloc(class_size); -} - -// -// Inlines for Pj_Pool -// -inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool, - pj_size_t initial_size, - pj_size_t increment_size, - const char *name, - pj_pool_callback *callback) -{ - p_ = caching_pool.create_pool(initial_size, increment_size, name, - callback); -} - - -#endif /* __PJPP_POOL_H__ */ + */ +#ifndef __PJPP_POOL_HPP__ +#define __PJPP_POOL_HPP__ + +#include + +class Pj_Pool; +class Pj_Caching_Pool; + +// +// Base class for all Pjlib objects +// +class Pj_Object +{ +public: + void *operator new(unsigned int class_size, Pj_Pool *pool); + void *operator new(unsigned int class_size, Pj_Pool &pool); + + void operator delete(void*) + { + } + + void operator delete(void*, Pj_Pool*) + { + } + + void operator delete(void*, Pj_Pool&) + { + } + + // + // Inline implementations at the end of this file. + // + +private: + // Can not use normal new operator; must use pool. + // e.g.: + // obj = new(pool) Pj_The_Object(pool, ...); + // + void *operator new(unsigned int) + {} +}; + + +// +// Pool. +// +class Pj_Pool : public Pj_Object +{ +public: + // + // Default constructor, initializes internal pool to NULL. + // Application must call attach() some time later. + // + Pj_Pool() + : p_(NULL) + { + } + + // + // Create pool. + // + Pj_Pool(Pj_Caching_Pool &caching_pool, + pj_size_t initial_size, + pj_size_t increment_size, + const char *name = NULL, + pj_pool_callback *callback = NULL); + + // + // Construct from existing pool. + // + explicit Pj_Pool(pj_pool_t *pool) + : p_(pool) + { + } + + // + // Attach existing pool. + // + void attach(pj_pool_t *pool) + { + p_ = pool; + } + + // + // Destructor. + // + // Release pool back to factory. Remember: if you delete pool, then + // make sure that all objects that have been allocated from this pool + // have been properly destroyed. + // + // This is where C++ is trickier than plain C!! + // + ~Pj_Pool() + { + if (p_) + pj_pool_release(p_); + } + + // + // Get name. + // + const char *getobjname() const + { + return pj_pool_getobjname(p_); + } + + // + // Get pjlib compatible pool object. + // + pj_pool_t *pool_() + { + return p_; + } + + // + // Get pjlib compatible pool object. + // + const pj_pool_t *pool_() const + { + return p_; + } + + // + // Get pjlib compatible pool object. + // + pj_pool_t *pj_pool_t_() + { + return p_; + } + + // + // Reset pool. + // + void reset() + { + pj_pool_reset(p_); + } + + // + // Get current capacity. + // + pj_size_t get_capacity() + { + pj_pool_get_capacity(p_); + } + + // + // Get current total bytes allocated from the pool. + // + pj_size_t get_used_size() + { + pj_pool_get_used_size(p_); + } + + // + // Allocate. + // + void *alloc(pj_size_t size) + { + return pj_pool_alloc(p_, size); + } + + // + // Allocate elements and zero fill the memory. + // + void *calloc(pj_size_t count, pj_size_t elem) + { + return pj_pool_calloc(p_, count, elem); + } + + // + // Allocate and zero fill memory. + // + void *zalloc(pj_size_t size) + { + return pj_pool_zalloc(p_, size); + } + +private: + pj_pool_t *p_; +}; + + +// +// Caching pool. +// +class Pj_Caching_Pool +{ +public: + // + // Construct caching pool. + // + Pj_Caching_Pool( pj_size_t cache_capacity = 0, + const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy) + { + pj_caching_pool_init(&cp_, pol, cache_capacity); + } + + // + // Destroy caching pool. + // + ~Pj_Caching_Pool() + { + pj_caching_pool_destroy(&cp_); + } + + // + // Create pool. + // + pj_pool_t *create_pool( pj_size_t initial_size, + pj_size_t increment_size, + const char *name = NULL, + pj_pool_callback *callback = NULL) + { + return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, + initial_size, + increment_size, + callback); + } + +private: + pj_caching_pool cp_; +}; + +// +// Inlines for Pj_Object +// +inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool) +{ + return pool->alloc(class_size); +} +inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool) +{ + return pool.alloc(class_size); +} + +// +// Inlines for Pj_Pool +// +inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool, + pj_size_t initial_size, + pj_size_t increment_size, + const char *name, + pj_pool_callback *callback) +{ + p_ = caching_pool.create_pool(initial_size, increment_size, name, + callback); +} + + +#endif /* __PJPP_POOL_HPP__ */ + diff --git a/pjlib/include/pj++/proactor.hpp b/pjlib/include/pj++/proactor.hpp index 891dd75d..73be85f4 100644 --- a/pjlib/include/pj++/proactor.hpp +++ b/pjlib/include/pj++/proactor.hpp @@ -1,500 +1,502 @@ /* $Id$ - */ -#ifndef __PJPP_PROACTOR_H__ -#define __PJPP_PROACTOR_H__ - -#include -#include -#include -#include -#include - -class Pj_Proactor; -class Pj_Event_Handler; - - -////////////////////////////////////////////////////////////////////////////// -// Asynchronous operation key. -// -// Applications may inheric this class to put their application -// specific data. -// -class Pj_Async_Op : public pj_ioqueue_op_key_t -{ -public: - // - // Construct with null handler. - // App must call set_handler() before use. - // - Pj_Async_Op() - : handler_(NULL) - { - } - - // - // Constructor. - // - explicit Pj_Async_Op(Pj_Event_Handler *handler) - : handler_(handler) - { - pj_memset(this, 0, sizeof(pj_ioqueue_op_key_t)); - } - - // - // Set handler. - // - void set_handler(Pj_Event_Handler *handler) - { - handler_ = handler; - } - - // - // Check whether operation is still pending for this key. - // - bool is_pending(); - - // - // Cancel the operation. - // - bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED); - -protected: - Pj_Event_Handler *handler_; -}; - - -////////////////////////////////////////////////////////////////////////////// -// Event handler. -// -// Applications should inherit this class to receive various event -// notifications. -// -// Applications should implement get_socket_handle(). -// -class Pj_Event_Handler : public Pj_Object -{ - friend class Pj_Proactor; -public: - // - // Default constructor. - // - Pj_Event_Handler() - : key_(NULL) - { - pj_memset(&timer_, 0, sizeof(timer_)); - timer_.user_data = this; - timer_.cb = &timer_callback; - } - - // - // Destroy. - // - virtual ~Pj_Event_Handler() - { - unregister(); - } - - // - // Unregister this handler from the ioqueue. - // - void unregister() - { - if (key_) { - pj_ioqueue_unregister(key_); - key_ = NULL; - } - } - - // - // Get socket handle associated with this. - // - virtual pj_sock_t get_socket_handle() - { - return PJ_INVALID_SOCKET; - } - - // - // Start async receive. - // - pj_status_t recv( Pj_Async_Op *op_key, - void *buf, pj_ssize_t *len, - unsigned flags) - { - return pj_ioqueue_recv( key_, op_key, - buf, len, flags); - } - - // - // Start async recvfrom() - // - pj_status_t recvfrom( Pj_Async_Op *op_key, - void *buf, pj_ssize_t *len, unsigned flags, - Pj_Inet_Addr *addr) - { - addr->addrlen_ = sizeof(Pj_Inet_Addr); - return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags, - addr, &addr->addrlen_ ); - } - - // - // Start async send() - // - pj_status_t send( Pj_Async_Op *op_key, - const void *data, pj_ssize_t *len, - unsigned flags) - { - return pj_ioqueue_send( key_, op_key, data, len, flags); - } - - // - // Start async sendto() - // - pj_status_t sendto( Pj_Async_Op *op_key, - const void *data, pj_ssize_t *len, unsigned flags, - const Pj_Inet_Addr &addr) - { - return pj_ioqueue_sendto(key_, op_key, data, len, flags, - &addr, sizeof(addr)); - } - -#if PJ_HAS_TCP - // - // Start async connect() - // - pj_status_t connect(const Pj_Inet_Addr &addr) - { - return pj_ioqueue_connect(key_, &addr, sizeof(addr)); - } - - // - // Start async accept(). - // - pj_status_t accept( Pj_Async_Op *op_key, - Pj_Socket *sock, - Pj_Inet_Addr *local = NULL, - Pj_Inet_Addr *remote = NULL) - { - int *addrlen = local ? &local->addrlen_ : NULL; - return pj_ioqueue_accept( key_, op_key, &sock->sock_, - local, remote, addrlen ); - } - -#endif - -protected: - ////////////////// - // Overridables - ////////////////// - - // - // Timeout callback. - // - virtual void on_timeout(int data) - { - } - - // - // On read complete callback. - // - virtual void on_read_complete( Pj_Async_Op *op_key, - pj_ssize_t bytes_read) - { - } - - // - // On write complete callback. - // - virtual void on_write_complete( Pj_Async_Op *op_key, - pj_ssize_t bytes_sent) - { - } - -#if PJ_HAS_TCP - // - // On connect complete callback. - // - virtual void on_connect_complete(pj_status_t status) - { - } - - // - // On new connection callback. - // - virtual void on_accept_complete( Pj_Async_Op *op_key, - pj_sock_t new_sock, - pj_status_t status) - { - } - -#endif - - -private: - pj_ioqueue_key_t *key_; - pj_timer_entry timer_; - - friend class Pj_Proactor; - friend class Pj_Async_Op; - - // - // Static timer callback. - // - static void timer_callback( pj_timer_heap_t *timer_heap, - struct pj_timer_entry *entry) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) entry->user_data; - - handler->on_timeout(entry->id); - } -}; - -inline bool Pj_Async_Op::is_pending() -{ - return pj_ioqueue_is_pending(handler_->key_, this) != 0; -} - -inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status) -{ - return pj_ioqueue_post_completion(handler_->key_, this, - bytes_status) == PJ_SUCCESS; -} - -////////////////////////////////////////////////////////////////////////////// -// Proactor -// -class Pj_Proactor : public Pj_Object -{ -public: - // - // Default constructor, initializes to NULL. - // - Pj_Proactor() - : ioq_(NULL), th_(NULL) - { - cb_.on_read_complete = &read_complete_cb; - cb_.on_write_complete = &write_complete_cb; - cb_.on_accept_complete = &accept_complete_cb; - cb_.on_connect_complete = &connect_complete_cb; - } - - // - // Construct proactor. - // - Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd, - pj_size_t max_timer_entries ) - : ioq_(NULL), th_(NULL) - { - cb_.on_read_complete = &read_complete_cb; - cb_.on_write_complete = &write_complete_cb; - cb_.on_accept_complete = &accept_complete_cb; - cb_.on_connect_complete = &connect_complete_cb; - - create(pool, max_fd, max_timer_entries); - } - - // - // Destructor. - // - ~Pj_Proactor() - { - destroy(); - } - - // - // Create proactor. - // - pj_status_t create( Pj_Pool *pool, pj_size_t max_fd, - pj_size_t timer_entry_count) - { - pj_status_t status; - - destroy(); - - status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_); - if (status != PJ_SUCCESS) - return status; - - status = pj_timer_heap_create(pool->pool_(), - timer_entry_count, &th_); - if (status != PJ_SUCCESS) { - pj_ioqueue_destroy(ioq_); - ioq_ = NULL; - return NULL; - } - - return status; - } - - // - // Destroy proactor. - // - void destroy() - { - if (ioq_) { - pj_ioqueue_destroy(ioq_); - ioq_ = NULL; - } - if (th_) { - pj_timer_heap_destroy(th_); - th_ = NULL; - } - } - - // - // Register handler. - // This will call handler->get_socket_handle() - // - pj_status_t register_socket_handler(Pj_Pool *pool, - Pj_Event_Handler *handler) - { - return pj_ioqueue_register_sock( pool->pool_(), ioq_, - handler->get_socket_handle(), - handler, &cb_, &handler->key_ ); - } - - // - // Unregister handler. - // - static void unregister_handler(Pj_Event_Handler *handler) - { - if (handler->key_) { - pj_ioqueue_unregister( handler->key_ ); - handler->key_ = NULL; - } - } - - // - // Scheduler timer. - // - bool schedule_timer( Pj_Event_Handler *handler, - const Pj_Time_Val &delay, - int id=-1) - { - return schedule_timer(th_, handler, delay, id); - } - - // - // Cancel timer. - // - bool cancel_timer(Pj_Event_Handler *handler) - { - return pj_timer_heap_cancel(th_, &handler->timer_) == 1; - } - - // - // Handle events. - // - int handle_events(Pj_Time_Val *max_timeout) - { - Pj_Time_Val timeout(0, 0); - int timer_count; - - timer_count = pj_timer_heap_poll( th_, &timeout ); - - if (timeout.get_sec() < 0) - timeout.sec = PJ_MAXINT32; - - /* If caller specifies maximum time to wait, then compare the value - * with the timeout to wait from timer, and use the minimum value. - */ - if (max_timeout && timeout >= *max_timeout) { - timeout = *max_timeout; - } - - /* Poll events in ioqueue. */ - int ioqueue_count; - - ioqueue_count = pj_ioqueue_poll(ioq_, &timeout); - if (ioqueue_count < 0) - return ioqueue_count; - - return ioqueue_count + timer_count; - } - - // - // Get the internal ioqueue object. - // - pj_ioqueue_t *get_io_queue() - { - return ioq_; - } - - // - // Get the internal timer heap object. - // - pj_timer_heap_t *get_timer_heap() - { - return th_; - } - -private: - pj_ioqueue_t *ioq_; - pj_timer_heap_t *th_; - pj_ioqueue_callback cb_; - - static bool schedule_timer( pj_timer_heap_t *timer, - Pj_Event_Handler *handler, - const Pj_Time_Val &delay, - int id=-1) - { - handler->timer_.id = id; - return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0; - } - - - // - // Static read completion callback. - // - static void read_complete_cb( pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_read) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read); - } - - // - // Static write completion callback. - // - static void write_complete_cb(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_sent) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent); - } - - // - // Static accept completion callback. - // - static void accept_complete_cb(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_sock_t new_sock, - pj_status_t status) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status); - } - - // - // Static connect completion callback. - // - static void connect_complete_cb(pj_ioqueue_key_t *key, - pj_status_t status) - { - Pj_Event_Handler *handler = - (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); - - handler->on_connect_complete(status); - } - -}; - -#endif /* __PJPP_PROACTOR_H__ */ + */ +#ifndef __PJPP_PROACTOR_HPP__ +#define __PJPP_PROACTOR_HPP__ + +#include +#include +#include +#include +#include + +class Pj_Proactor; +class Pj_Event_Handler; + + +////////////////////////////////////////////////////////////////////////////// +// Asynchronous operation key. +// +// Applications may inheric this class to put their application +// specific data. +// +class Pj_Async_Op : public pj_ioqueue_op_key_t +{ +public: + // + // Construct with null handler. + // App must call set_handler() before use. + // + Pj_Async_Op() + : handler_(NULL) + { + pj_ioqueue_op_key_init(this, sizeof(*this)); + } + + // + // Constructor. + // + explicit Pj_Async_Op(Pj_Event_Handler *handler) + : handler_(handler) + { + pj_ioqueue_op_key_init(this, sizeof(*this)); + } + + // + // Set handler. + // + void set_handler(Pj_Event_Handler *handler) + { + handler_ = handler; + } + + // + // Check whether operation is still pending for this key. + // + bool is_pending(); + + // + // Cancel the operation. + // + bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED); + +protected: + Pj_Event_Handler *handler_; +}; + + +////////////////////////////////////////////////////////////////////////////// +// Event handler. +// +// Applications should inherit this class to receive various event +// notifications. +// +// Applications should implement get_socket_handle(). +// +class Pj_Event_Handler : public Pj_Object +{ + friend class Pj_Proactor; +public: + // + // Default constructor. + // + Pj_Event_Handler() + : key_(NULL) + { + pj_memset(&timer_, 0, sizeof(timer_)); + timer_.user_data = this; + timer_.cb = &timer_callback; + } + + // + // Destroy. + // + virtual ~Pj_Event_Handler() + { + unregister(); + } + + // + // Unregister this handler from the ioqueue. + // + void unregister() + { + if (key_) { + pj_ioqueue_unregister(key_); + key_ = NULL; + } + } + + // + // Get socket handle associated with this. + // + virtual pj_sock_t get_socket_handle() + { + return PJ_INVALID_SOCKET; + } + + // + // Start async receive. + // + pj_status_t recv( Pj_Async_Op *op_key, + void *buf, pj_ssize_t *len, + unsigned flags) + { + return pj_ioqueue_recv( key_, op_key, + buf, len, flags); + } + + // + // Start async recvfrom() + // + pj_status_t recvfrom( Pj_Async_Op *op_key, + void *buf, pj_ssize_t *len, unsigned flags, + Pj_Inet_Addr *addr) + { + addr->addrlen_ = sizeof(Pj_Inet_Addr); + return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags, + addr, &addr->addrlen_ ); + } + + // + // Start async send() + // + pj_status_t send( Pj_Async_Op *op_key, + const void *data, pj_ssize_t *len, + unsigned flags) + { + return pj_ioqueue_send( key_, op_key, data, len, flags); + } + + // + // Start async sendto() + // + pj_status_t sendto( Pj_Async_Op *op_key, + const void *data, pj_ssize_t *len, unsigned flags, + const Pj_Inet_Addr &addr) + { + return pj_ioqueue_sendto(key_, op_key, data, len, flags, + &addr, sizeof(addr)); + } + +#if PJ_HAS_TCP + // + // Start async connect() + // + pj_status_t connect(const Pj_Inet_Addr &addr) + { + return pj_ioqueue_connect(key_, &addr, sizeof(addr)); + } + + // + // Start async accept(). + // + pj_status_t accept( Pj_Async_Op *op_key, + Pj_Socket *sock, + Pj_Inet_Addr *local = NULL, + Pj_Inet_Addr *remote = NULL) + { + int *addrlen = local ? &local->addrlen_ : NULL; + return pj_ioqueue_accept( key_, op_key, &sock->sock_, + local, remote, addrlen ); + } + +#endif + +protected: + ////////////////// + // Overridables + ////////////////// + + // + // Timeout callback. + // + virtual void on_timeout(int data) + { + } + + // + // On read complete callback. + // + virtual void on_read_complete( Pj_Async_Op *op_key, + pj_ssize_t bytes_read) + { + } + + // + // On write complete callback. + // + virtual void on_write_complete( Pj_Async_Op *op_key, + pj_ssize_t bytes_sent) + { + } + +#if PJ_HAS_TCP + // + // On connect complete callback. + // + virtual void on_connect_complete(pj_status_t status) + { + } + + // + // On new connection callback. + // + virtual void on_accept_complete( Pj_Async_Op *op_key, + pj_sock_t new_sock, + pj_status_t status) + { + } + +#endif + + +private: + pj_ioqueue_key_t *key_; + pj_timer_entry timer_; + + friend class Pj_Proactor; + friend class Pj_Async_Op; + + // + // Static timer callback. + // + static void timer_callback( pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) + { + Pj_Event_Handler *handler = + (Pj_Event_Handler*) entry->user_data; + + handler->on_timeout(entry->id); + } +}; + +inline bool Pj_Async_Op::is_pending() +{ + return pj_ioqueue_is_pending(handler_->key_, this) != 0; +} + +inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status) +{ + return pj_ioqueue_post_completion(handler_->key_, this, + bytes_status) == PJ_SUCCESS; +} + +////////////////////////////////////////////////////////////////////////////// +// Proactor +// +class Pj_Proactor : public Pj_Object +{ +public: + // + // Default constructor, initializes to NULL. + // + Pj_Proactor() + : ioq_(NULL), th_(NULL) + { + cb_.on_read_complete = &read_complete_cb; + cb_.on_write_complete = &write_complete_cb; + cb_.on_accept_complete = &accept_complete_cb; + cb_.on_connect_complete = &connect_complete_cb; + } + + // + // Construct proactor. + // + Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd, + pj_size_t max_timer_entries ) + : ioq_(NULL), th_(NULL) + { + cb_.on_read_complete = &read_complete_cb; + cb_.on_write_complete = &write_complete_cb; + cb_.on_accept_complete = &accept_complete_cb; + cb_.on_connect_complete = &connect_complete_cb; + + create(pool, max_fd, max_timer_entries); + } + + // + // Destructor. + // + ~Pj_Proactor() + { + destroy(); + } + + // + // Create proactor. + // + pj_status_t create( Pj_Pool *pool, pj_size_t max_fd, + pj_size_t timer_entry_count) + { + pj_status_t status; + + destroy(); + + status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_); + if (status != PJ_SUCCESS) + return status; + + status = pj_timer_heap_create(pool->pool_(), + timer_entry_count, &th_); + if (status != PJ_SUCCESS) { + pj_ioqueue_destroy(ioq_); + ioq_ = NULL; + return NULL; + } + + return status; + } + + // + // Destroy proactor. + // + void destroy() + { + if (ioq_) { + pj_ioqueue_destroy(ioq_); + ioq_ = NULL; + } + if (th_) { + pj_timer_heap_destroy(th_); + th_ = NULL; + } + } + + // + // Register handler. + // This will call handler->get_socket_handle() + // + pj_status_t register_socket_handler(Pj_Pool *pool, + Pj_Event_Handler *handler) + { + return pj_ioqueue_register_sock( pool->pool_(), ioq_, + handler->get_socket_handle(), + handler, &cb_, &handler->key_ ); + } + + // + // Unregister handler. + // + static void unregister_handler(Pj_Event_Handler *handler) + { + if (handler->key_) { + pj_ioqueue_unregister( handler->key_ ); + handler->key_ = NULL; + } + } + + // + // Scheduler timer. + // + bool schedule_timer( Pj_Event_Handler *handler, + const Pj_Time_Val &delay, + int id=-1) + { + return schedule_timer(th_, handler, delay, id); + } + + // + // Cancel timer. + // + bool cancel_timer(Pj_Event_Handler *handler) + { + return pj_timer_heap_cancel(th_, &handler->timer_) == 1; + } + + // + // Handle events. + // + int handle_events(Pj_Time_Val *max_timeout) + { + Pj_Time_Val timeout(0, 0); + int timer_count; + + timer_count = pj_timer_heap_poll( th_, &timeout ); + + if (timeout.get_sec() < 0) + timeout.sec = PJ_MAXINT32; + + /* If caller specifies maximum time to wait, then compare the value + * with the timeout to wait from timer, and use the minimum value. + */ + if (max_timeout && timeout >= *max_timeout) { + timeout = *max_timeout; + } + + /* Poll events in ioqueue. */ + int ioqueue_count; + + ioqueue_count = pj_ioqueue_poll(ioq_, &timeout); + if (ioqueue_count < 0) + return ioqueue_count; + + return ioqueue_count + timer_count; + } + + // + // Get the internal ioqueue object. + // + pj_ioqueue_t *get_io_queue() + { + return ioq_; + } + + // + // Get the internal timer heap object. + // + pj_timer_heap_t *get_timer_heap() + { + return th_; + } + +private: + pj_ioqueue_t *ioq_; + pj_timer_heap_t *th_; + pj_ioqueue_callback cb_; + + static bool schedule_timer( pj_timer_heap_t *timer, + Pj_Event_Handler *handler, + const Pj_Time_Val &delay, + int id=-1) + { + handler->timer_.id = id; + return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0; + } + + + // + // Static read completion callback. + // + static void read_complete_cb( pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_read) + { + Pj_Event_Handler *handler = + (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); + + handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read); + } + + // + // Static write completion callback. + // + static void write_complete_cb(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_sent) + { + Pj_Event_Handler *handler = + (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); + + handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent); + } + + // + // Static accept completion callback. + // + static void accept_complete_cb(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_sock_t new_sock, + pj_status_t status) + { + Pj_Event_Handler *handler = + (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); + + handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status); + } + + // + // Static connect completion callback. + // + static void connect_complete_cb(pj_ioqueue_key_t *key, + pj_status_t status) + { + Pj_Event_Handler *handler = + (Pj_Event_Handler*) pj_ioqueue_get_user_data(key); + + handler->on_connect_complete(status); + } + +}; + +#endif /* __PJPP_PROACTOR_HPP__ */ + diff --git a/pjlib/include/pj++/scanner.hpp b/pjlib/include/pj++/scanner.hpp index 9ddac097..8a3d9897 100644 --- a/pjlib/include/pj++/scanner.hpp +++ b/pjlib/include/pj++/scanner.hpp @@ -1,173 +1,173 @@ /* $Id$ - * - */ -#ifndef __PJPP_SCANNER_H__ -#define __PJPP_SCANNER_H__ - -#include -#include - -class Pj_Char_Spec -{ -public: - Pj_Char_Spec() { pj_cs_init(cs__); } - - void set(int c) { pj_cs_set(cs__, c); } - void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); } - void add_alpha() { pj_cs_add_alpha(cs__); } - void add_num() { pj_cs_add_num(cs__); } - void add_str(const char *str) { pj_cs_add_str(cs__, str); } - void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); } - void del_str(const char *str) { pj_cs_del_str(cs__, str); } - void invert() { pj_cs_invert(cs__); } - int match(int c) { return pj_cs_match(cs__, c); } - - pj_char_spec_element_t *cs_() - { - return cs__; - } - - const pj_char_spec_element_t *cs_() const - { - return cs__; - } - -private: - pj_char_spec cs__; -}; - -class Pj_Scanner -{ -public: - Pj_Scanner() {} - - enum - { - SYNTAX_ERROR = 101 - }; - static void syntax_error_handler_throw_pj(pj_scanner *); - - typedef pj_scan_state State; - - void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS, - pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj) - { - pj_scan_init(&scanner_, buf, len, options, callback); - } - - void fini() - { - pj_scan_fini(&scanner_); - } - - int eof() const - { - return pj_scan_is_eof(&scanner_); - } - - int peek_char() const - { - return *scanner_.curptr; - } - - int peek(const Pj_Char_Spec *cs, Pj_String *out) - { - return pj_scan_peek(&scanner_, cs->cs_(), out); - } - - int peek_n(pj_size_t len, Pj_String *out) - { - return pj_scan_peek_n(&scanner_, len, out); - } - - int peek_until(const Pj_Char_Spec *cs, Pj_String *out) - { - return pj_scan_peek_until(&scanner_, cs->cs_(), out); - } - - void get(const Pj_Char_Spec *cs, Pj_String *out) - { - pj_scan_get(&scanner_, cs->cs_(), out); - } - - void get_n(unsigned N, Pj_String *out) - { - pj_scan_get_n(&scanner_, N, out); - } - - int get_char() - { - return pj_scan_get_char(&scanner_); - } - - void get_quote(int begin_quote, int end_quote, Pj_String *out) - { - pj_scan_get_quote(&scanner_, begin_quote, end_quote, out); - } - - void get_newline() - { - pj_scan_get_newline(&scanner_); - } - - void get_until(const Pj_Char_Spec *cs, Pj_String *out) - { - pj_scan_get_until(&scanner_, cs->cs_(), out); - } - - void get_until_ch(int until_ch, Pj_String *out) - { - pj_scan_get_until_ch(&scanner_, until_ch, out); - } - - void get_until_chr(const char *spec, Pj_String *out) - { - pj_scan_get_until_chr(&scanner_, spec, out); - } - - void advance_n(unsigned N, bool skip_ws=true) - { - pj_scan_advance_n(&scanner_, N, skip_ws); - } - - int strcmp(const char *s, int len) - { - return pj_scan_strcmp(&scanner_, s, len); - } - - int stricmp(const char *s, int len) - { - return pj_scan_stricmp(&scanner_, s, len); - } - - void skip_ws() - { - pj_scan_skip_whitespace(&scanner_); - } - - void save_state(State *state) - { - pj_scan_save_state(&scanner_, state); - } - - void restore_state(State *state) - { - pj_scan_restore_state(&scanner_, state); - } - - int get_pos_line() const - { - return scanner_.line; - } - - int get_pos_col() const - { - return scanner_.col; - } - - -private: - pj_scanner scanner_; -}; - -#endif /* __PJPP_SCANNER_H__ */ + */ +#ifndef __PJPP_SCANNER_HPP__ +#define __PJPP_SCANNER_HPP__ + +#include +#include + +class Pj_Char_Spec +{ +public: + Pj_Char_Spec() { pj_cs_init(cs__); } + + void set(int c) { pj_cs_set(cs__, c); } + void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); } + void add_alpha() { pj_cs_add_alpha(cs__); } + void add_num() { pj_cs_add_num(cs__); } + void add_str(const char *str) { pj_cs_add_str(cs__, str); } + void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); } + void del_str(const char *str) { pj_cs_del_str(cs__, str); } + void invert() { pj_cs_invert(cs__); } + int match(int c) { return pj_cs_match(cs__, c); } + + pj_char_spec_element_t *cs_() + { + return cs__; + } + + const pj_char_spec_element_t *cs_() const + { + return cs__; + } + +private: + pj_char_spec cs__; +}; + +class Pj_Scanner +{ +public: + Pj_Scanner() {} + + enum + { + SYNTAX_ERROR = 101 + }; + static void syntax_error_handler_throw_pj(pj_scanner *); + + typedef pj_scan_state State; + + void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS, + pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj) + { + pj_scan_init(&scanner_, buf, len, options, callback); + } + + void fini() + { + pj_scan_fini(&scanner_); + } + + int eof() const + { + return pj_scan_is_eof(&scanner_); + } + + int peek_char() const + { + return *scanner_.curptr; + } + + int peek(const Pj_Char_Spec *cs, Pj_String *out) + { + return pj_scan_peek(&scanner_, cs->cs_(), out); + } + + int peek_n(pj_size_t len, Pj_String *out) + { + return pj_scan_peek_n(&scanner_, len, out); + } + + int peek_until(const Pj_Char_Spec *cs, Pj_String *out) + { + return pj_scan_peek_until(&scanner_, cs->cs_(), out); + } + + void get(const Pj_Char_Spec *cs, Pj_String *out) + { + pj_scan_get(&scanner_, cs->cs_(), out); + } + + void get_n(unsigned N, Pj_String *out) + { + pj_scan_get_n(&scanner_, N, out); + } + + int get_char() + { + return pj_scan_get_char(&scanner_); + } + + void get_quote(int begin_quote, int end_quote, Pj_String *out) + { + pj_scan_get_quote(&scanner_, begin_quote, end_quote, out); + } + + void get_newline() + { + pj_scan_get_newline(&scanner_); + } + + void get_until(const Pj_Char_Spec *cs, Pj_String *out) + { + pj_scan_get_until(&scanner_, cs->cs_(), out); + } + + void get_until_ch(int until_ch, Pj_String *out) + { + pj_scan_get_until_ch(&scanner_, until_ch, out); + } + + void get_until_chr(const char *spec, Pj_String *out) + { + pj_scan_get_until_chr(&scanner_, spec, out); + } + + void advance_n(unsigned N, bool skip_ws=true) + { + pj_scan_advance_n(&scanner_, N, skip_ws); + } + + int strcmp(const char *s, int len) + { + return pj_scan_strcmp(&scanner_, s, len); + } + + int stricmp(const char *s, int len) + { + return pj_scan_stricmp(&scanner_, s, len); + } + + void skip_ws() + { + pj_scan_skip_whitespace(&scanner_); + } + + void save_state(State *state) + { + pj_scan_save_state(&scanner_, state); + } + + void restore_state(State *state) + { + pj_scan_restore_state(&scanner_, state); + } + + int get_pos_line() const + { + return scanner_.line; + } + + int get_pos_col() const + { + return scanner_.col; + } + + +private: + pj_scanner scanner_; +}; + +#endif /* __PJPP_SCANNER_HPP__ */ + diff --git a/pjlib/include/pj++/sock.hpp b/pjlib/include/pj++/sock.hpp index 1c6c2dd9..f1a1e45f 100644 --- a/pjlib/include/pj++/sock.hpp +++ b/pjlib/include/pj++/sock.hpp @@ -1,426 +1,427 @@ /* $Id$ - */ -#ifndef __PJPP_SOCK_H__ -#define __PJPP_SOCK_H__ - -#include -#include - -class Pj_Event_Handler; - -// -// Base class for address. -// -class Pj_Addr -{ -}; - -// -// Internet address. -// -class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr -{ -public: - // - // Get port number. - // - pj_uint16_t get_port_number() const - { - return pj_sockaddr_in_get_port(this); - } - - // - // Set port number. - // - void set_port_number(pj_uint16_t port) - { - sin_family = PJ_AF_INET; - pj_sockaddr_in_set_port(this, port); - } - - // - // Get IP address. - // - pj_uint32_t get_ip_address() const - { - return pj_sockaddr_in_get_addr(this).s_addr; - } - - // - // Get address string. - // - const char *get_address() const - { - return pj_inet_ntoa(sin_addr); - } - - // - // Set IP address. - // - void set_ip_address(pj_uint32_t addr) - { - sin_family = PJ_AF_INET; - pj_sockaddr_in_set_addr(this, addr); - } - - // - // Set address. - // - pj_status_t set_address(const pj_str_t *addr) - { - return pj_sockaddr_in_set_str_addr(this, addr); - } - - // - // Set address. - // - pj_status_t set_address(const char *addr) - { - pj_str_t s; - return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr)); - } - - // - // Compare for equality. - // - bool operator==(const Pj_Inet_Addr &rhs) const - { - return sin_family == rhs.sin_family && - sin_addr.s_addr == rhs.sin_addr.s_addr && - sin_port == rhs.sin_port; - } - -private: - // - // Dummy length used in pj_ioqueue_recvfrom() etc - // - friend class Pj_Event_Handler; - friend class Pj_Socket; - friend class Pj_Sock_Stream; - friend class Pj_Sock_Dgram; - - int addrlen_; -}; - - -// -// Socket base class. -// -// Note: -// socket will not automatically be closed on destructor. -// -class Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Socket() - : sock_(PJ_INVALID_SOCKET) - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Socket(pj_sock_t sock) - : sock_(sock) - { - } - - // - // Copy constructor. - // - Pj_Socket(const Pj_Socket &rhs) - : sock_(rhs.sock_) - { - } - - // - // Destructor will not close the socket. - // You must call close() explicitly. - // - ~Pj_Socket() - { - } - - // - // Set socket handle. - // - void set_handle(pj_sock_t sock) - { - sock_ = sock; - } - - // - // Get socket handle. - // - pj_sock_t get_handle() const - { - return sock_; - } - - // - // Get socket handle. - // - pj_sock_t& get_handle() - { - return sock_; - } - - // - // See if the socket is valid. - // - bool is_valid() const - { - return sock_ != PJ_INVALID_SOCKET; - } - - // - // Create the socket. - // - pj_status_t create(int af, int type, int proto) - { - return pj_sock_socket(af, type, proto, &sock_); - } - - // - // Bind socket. - // - pj_status_t bind(const Pj_Inet_Addr &addr) - { - return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr)); - } - - // - // Close socket. - // - pj_status_t close() - { - pj_sock_close(sock_); - } - - // - // Get peer socket name. - // - pj_status_t getpeername(Pj_Inet_Addr *addr) - { - return pj_sock_getpeername(sock_, addr, &addr->addrlen_); - } - - // - // getsockname - // - pj_status_t getsockname(Pj_Inet_Addr *addr) - { - return pj_sock_getsockname(sock_, addr, &addr->addrlen_); - } - - // - // getsockopt. - // - pj_status_t getsockopt(int level, int optname, - void *optval, int *optlen) - { - return pj_sock_getsockopt(sock_, level, optname, optval, optlen); - } - - // - // setsockopt - // - pj_status_t setsockopt(int level, int optname, - const void *optval, int optlen) - { - return pj_sock_setsockopt(sock_, level, optname, optval, optlen); - } - - // - // receive data. - // - pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0) - { - pj_ssize_t bytes = len; - if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // send data. - // - pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0) - { - pj_ssize_t bytes = len; - if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS) - return -1; - return bytes; - } - - // - // connect. - // - pj_status_t connect(const Pj_Inet_Addr &addr) - { - return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr)); - } - - // - // assignment. - // - Pj_Socket &operator=(const Pj_Socket &rhs) - { - sock_ = rhs.sock_; - return *this; - } - -protected: - friend class Pj_Event_Handler; - pj_sock_t sock_; -}; - - -#if PJ_HAS_TCP -// -// Stream socket. -// -class Pj_Sock_Stream : public Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Sock_Stream() - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Sock_Stream(pj_sock_t sock) - : Pj_Socket(sock) - { - } - - // - // Copy constructor. - // - Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs) - { - } - - // - // Assignment. - // - Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs) - { - sock_ = rhs.sock_; - return *this; - } - - // - // listen() - // - pj_status_t listen(int backlog = 5) - { - return pj_sock_listen(sock_, backlog); - } - - // - // blocking accept() - // - Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL) - { - pj_sock_t newsock; - int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL; - pj_status_t status; - - status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen); - if (status != PJ_SUCCESS) - return Pj_Sock_Stream(-1); - - return Pj_Sock_Stream(newsock); - } - - // - // shutdown() - // - pj_status_t shutdown(int how = PJ_SHUT_RDWR) - { - return pj_sock_shutdown(sock_, how); - } - -}; -#endif - -// -// Datagram socket. -// -class Pj_Sock_Dgram : public Pj_Socket -{ -public: - // - // Default constructor. - // - Pj_Sock_Dgram() - { - } - - // - // Initialize from a socket handle. - // - explicit Pj_Sock_Dgram(pj_sock_t sock) - : Pj_Socket(sock) - { - } - - // - // Copy constructor. - // - Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs) - : Pj_Socket(rhs) - { - } - - // - // Assignment. - // - Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs) - { - Pj_Socket::operator =(rhs); - return *this; - } - - // - // recvfrom() - // - pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0, - Pj_Inet_Addr *fromaddr = NULL) - { - pj_ssize_t bytes = len; - int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL; - if (pj_sock_recvfrom( sock_, buf, &bytes, flag, - fromaddr, addrlen) != PJ_SUCCESS) - { - return -1; - } - return bytes; - } - - // - // sendto() - // - pj_ssize_t sendto( const void *buf, pj_size_t len, int flag, - const Pj_Inet_Addr &addr) - { - pj_ssize_t bytes = len; - if (pj_sock_sendto( sock_, buf, &bytes, flag, - &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS) - { - return -1; - } - return bytes; - } -}; - - -#endif /* __PJPP_SOCK_H__ */ + */ +#ifndef __PJPP_SOCK_HPP__ +#define __PJPP_SOCK_HPP__ + +#include +#include + +class Pj_Event_Handler; + +// +// Base class for address. +// +class Pj_Addr +{ +}; + +// +// Internet address. +// +class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr +{ +public: + // + // Get port number. + // + pj_uint16_t get_port_number() const + { + return pj_sockaddr_in_get_port(this); + } + + // + // Set port number. + // + void set_port_number(pj_uint16_t port) + { + sin_family = PJ_AF_INET; + pj_sockaddr_in_set_port(this, port); + } + + // + // Get IP address. + // + pj_uint32_t get_ip_address() const + { + return pj_sockaddr_in_get_addr(this).s_addr; + } + + // + // Get address string. + // + const char *get_address() const + { + return pj_inet_ntoa(sin_addr); + } + + // + // Set IP address. + // + void set_ip_address(pj_uint32_t addr) + { + sin_family = PJ_AF_INET; + pj_sockaddr_in_set_addr(this, addr); + } + + // + // Set address. + // + pj_status_t set_address(const pj_str_t *addr) + { + return pj_sockaddr_in_set_str_addr(this, addr); + } + + // + // Set address. + // + pj_status_t set_address(const char *addr) + { + pj_str_t s; + return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr)); + } + + // + // Compare for equality. + // + bool operator==(const Pj_Inet_Addr &rhs) const + { + return sin_family == rhs.sin_family && + sin_addr.s_addr == rhs.sin_addr.s_addr && + sin_port == rhs.sin_port; + } + +private: + // + // Dummy length used in pj_ioqueue_recvfrom() etc + // + friend class Pj_Event_Handler; + friend class Pj_Socket; + friend class Pj_Sock_Stream; + friend class Pj_Sock_Dgram; + + int addrlen_; +}; + + +// +// Socket base class. +// +// Note: +// socket will not automatically be closed on destructor. +// +class Pj_Socket +{ +public: + // + // Default constructor. + // + Pj_Socket() + : sock_(PJ_INVALID_SOCKET) + { + } + + // + // Initialize from a socket handle. + // + explicit Pj_Socket(pj_sock_t sock) + : sock_(sock) + { + } + + // + // Copy constructor. + // + Pj_Socket(const Pj_Socket &rhs) + : sock_(rhs.sock_) + { + } + + // + // Destructor will not close the socket. + // You must call close() explicitly. + // + ~Pj_Socket() + { + } + + // + // Set socket handle. + // + void set_handle(pj_sock_t sock) + { + sock_ = sock; + } + + // + // Get socket handle. + // + pj_sock_t get_handle() const + { + return sock_; + } + + // + // Get socket handle. + // + pj_sock_t& get_handle() + { + return sock_; + } + + // + // See if the socket is valid. + // + bool is_valid() const + { + return sock_ != PJ_INVALID_SOCKET; + } + + // + // Create the socket. + // + pj_status_t create(int af, int type, int proto) + { + return pj_sock_socket(af, type, proto, &sock_); + } + + // + // Bind socket. + // + pj_status_t bind(const Pj_Inet_Addr &addr) + { + return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr)); + } + + // + // Close socket. + // + pj_status_t close() + { + pj_sock_close(sock_); + } + + // + // Get peer socket name. + // + pj_status_t getpeername(Pj_Inet_Addr *addr) + { + return pj_sock_getpeername(sock_, addr, &addr->addrlen_); + } + + // + // getsockname + // + pj_status_t getsockname(Pj_Inet_Addr *addr) + { + return pj_sock_getsockname(sock_, addr, &addr->addrlen_); + } + + // + // getsockopt. + // + pj_status_t getsockopt(int level, int optname, + void *optval, int *optlen) + { + return pj_sock_getsockopt(sock_, level, optname, optval, optlen); + } + + // + // setsockopt + // + pj_status_t setsockopt(int level, int optname, + const void *optval, int optlen) + { + return pj_sock_setsockopt(sock_, level, optname, optval, optlen); + } + + // + // receive data. + // + pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0) + { + pj_ssize_t bytes = len; + if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS) + return -1; + return bytes; + } + + // + // send data. + // + pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0) + { + pj_ssize_t bytes = len; + if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS) + return -1; + return bytes; + } + + // + // connect. + // + pj_status_t connect(const Pj_Inet_Addr &addr) + { + return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr)); + } + + // + // assignment. + // + Pj_Socket &operator=(const Pj_Socket &rhs) + { + sock_ = rhs.sock_; + return *this; + } + +protected: + friend class Pj_Event_Handler; + pj_sock_t sock_; +}; + + +#if PJ_HAS_TCP +// +// Stream socket. +// +class Pj_Sock_Stream : public Pj_Socket +{ +public: + // + // Default constructor. + // + Pj_Sock_Stream() + { + } + + // + // Initialize from a socket handle. + // + explicit Pj_Sock_Stream(pj_sock_t sock) + : Pj_Socket(sock) + { + } + + // + // Copy constructor. + // + Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs) + { + } + + // + // Assignment. + // + Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs) + { + sock_ = rhs.sock_; + return *this; + } + + // + // listen() + // + pj_status_t listen(int backlog = 5) + { + return pj_sock_listen(sock_, backlog); + } + + // + // blocking accept() + // + Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL) + { + pj_sock_t newsock; + int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL; + pj_status_t status; + + status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen); + if (status != PJ_SUCCESS) + return Pj_Sock_Stream(-1); + + return Pj_Sock_Stream(newsock); + } + + // + // shutdown() + // + pj_status_t shutdown(int how = PJ_SHUT_RDWR) + { + return pj_sock_shutdown(sock_, how); + } + +}; +#endif + +// +// Datagram socket. +// +class Pj_Sock_Dgram : public Pj_Socket +{ +public: + // + // Default constructor. + // + Pj_Sock_Dgram() + { + } + + // + // Initialize from a socket handle. + // + explicit Pj_Sock_Dgram(pj_sock_t sock) + : Pj_Socket(sock) + { + } + + // + // Copy constructor. + // + Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs) + : Pj_Socket(rhs) + { + } + + // + // Assignment. + // + Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs) + { + Pj_Socket::operator =(rhs); + return *this; + } + + // + // recvfrom() + // + pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0, + Pj_Inet_Addr *fromaddr = NULL) + { + pj_ssize_t bytes = len; + int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL; + if (pj_sock_recvfrom( sock_, buf, &bytes, flag, + fromaddr, addrlen) != PJ_SUCCESS) + { + return -1; + } + return bytes; + } + + // + // sendto() + // + pj_ssize_t sendto( const void *buf, pj_size_t len, int flag, + const Pj_Inet_Addr &addr) + { + pj_ssize_t bytes = len; + if (pj_sock_sendto( sock_, buf, &bytes, flag, + &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS) + { + return -1; + } + return bytes; + } +}; + + +#endif /* __PJPP_SOCK_HPP__ */ + diff --git a/pjlib/include/pj++/string.hpp b/pjlib/include/pj++/string.hpp index 456e1ff3..6be1e50a 100644 --- a/pjlib/include/pj++/string.hpp +++ b/pjlib/include/pj++/string.hpp @@ -1,408 +1,409 @@ /* $Id$ - */ -#ifndef __PJPP_STRING_H__ -#define __PJPP_STRING_H__ - -#include -#include -#include - -// -// String wrapper class for pj_str_t. -// -class Pj_String : public pj_str_t -{ -public: - // - // Default constructor. - // - Pj_String() - { - pj_assert(sizeof(Pj_String) == sizeof(pj_str_t)); - ptr=NULL; - slen=0; - } - - // - // Construct the buffer from a char*. - // - explicit Pj_String(char *str) - { - set(str); - } - - // - // Construct from a const char*. - // - Pj_String(Pj_Pool *pool, const char *src) - { - set(pool, src); - } - - // - // Construct from pj_str_t*. - // - explicit Pj_String(pj_str_t *s) - { - set(s); - } - - // - // Construct by copying from const pj_str_t*. - // - Pj_String(Pj_Pool *pool, const pj_str_t *s) - { - set(pool, s); - } - - // - // Construct from another Pj_String - // - explicit Pj_String(Pj_String &rhs) - { - set(rhs); - } - - // - // Construct by copying from Pj_String - // - Pj_String(Pj_Pool *pool, const Pj_String &rhs) - { - set(pool, rhs); - } - - // - // Construct from a char* and a length. - // - Pj_String(char *str, pj_size_t len) - { - set(str, len); - } - - // - // Construct from pair of pointer. - // - Pj_String(char *begin, char *end) - { - pj_strset3(this, begin, end); - } - - // - // Get the length of the string. - // - pj_size_t length() const - { - return pj_strlen(this); - } - - // - // Get the length of the string. - // - pj_size_t size() const - { - return length(); - } - - // - // Get the string buffer. - // - const char *buf() const - { - return ptr; - } - - // - // Initialize buffer from char*. - // - void set(char *str) - { - pj_strset2(this, str); - } - - // - // Initialize by copying from a const char*. - // - void set(Pj_Pool *pool, const char *s) - { - pj_strdup2(pool->pool_(), this, s); - } - - // - // Initialize from pj_str_t*. - // - void set(pj_str_t *s) - { - pj_strassign(this, s); - } - - // - // Initialize by copying from const pj_str_t*. - // - void set(Pj_Pool *pool, const pj_str_t *s) - { - pj_strdup(pool->pool_(), this, s); - } - - // - // Initialize from char* and length. - // - void set(char *str, pj_size_t len) - { - pj_strset(this, str, len); - } - - // - // Initialize from pair of pointers. - // - void set(char *begin, char *end) - { - pj_strset3(this, begin, end); - } - - // - // Initialize from other Pj_String. - // - void set(Pj_String &rhs) - { - pj_strassign(this, &rhs); - } - - // - // Initialize by copying from a Pj_String*. - // - void set(Pj_Pool *pool, const Pj_String *s) - { - pj_strdup(pool->pool_(), this, s); - } - - // - // Initialize by copying from other Pj_String. - // - void set(Pj_Pool *pool, const Pj_String &s) - { - pj_strdup(pool->pool_(), this, &s); - } - - // - // Copy the contents of other string. - // - void strcpy(const pj_str_t *s) - { - pj_strcpy(this, s); - } - - // - // Copy the contents of other string. - // - void strcpy(const Pj_String &rhs) - { - pj_strcpy(this, &rhs); - } - - // - // Copy the contents of other string. - // - void strcpy(const char *s) - { - pj_strcpy2(this, s); - } - - // - // Compare string. - // - int strcmp(const char *s) const - { - return pj_strcmp2(this, s); - } - - // - // Compare string. - // - int strcmp(const pj_str_t *s) const - { - return pj_strcmp(this, s); - } - - // - // Compare string. - // - int strcmp(const Pj_String &rhs) const - { - return pj_strcmp(this, &rhs); - } - - // - // Compare string. - // - int strncmp(const char *s, pj_size_t len) const - { - return pj_strncmp2(this, s, len); - } - - // - // Compare string. - // - int strncmp(const pj_str_t *s, pj_size_t len) const - { - return pj_strncmp(this, s, len); - } - - // - // Compare string. - // - int strncmp(const Pj_String &rhs, pj_size_t len) const - { - return pj_strncmp(this, &rhs, len); - } - - // - // Compare string. - // - int stricmp(const char *s) const - { - return pj_stricmp2(this, s); - } - - // - // Compare string. - // - int stricmp(const pj_str_t *s) const - { - return pj_stricmp(this, s); - } - - // - // Compare string. - // - int stricmp(const Pj_String &rhs) const - { - return stricmp(&rhs); - } - - // - // Compare string. - // - int strnicmp(const char *s, pj_size_t len) const - { - return pj_strnicmp2(this, s, len); - } - - // - // Compare string. - // - int strnicmp(const pj_str_t *s, pj_size_t len) const - { - return pj_strnicmp(this, s, len); - } - - // - // Compare string. - // - int strnicmp(const Pj_String &rhs, pj_size_t len) const - { - return strnicmp(&rhs, len); - } - - // - // Compare contents for equality. - // - bool operator==(const char *s) const - { - return strcmp(s) == 0; - } - - // - // Compare contents for equality. - // - bool operator==(const pj_str_t *s) const - { - return strcmp(s) == 0; - } - - // - // Compare contents for equality. - // - bool operator==(const Pj_String &rhs) const - { - return pj_strcmp(this, &rhs) == 0; - } - - // - // Find a character in the string. - // - char *strchr(int chr) - { - return pj_strchr(this, chr); - } - - // - // Find a character in the string. - // - char *find(int chr) - { - return strchr(chr); - } - - // - // Concatenate string. - // - void strcat(const Pj_String &rhs) - { - pj_strcat(this, &rhs); - } - - // - // Left trim. - // - void ltrim() - { - pj_strltrim(this); - } - - // - // Right trim. - // - void rtrim() - { - pj_strrtrim(this); - } - - // - // Left and right trim. - // - void trim() - { - pj_strtrim(this); - } - - // - // Convert to unsigned long. - // - unsigned long to_ulong() const - { - return pj_strtoul(this); - } - - // - // Convert from unsigned long. - // - void from_ulong(unsigned long value) - { - slen = pj_utoa(value, ptr); - } - - // - // Convert from unsigned long with padding. - // - void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ') - { - slen = pj_utoa_pad(value, ptr, min_dig, pad); - } - - -private: - //Pj_String(const Pj_String &rhs) {} - void operator=(const Pj_String &rhs) { pj_assert(false); } -}; - -#endif /* __PJPP_STRING_H__ */ + */ +#ifndef __PJPP_STRING_HPP__ +#define __PJPP_STRING_HPP__ + +#include +#include +#include + +// +// String wrapper class for pj_str_t. +// +class Pj_String : public pj_str_t +{ +public: + // + // Default constructor. + // + Pj_String() + { + pj_assert(sizeof(Pj_String) == sizeof(pj_str_t)); + ptr=NULL; + slen=0; + } + + // + // Construct the buffer from a char*. + // + explicit Pj_String(char *str) + { + set(str); + } + + // + // Construct from a const char*. + // + Pj_String(Pj_Pool *pool, const char *src) + { + set(pool, src); + } + + // + // Construct from pj_str_t*. + // + explicit Pj_String(pj_str_t *s) + { + set(s); + } + + // + // Construct by copying from const pj_str_t*. + // + Pj_String(Pj_Pool *pool, const pj_str_t *s) + { + set(pool, s); + } + + // + // Construct from another Pj_String + // + explicit Pj_String(Pj_String &rhs) + { + set(rhs); + } + + // + // Construct by copying from Pj_String + // + Pj_String(Pj_Pool *pool, const Pj_String &rhs) + { + set(pool, rhs); + } + + // + // Construct from a char* and a length. + // + Pj_String(char *str, pj_size_t len) + { + set(str, len); + } + + // + // Construct from pair of pointer. + // + Pj_String(char *begin, char *end) + { + pj_strset3(this, begin, end); + } + + // + // Get the length of the string. + // + pj_size_t length() const + { + return pj_strlen(this); + } + + // + // Get the length of the string. + // + pj_size_t size() const + { + return length(); + } + + // + // Get the string buffer. + // + const char *buf() const + { + return ptr; + } + + // + // Initialize buffer from char*. + // + void set(char *str) + { + pj_strset2(this, str); + } + + // + // Initialize by copying from a const char*. + // + void set(Pj_Pool *pool, const char *s) + { + pj_strdup2(pool->pool_(), this, s); + } + + // + // Initialize from pj_str_t*. + // + void set(pj_str_t *s) + { + pj_strassign(this, s); + } + + // + // Initialize by copying from const pj_str_t*. + // + void set(Pj_Pool *pool, const pj_str_t *s) + { + pj_strdup(pool->pool_(), this, s); + } + + // + // Initialize from char* and length. + // + void set(char *str, pj_size_t len) + { + pj_strset(this, str, len); + } + + // + // Initialize from pair of pointers. + // + void set(char *begin, char *end) + { + pj_strset3(this, begin, end); + } + + // + // Initialize from other Pj_String. + // + void set(Pj_String &rhs) + { + pj_strassign(this, &rhs); + } + + // + // Initialize by copying from a Pj_String*. + // + void set(Pj_Pool *pool, const Pj_String *s) + { + pj_strdup(pool->pool_(), this, s); + } + + // + // Initialize by copying from other Pj_String. + // + void set(Pj_Pool *pool, const Pj_String &s) + { + pj_strdup(pool->pool_(), this, &s); + } + + // + // Copy the contents of other string. + // + void strcpy(const pj_str_t *s) + { + pj_strcpy(this, s); + } + + // + // Copy the contents of other string. + // + void strcpy(const Pj_String &rhs) + { + pj_strcpy(this, &rhs); + } + + // + // Copy the contents of other string. + // + void strcpy(const char *s) + { + pj_strcpy2(this, s); + } + + // + // Compare string. + // + int strcmp(const char *s) const + { + return pj_strcmp2(this, s); + } + + // + // Compare string. + // + int strcmp(const pj_str_t *s) const + { + return pj_strcmp(this, s); + } + + // + // Compare string. + // + int strcmp(const Pj_String &rhs) const + { + return pj_strcmp(this, &rhs); + } + + // + // Compare string. + // + int strncmp(const char *s, pj_size_t len) const + { + return pj_strncmp2(this, s, len); + } + + // + // Compare string. + // + int strncmp(const pj_str_t *s, pj_size_t len) const + { + return pj_strncmp(this, s, len); + } + + // + // Compare string. + // + int strncmp(const Pj_String &rhs, pj_size_t len) const + { + return pj_strncmp(this, &rhs, len); + } + + // + // Compare string. + // + int stricmp(const char *s) const + { + return pj_stricmp2(this, s); + } + + // + // Compare string. + // + int stricmp(const pj_str_t *s) const + { + return pj_stricmp(this, s); + } + + // + // Compare string. + // + int stricmp(const Pj_String &rhs) const + { + return stricmp(&rhs); + } + + // + // Compare string. + // + int strnicmp(const char *s, pj_size_t len) const + { + return pj_strnicmp2(this, s, len); + } + + // + // Compare string. + // + int strnicmp(const pj_str_t *s, pj_size_t len) const + { + return pj_strnicmp(this, s, len); + } + + // + // Compare string. + // + int strnicmp(const Pj_String &rhs, pj_size_t len) const + { + return strnicmp(&rhs, len); + } + + // + // Compare contents for equality. + // + bool operator==(const char *s) const + { + return strcmp(s) == 0; + } + + // + // Compare contents for equality. + // + bool operator==(const pj_str_t *s) const + { + return strcmp(s) == 0; + } + + // + // Compare contents for equality. + // + bool operator==(const Pj_String &rhs) const + { + return pj_strcmp(this, &rhs) == 0; + } + + // + // Find a character in the string. + // + char *strchr(int chr) + { + return pj_strchr(this, chr); + } + + // + // Find a character in the string. + // + char *find(int chr) + { + return strchr(chr); + } + + // + // Concatenate string. + // + void strcat(const Pj_String &rhs) + { + pj_strcat(this, &rhs); + } + + // + // Left trim. + // + void ltrim() + { + pj_strltrim(this); + } + + // + // Right trim. + // + void rtrim() + { + pj_strrtrim(this); + } + + // + // Left and right trim. + // + void trim() + { + pj_strtrim(this); + } + + // + // Convert to unsigned long. + // + unsigned long to_ulong() const + { + return pj_strtoul(this); + } + + // + // Convert from unsigned long. + // + void from_ulong(unsigned long value) + { + slen = pj_utoa(value, ptr); + } + + // + // Convert from unsigned long with padding. + // + void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ') + { + slen = pj_utoa_pad(value, ptr, min_dig, pad); + } + + +private: + //Pj_String(const Pj_String &rhs) {} + void operator=(const Pj_String &rhs) { pj_assert(false); } +}; + +#endif /* __PJPP_STRING_HPP__ */ + diff --git a/pjlib/include/pj++/timer.hpp b/pjlib/include/pj++/timer.hpp index b1070421..fbb15f7a 100644 --- a/pjlib/include/pj++/timer.hpp +++ b/pjlib/include/pj++/timer.hpp @@ -1,180 +1,181 @@ /* $Id$ - */ -#ifndef __PJPP_TIMER_H__ -#define __PJPP_TIMER_H__ - -#include -#include -#include -#include - -class Pj_Timer_Heap; - -////////////////////////////////////////////////////////////////////////////// -// Timer entry. -// -// How to use: -// Derive class from Pj_Timer_Entry and override on_timeout(). -// Scheduler timer in Pj_Timer_Heap. -// -class Pj_Timer_Entry : public Pj_Object -{ - friend class Pj_Timer_Heap; - -public: - // - // Default constructor. - // - Pj_Timer_Entry() - { - entry_.user_data = this; - entry_.cb = &timer_heap_callback; - } - - // - // Destructor, do nothing. - // - ~Pj_Timer_Entry() - { - } - - // - // Override this to get the timeout notification. - // - virtual void on_timeout(int id) = 0; - -private: - pj_timer_entry entry_; - - static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e) - { - Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data; - entry->on_timeout(e->id); - } - -}; - -////////////////////////////////////////////////////////////////////////////// -// Timer heap. -// -class Pj_Timer_Heap : public Pj_Object -{ -public: - // - // Default constructor. - // - Pj_Timer_Heap() - : ht_(NULL) - { - } - - // - // Construct timer heap. - // - Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count) - : ht_(NULL) - { - create(pool, initial_count); - } - - // - // Destructor. - // - ~Pj_Timer_Heap() - { - destroy(); - } - - // - // Create - // - pj_status_t create(Pj_Pool *pool, pj_size_t initial_count) - { - destroy(); - return pj_timer_heap_create(pool->pool_(), initial_count, &ht_); - } - - // - // Destroy - // - void destroy() - { - if (ht_) { - pj_timer_heap_destroy(ht_); - ht_ = NULL; - } - } - - // - // Get pjlib compatible timer heap object. - // - pj_timer_heap_t *get_timer_heap() - { - return ht_; - } - - // - // Set the lock object. - // - void set_lock( Pj_Lock *lock, bool auto_delete ) - { - pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete); - } - - // - // Set maximum number of timed out entries to be processed per poll. - // - unsigned set_max_timed_out_per_poll(unsigned count) - { - return pj_timer_heap_set_max_timed_out_per_poll(ht_, count); - } - - // - // Schedule a timer. - // - bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay, - int id) - { - ent->entry_.id = id; - return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0; - } - - // - // Cancel a timer. - // - bool cancel(Pj_Timer_Entry *ent) - { - return pj_timer_heap_cancel(ht_, &ent->entry_) == 1; - } - - // - // Get current number of timers - // - pj_size_t count() - { - return pj_timer_heap_count(ht_); - } - - // - // Get the earliest time. - // Return false if no timer is found. - // - bool earliest_time(Pj_Time_Val *t) - { - return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS; - } - - // - // Poll the timer. - // Return number of timed out entries has been called. - // - unsigned poll(Pj_Time_Val *next_delay = NULL) - { - return pj_timer_heap_poll(ht_, next_delay); - } - -private: - pj_timer_heap_t *ht_; -}; - -#endif /* __PJPP_TIMER_H__ */ + */ +#ifndef __PJPP_TIMER_HPP__ +#define __PJPP_TIMER_HPP__ + +#include +#include +#include +#include + +class Pj_Timer_Heap; + +////////////////////////////////////////////////////////////////////////////// +// Timer entry. +// +// How to use: +// Derive class from Pj_Timer_Entry and override on_timeout(). +// Scheduler timer in Pj_Timer_Heap. +// +class Pj_Timer_Entry : public Pj_Object +{ + friend class Pj_Timer_Heap; + +public: + // + // Default constructor. + // + Pj_Timer_Entry() + { + entry_.user_data = this; + entry_.cb = &timer_heap_callback; + } + + // + // Destructor, do nothing. + // + ~Pj_Timer_Entry() + { + } + + // + // Override this to get the timeout notification. + // + virtual void on_timeout(int id) = 0; + +private: + pj_timer_entry entry_; + + static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e) + { + Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data; + entry->on_timeout(e->id); + } + +}; + +////////////////////////////////////////////////////////////////////////////// +// Timer heap. +// +class Pj_Timer_Heap : public Pj_Object +{ +public: + // + // Default constructor. + // + Pj_Timer_Heap() + : ht_(NULL) + { + } + + // + // Construct timer heap. + // + Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count) + : ht_(NULL) + { + create(pool, initial_count); + } + + // + // Destructor. + // + ~Pj_Timer_Heap() + { + destroy(); + } + + // + // Create + // + pj_status_t create(Pj_Pool *pool, pj_size_t initial_count) + { + destroy(); + return pj_timer_heap_create(pool->pool_(), initial_count, &ht_); + } + + // + // Destroy + // + void destroy() + { + if (ht_) { + pj_timer_heap_destroy(ht_); + ht_ = NULL; + } + } + + // + // Get pjlib compatible timer heap object. + // + pj_timer_heap_t *get_timer_heap() + { + return ht_; + } + + // + // Set the lock object. + // + void set_lock( Pj_Lock *lock, bool auto_delete ) + { + pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete); + } + + // + // Set maximum number of timed out entries to be processed per poll. + // + unsigned set_max_timed_out_per_poll(unsigned count) + { + return pj_timer_heap_set_max_timed_out_per_poll(ht_, count); + } + + // + // Schedule a timer. + // + bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay, + int id) + { + ent->entry_.id = id; + return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0; + } + + // + // Cancel a timer. + // + bool cancel(Pj_Timer_Entry *ent) + { + return pj_timer_heap_cancel(ht_, &ent->entry_) == 1; + } + + // + // Get current number of timers + // + pj_size_t count() + { + return pj_timer_heap_count(ht_); + } + + // + // Get the earliest time. + // Return false if no timer is found. + // + bool earliest_time(Pj_Time_Val *t) + { + return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS; + } + + // + // Poll the timer. + // Return number of timed out entries has been called. + // + unsigned poll(Pj_Time_Val *next_delay = NULL) + { + return pj_timer_heap_poll(ht_, next_delay); + } + +private: + pj_timer_heap_t *ht_; +}; + +#endif /* __PJPP_TIMER_HPP__ */ + diff --git a/pjlib/include/pj++/tree.hpp b/pjlib/include/pj++/tree.hpp index 7d30c678..f4fe8fc1 100644 --- a/pjlib/include/pj++/tree.hpp +++ b/pjlib/include/pj++/tree.hpp @@ -1,112 +1,112 @@ /* $Id$ - * - */ -#ifndef __PJPP_TREE_H__ -#define __PJPP_TREE_H__ - -#include - -// -// Tree. -// -class PJ_Tree -{ -public: - typedef pj_rbtree_comp Comp; - class iterator; - class reverse_iterator; - - class Node : private pj_rbtree_node - { - friend class PJ_Tree; - friend class iterator; - friend class reverse_iterator; - - public: - Node() {} - explicit Node(void *data) { user_data = data; } - void set_user_data(void *data) { user_data = data; } - void *get_user_data() const { return user_data; } - }; - - class iterator - { - public: - iterator() {} - iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {} - iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {} - Node *operator*() { return (Node*)nd_; } - bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; } - iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; } - void operator++() { nd_=pj_rbtree_next(tr_, nd_); } - void operator--() { nd_=pj_rbtree_prev(tr_, nd_); } - protected: - pj_rbtree *tr_; - pj_rbtree_node *nd_; - }; - - class reverse_iterator : public iterator - { - public: - reverse_iterator() {} - reverse_iterator(const reverse_iterator &it) : iterator(it) {} - reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {} - reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; } - Node *operator*() { return (Node*)nd_; } - bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); } - void operator++() { nd_=pj_rbtree_prev(tr_, nd_); } - void operator--() { nd_=pj_rbtree_next(tr_, nd_); } - }; - - explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); } - - iterator begin() - { - return iterator(&t_, pj_rbtree_first(&t_)); - } - - iterator end() - { - return iterator(&t_, NULL); - } - - reverse_iterator rbegin() - { - return reverse_iterator(&t_, pj_rbtree_last(&t_)); - } - - reverse_iterator rend() - { - return reverse_iterator(&t_, NULL); - } - - bool insert(Node *node) - { - return pj_rbtree_insert(&t_, node)==0 ? true : false; - } - - Node *find(const void *key) - { - return (Node*)pj_rbtree_find(&t_, key); - } - - Node *erase(Node *node) - { - return (Node*)pj_rbtree_erase(&t_, node); - } - - unsigned max_height(Node *node=NULL) - { - return pj_rbtree_max_height(&t_, node); - } - - unsigned min_height(Node *node=NULL) - { - return pj_rbtree_min_height(&t_, node); - } - -private: - pj_rbtree t_; -}; - -#endif /* __PJPP_TREE_H__ */ + */ +#ifndef __PJPP_TREE_HPP__ +#define __PJPP_TREE_HPP__ + +#include + +// +// Tree. +// +class PJ_Tree +{ +public: + typedef pj_rbtree_comp Comp; + class iterator; + class reverse_iterator; + + class Node : private pj_rbtree_node + { + friend class PJ_Tree; + friend class iterator; + friend class reverse_iterator; + + public: + Node() {} + explicit Node(void *data) { user_data = data; } + void set_user_data(void *data) { user_data = data; } + void *get_user_data() const { return user_data; } + }; + + class iterator + { + public: + iterator() {} + iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {} + iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {} + Node *operator*() { return (Node*)nd_; } + bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; } + iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; } + void operator++() { nd_=pj_rbtree_next(tr_, nd_); } + void operator--() { nd_=pj_rbtree_prev(tr_, nd_); } + protected: + pj_rbtree *tr_; + pj_rbtree_node *nd_; + }; + + class reverse_iterator : public iterator + { + public: + reverse_iterator() {} + reverse_iterator(const reverse_iterator &it) : iterator(it) {} + reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {} + reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; } + Node *operator*() { return (Node*)nd_; } + bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); } + void operator++() { nd_=pj_rbtree_prev(tr_, nd_); } + void operator--() { nd_=pj_rbtree_next(tr_, nd_); } + }; + + explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); } + + iterator begin() + { + return iterator(&t_, pj_rbtree_first(&t_)); + } + + iterator end() + { + return iterator(&t_, NULL); + } + + reverse_iterator rbegin() + { + return reverse_iterator(&t_, pj_rbtree_last(&t_)); + } + + reverse_iterator rend() + { + return reverse_iterator(&t_, NULL); + } + + bool insert(Node *node) + { + return pj_rbtree_insert(&t_, node)==0 ? true : false; + } + + Node *find(const void *key) + { + return (Node*)pj_rbtree_find(&t_, key); + } + + Node *erase(Node *node) + { + return (Node*)pj_rbtree_erase(&t_, node); + } + + unsigned max_height(Node *node=NULL) + { + return pj_rbtree_max_height(&t_, node); + } + + unsigned min_height(Node *node=NULL) + { + return pj_rbtree_min_height(&t_, node); + } + +private: + pj_rbtree t_; +}; + +#endif /* __PJPP_TREE_HPP__ */ + diff --git a/pjlib/include/pj++/types.hpp b/pjlib/include/pj++/types.hpp index 637c1222..3155eb02 100644 --- a/pjlib/include/pj++/types.hpp +++ b/pjlib/include/pj++/types.hpp @@ -1,144 +1,144 @@ /* $Id$ - * - */ -#ifndef __PJPP_TYPES_H__ -#define __PJPP_TYPES_H__ - -#include - -class Pj_Pool; -class Pj_Socket ; -class Pj_Lock; - - -// -// PJLIB initializer. -// -class Pjlib -{ -public: - Pjlib() - { - pj_init(); - } -}; - -// -// Class Pj_Object is declared in pool.hpp -// - -// -// Time value wrapper. -// -class Pj_Time_Val : public pj_time_val -{ -public: - Pj_Time_Val() - { - } - - Pj_Time_Val(long init_sec, long init_msec) - { - sec = init_sec; - msec = init_msec; - } - - Pj_Time_Val(const Pj_Time_Val &rhs) - { - sec=rhs.sec; - msec=rhs.msec; - } - - explicit Pj_Time_Val(const pj_time_val &tv) - { - sec = tv.sec; - msec = tv.msec; - } - - long get_sec() const - { - return sec; - } - - long get_msec() const - { - return msec; - } - - void set_sec (long s) - { - sec = s; - } - - void set_msec(long ms) - { - msec = ms; - normalize(); - } - - long to_msec() const - { - return PJ_TIME_VAL_MSEC((*this)); - } - - bool operator == (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_EQ((*this), rhs); - } - - bool operator > (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_GT((*this), rhs); - } - - bool operator >= (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_GTE((*this), rhs); - } - - bool operator < (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_LT((*this), rhs); - } - - bool operator <= (const Pj_Time_Val &rhs) const - { - return PJ_TIME_VAL_LTE((*this), rhs); - } - - Pj_Time_Val & operator = (const Pj_Time_Val &rhs) - { - sec = rhs.sec; - msec = rhs.msec; - return *this; - } - - Pj_Time_Val & operator += (const Pj_Time_Val &rhs) - { - PJ_TIME_VAL_ADD((*this), rhs); - return *this; - } - - Pj_Time_Val & operator -= (const Pj_Time_Val &rhs) - { - PJ_TIME_VAL_SUB((*this), rhs); - return *this; - } - - /* Must include os.hpp to use these, otherwise unresolved in linking */ - inline pj_status_t gettimeofday(); - inline pj_parsed_time decode(); - inline pj_status_t encode(const pj_parsed_time *pt); - inline pj_status_t to_gmt(); - inline pj_status_t to_local(); - - -private: - void normalize() - { - pj_time_val_normalize(this); - } - -}; - -#endif /* __PJPP_TYPES_H__ */ + */ +#ifndef __PJPP_TYPES_HPP__ +#define __PJPP_TYPES_HPP__ + +#include + +class Pj_Pool; +class Pj_Socket ; +class Pj_Lock; + + +// +// PJLIB initializer. +// +class Pjlib +{ +public: + Pjlib() + { + pj_init(); + } +}; + +// +// Class Pj_Object is declared in pool.hpp +// + +// +// Time value wrapper. +// +class Pj_Time_Val : public pj_time_val +{ +public: + Pj_Time_Val() + { + } + + Pj_Time_Val(long init_sec, long init_msec) + { + sec = init_sec; + msec = init_msec; + } + + Pj_Time_Val(const Pj_Time_Val &rhs) + { + sec=rhs.sec; + msec=rhs.msec; + } + + explicit Pj_Time_Val(const pj_time_val &tv) + { + sec = tv.sec; + msec = tv.msec; + } + + long get_sec() const + { + return sec; + } + + long get_msec() const + { + return msec; + } + + void set_sec (long s) + { + sec = s; + } + + void set_msec(long ms) + { + msec = ms; + normalize(); + } + + long to_msec() const + { + return PJ_TIME_VAL_MSEC((*this)); + } + + bool operator == (const Pj_Time_Val &rhs) const + { + return PJ_TIME_VAL_EQ((*this), rhs); + } + + bool operator > (const Pj_Time_Val &rhs) const + { + return PJ_TIME_VAL_GT((*this), rhs); + } + + bool operator >= (const Pj_Time_Val &rhs) const + { + return PJ_TIME_VAL_GTE((*this), rhs); + } + + bool operator < (const Pj_Time_Val &rhs) const + { + return PJ_TIME_VAL_LT((*this), rhs); + } + + bool operator <= (const Pj_Time_Val &rhs) const + { + return PJ_TIME_VAL_LTE((*this), rhs); + } + + Pj_Time_Val & operator = (const Pj_Time_Val &rhs) + { + sec = rhs.sec; + msec = rhs.msec; + return *this; + } + + Pj_Time_Val & operator += (const Pj_Time_Val &rhs) + { + PJ_TIME_VAL_ADD((*this), rhs); + return *this; + } + + Pj_Time_Val & operator -= (const Pj_Time_Val &rhs) + { + PJ_TIME_VAL_SUB((*this), rhs); + return *this; + } + + /* Must include os.hpp to use these, otherwise unresolved in linking */ + inline pj_status_t gettimeofday(); + inline pj_parsed_time decode(); + inline pj_status_t encode(const pj_parsed_time *pt); + inline pj_status_t to_gmt(); + inline pj_status_t to_local(); + + +private: + void normalize() + { + pj_time_val_normalize(this); + } + +}; + +#endif /* __PJPP_TYPES_HPP__ */ + diff --git a/pjlib/include/pj/compat/string.h b/pjlib/include/pj/compat/string.h index f637eb2e..b8917387 100644 --- a/pjlib/include/pj/compat/string.h +++ b/pjlib/include/pj/compat/string.h @@ -39,5 +39,14 @@ # define strnicmp strncasecmp #endif + +#define pj_native_strcmp strcmp +#define pj_native_strlen strlen +#define pj_native_strcpy strcpy +#define pj_native_strstr strstr +#define pj_native_strchr strchr +#define pj_native_strcasecmp strcasecmp +#define pj_native_strncasecmp strncasecmp + #endif /* __PJ_COMPAT_STRING_H__ */ diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index 597c4d9f..0465ac9a 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -147,7 +147,7 @@ * Default: 4 */ #ifndef PJ_LOG_MAX_LEVEL -# define PJ_LOG_MAX_LEVEL 4 +# define PJ_LOG_MAX_LEVEL 5 #endif /** @@ -403,6 +403,13 @@ # define PJ_TODO(id) TODO___##id: #endif +/** + * Function attributes to inform that the function may throw exception. + * + * @param x The exception list, enclosed in parenthesis. + */ +#define __pj_throw__(x) + /******************************************************************** * Sanity Checks diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index e7b3ab93..b7c62533 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -215,6 +215,11 @@ PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, * Operation is cancelled. */ #define PJ_ECANCELLED (PJ_ERRNO_START_STATUS + 14) +/** + * @hideinitializer + * Object already exists. + */ +#define PJ_EEXISTS (PJ_ERRNO_START_STATUS + 14) /** @} */ /* pj_errnum */ diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h index 3f48abdf..8bdda480 100644 --- a/pjlib/include/pj/except.h +++ b/pjlib/include/pj/except.h @@ -182,6 +182,7 @@ PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id); * @return The name associated with the specified ID. */ PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id); + /** @} */ diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h index 8e39d652..b1eb9d9f 100644 --- a/pjlib/include/pj/hash.h +++ b/pjlib/include/pj/hash.h @@ -44,6 +44,21 @@ PJ_BEGIN_DECL PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, const void *key, unsigned keylen); + +/** + * Convert the key to lowercase and calculate the hash value. The resulting + * string is stored in \c result. + * + * @param hval The initial hash value, normally zero. + * @param result Buffer to store the result, which must be enough to hold + * the string. + * @param key The input key to be converted and calculated. + * + * @return The hash value. + */ +PJ_DECL(pj_uint32_t) pj_hash_calc_tolower(pj_uint32_t hval, + char *result, + const pj_str_t *key); /** * Create a hash table with the specified 'bucket' size. diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index c44b7ced..d1aea694 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -340,10 +340,20 @@ PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key, void **old_data); +/** + * Initialize operation key. + * + * @param op_key The operation key to be initialied. + * @param size The size of the operation key. + */ +PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key, + pj_size_t size ); + /** * Check if operation is pending on the specified operation key. - * The \c op_key must have been submitted as pending operation before, - * or otherwise the result is undefined. + * The \c op_key must have been initialized with #pj_ioqueue_op_key_init() + * or submitted as pending operation before, or otherwise the result + * is undefined. * * @param key The key. * @param op_key The operation key, previously submitted to any of diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h index 3c7a2ada..5b7ac130 100644 --- a/pjlib/include/pj/string.h +++ b/pjlib/include/pj/string.h @@ -12,6 +12,9 @@ #include #include +#include +#include + PJ_BEGIN_DECL diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c index 25bf5b7f..5a986514 100644 --- a/pjlib/src/pj/errno.c +++ b/pjlib/src/pj/errno.c @@ -30,7 +30,8 @@ static const struct { PJ_EBUSY, "Object is busy"}, { PJ_ENOTSUP, "Option/operation is not supported"}, { PJ_EINVALIDOP, "Invalid operation"}, - { PJ_ECANCELLED, "Operation cancelled"} + { PJ_ECANCELLED, "Operation cancelled"}, + { PJ_EEXISTS, "Object already exists" } }; /* diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c index 0fa95e1b..195c8817 100644 --- a/pjlib/src/pj/hash.c +++ b/pjlib/src/pj/hash.c @@ -50,6 +50,20 @@ PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned key } return hash; } + +PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval, + char *result, + const pj_str_t *key) +{ + long i; + + for (i=0; islen; ++i) { + result[i] = (char)pj_tolower(key->ptr[i]); + hval = hval * PJ_HASH_MULTIPLIER + result[i]; + } + + return hval; +} PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size) diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c index 75774ede..c2e11211 100644 --- a/pjlib/src/pj/ioqueue_common_abs.c +++ b/pjlib/src/pj/ioqueue_common_abs.c @@ -832,6 +832,14 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, } } #endif /* PJ_HAS_TCP */ + + +PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key, + pj_size_t size ) +{ + pj_memset(op_key, 0, size); +} + /* * pj_ioqueue_is_pending() diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c index 93cbb6d5..777cb6be 100644 --- a/pjlib/src/pj/ioqueue_winnt.c +++ b/pjlib/src/pj/ioqueue_winnt.c @@ -892,6 +892,11 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, #endif /* #if PJ_HAS_TCP */ +PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key, + pj_size_t size ) +{ + pj_memset(op_key, 0, size); +} PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key ) diff --git a/pjsip/build/TODO.txt b/pjsip/build/TODO.txt deleted file mode 100644 index 670e2bff..00000000 --- a/pjsip/build/TODO.txt +++ /dev/null @@ -1,21 +0,0 @@ -- regc refresh automatically -- if dialog CANCEL return 481, disconnect the dialog -- presence implement callback from event_sub -- presence supports multiple tuples! -- implement event headers! - -Prio Task - 10 General authentication framework in pjsua. - 10 Start on SUBSCRIBE/NOTIFY framework. - 10 Refactor pjsip_event ---- - 10 Concurrency in pool factory because endpt pool is shared by app. - Choices: - - another pool factory (thread safe) for app ==> waste memory. - - endpt pool is thread safe ==> slow - 10 Sound in Linux - 10 Support TCP - 10 Per instance configuration: - - max number of tsxs - - max number of dialogs - - socket buffer size diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp index 0703f914..2204a6f3 100644 --- a/pjsip/build/pjsip_core.dsp +++ b/pjsip/build/pjsip_core.dsp @@ -32,16 +32,16 @@ RSC=rc.exe # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" +# PROP BASE Output_Dir ".\output\pjsip-core-i386-win32-vc6-release" +# PROP BASE Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\output\pjsip_core_vc6_Release" -# PROP Intermediate_Dir ".\output\pjsip_core_vc6_Release" +# PROP Output_Dir ".\output\pjsip-core-i386-win32-vc6-release" +# PROP Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MD /W4 /Zi /O2 /I "../src" /I "../../pjlib/src" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /FD /c +# ADD CPP /nologo /MD /W4 /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -50,22 +50,22 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"../lib/pjsip_core_vc6s.lib" +# ADD LIB32 /nologo /out:"../lib/pjsip-core-i386-win32-vc6-release.lib" !ELSEIF "$(CFG)" == "pjsip_core - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Output_Dir ".\output\pjsip-core-i386-win32-vc6-debug" +# PROP BASE Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".\output\pjsip_core_vc6_Debug" -# PROP Intermediate_Dir ".\output\pjsip_core_vc6_Debug" +# PROP Output_Dir ".\output\pjsip-core-i386-win32-vc6-debug" +# PROP Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../src" /I "../../pjlib/src" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -74,7 +74,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"../lib/pjsip_core_vc6sd.lib" +# ADD LIB32 /nologo /out:"../lib/pjsip-core-i386-win32-vc6-debug.lib" !ENDIF @@ -135,75 +135,79 @@ SOURCE=..\src\pjsip\sip_uri.c # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File -SOURCE=..\src\pjsip_core.h +SOURCE=..\include\pjsip_core.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\print.h +SOURCE=..\include\pjsip\print_util.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_auth.h +SOURCE=..\include\pjsip\sip_auth.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_auth_msg.h +SOURCE=..\include\pjsip\sip_auth_msg.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_auth_parser.h +SOURCE=..\include\pjsip\sip_auth_parser.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_config.h +SOURCE=..\include\pjsip\sip_config.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_endpoint.h +SOURCE=..\include\pjsip\sip_endpoint.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_event.h +SOURCE=..\include\pjsip\sip_errno.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_misc.h +SOURCE=..\include\pjsip\sip_event.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_module.h +SOURCE=..\include\pjsip\sip_misc.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_msg.h +SOURCE=..\include\pjsip\sip_module.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_parser.h +SOURCE=..\include\pjsip\sip_msg.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_private.h +SOURCE=..\include\pjsip\sip_parser.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_resolve.h +SOURCE=..\include\pjsip\sip_private.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_transaction.h +SOURCE=..\include\pjsip\sip_resolve.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_transport.h +SOURCE=..\include\pjsip\sip_transaction.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_types.h +SOURCE=..\include\pjsip\sip_transport.h # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_uri.h +SOURCE=..\include\pjsip\sip_types.h +# End Source File +# Begin Source File + +SOURCE=..\include\pjsip\sip_uri.h # End Source File # End Group # Begin Group "Inline Files" @@ -211,7 +215,7 @@ SOURCE=..\src\pjsip\sip_uri.h # PROP Default_Filter "" # Begin Source File -SOURCE=..\src\pjsip\sip_msg_i.h +SOURCE=..\include\pjsip\sip_msg_i.h # End Source File # End Group # Begin Source File diff --git a/pjsip/build/pjsip_ua.dsp b/pjsip/build/pjsip_ua.dsp index efde2534..cd45b10c 100644 --- a/pjsip/build/pjsip_ua.dsp +++ b/pjsip/build/pjsip_ua.dsp @@ -87,15 +87,19 @@ LIB32=link.exe -lib # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File -SOURCE=..\src\pjsip_mod_ua\sip_dialog.c +SOURCE="..\src\pjsip-ua\sip_dialog.c" # End Source File # Begin Source File -SOURCE=..\src\pjsip_mod_ua\sip_reg.c +SOURCE="..\src\pjsip-ua\sip_reg.c" # End Source File # Begin Source File -SOURCE=..\src\pjsip_mod_ua\sip_ua.c +SOURCE="..\src\pjsip-ua\sip_ua.c" +# End Source File +# Begin Source File + +SOURCE="..\src\pjsip-ua\sip_ua_private.h" # End Source File # End Group # Begin Group "Header Files" diff --git a/pjsip/build/tounix b/pjsip/build/tounix deleted file mode 100644 index 82b84c90..00000000 --- a/pjsip/build/tounix +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -name=`basename $1` -cp $1 /tmp -cat /tmp/$name | tr -d '\r' > $1 -rm -f /tmp/$name diff --git a/pjsip/include/pjsip/print_util.h b/pjsip/include/pjsip/print_util.h new file mode 100644 index 00000000..b23d45fc --- /dev/null +++ b/pjsip/include/pjsip/print_util.h @@ -0,0 +1,99 @@ +/* $Id$ + */ +#ifndef __PJSIP_PRINT_H__ +#define __PJSIP_PRINT_H__ + +#define copy_advance_check(buf,str) \ + do { \ + if ((str).slen+10 >= (endbuf-buf)) return -1; \ + pj_memcpy(buf, (str).ptr, (str).slen); \ + buf += (str).slen; \ + } while (0) + +/* +static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, int len1, const pj_str_t *str2) +{ + if (str2->slen) { + int printed = len1+str2->slen; + if (printed+10 >= (endbuf-buf)) return NULL; + pj_memcpy(buf,str1,len1); + pj_memcpy(buf+len1, str2->ptr, str2->slen); + return buf + printed; + } else + return buf; +} +*/ + +#define copy_advance_pair_check(buf,str1,len1,str2) \ + do { \ + if (str2.slen) { \ + printed = len1+str2.slen; \ + if (printed+10 >= (endbuf-buf)) return -1; \ + pj_memcpy(buf,str1,len1); \ + pj_memcpy(buf+len1, str2.ptr, str2.slen); \ + buf += printed; \ + } \ + } while (0) +/* +#define copy_advance_pair(buf,str1,len1,str2) \ + do { \ + buf = imp_copy_advance_pair(buf, endbuf, str1, len1, &str2); \ + if (buf == NULL) return -1; \ + } while (0) +*/ + +#define copy_advance_pair_quote_check(buf,str1,len1,str2,quotebegin,quoteend) \ + do { \ + if (str2.slen) { \ + printed = len1+str2.slen+2; \ + if (printed+10 >= (endbuf-buf)) return -1; \ + pj_memcpy(buf,str1,len1); \ + *(buf+len1)=quotebegin; \ + pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \ + *(buf+printed-1) = quoteend; \ + buf += printed; \ + } \ + } while (0) + +#define copy_advance_no_check(buf,str) \ + pj_memcpy(buf, (str).ptr, (str).slen); \ + buf += (str).slen; + +#define copy_advance_pair_no_check(buf,str1,len1,str2) \ + if (str2.slen) { \ + pj_memcpy(buf,str1,len1); \ + pj_memcpy(buf+len1, str2.ptr, str2.slen); \ + buf += len1+str2.slen; \ + } + +#define copy_advance copy_advance_check +#define copy_advance_pair copy_advance_pair_check +#define copy_advance_pair_quote copy_advance_pair_quote_check + +#define copy_advance_pair_quote_cond(buf,str1,len1,str2,quotebegin,quoteend) \ + do { \ + if (str2.slen && *str2.ptr!=quotebegin) \ + copy_advance_pair_quote(buf,str1,len1,str2,quotebegin,quoteend); \ + else \ + copy_advance_pair(buf,str1,len1,str2); \ + } while (0) + +/* + * Internal type declarations. + */ +typedef void* (*pjsip_hdr_clone_fptr)(pj_pool_t *, const void*); +typedef int (*pjsip_hdr_print_fptr)(void *hdr, char *buf, pj_size_t len); + +extern const pj_str_t pjsip_hdr_names[]; + +PJ_INLINE(void) init_hdr(void *hptr, pjsip_hdr_e htype, void *vptr) +{ + pjsip_hdr *hdr = hptr; + hdr->type = htype; + hdr->name = hdr->sname = pjsip_hdr_names[htype]; + hdr->vptr = vptr; + pj_list_init(hdr); +} + +#endif /* __PJSIP_PRINT_H__ */ + diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h index 3396b669..c34ca030 100644 --- a/pjsip/include/pjsip/sip_auth.h +++ b/pjsip/include/pjsip/sip_auth.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_AUTH_SIP_AUTH_H__ #define __PJSIP_AUTH_SIP_AUTH_H__ @@ -60,7 +59,7 @@ struct pjsip_cred_info */ typedef struct pjsip_cached_auth_hdr { - PJ_DECL_LIST_MEMBER(struct pjsip_cached_auth_hdr) + PJ_DECL_LIST_MEMBER(struct pjsip_cached_auth_hdr); pjsip_method method; pjsip_authorization_hdr *hdr; @@ -80,7 +79,7 @@ typedef struct pjsip_cached_auth_hdr */ typedef struct pjsip_auth_session { - PJ_DECL_LIST_MEMBER(struct pjsip_auth_session) + PJ_DECL_LIST_MEMBER(struct pjsip_auth_session); pj_str_t realm; pj_bool_t is_proxy; diff --git a/pjsip/include/pjsip/sip_auth_msg.h b/pjsip/include/pjsip/sip_auth_msg.h index ce1ca1e7..8e68331d 100644 --- a/pjsip/include/pjsip/sip_auth_msg.h +++ b/pjsip/include/pjsip/sip_auth_msg.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_AUTH_SIP_AUTH_MSG_H__ #define __PJSIP_AUTH_SIP_AUTH_MSG_H__ @@ -68,7 +67,7 @@ typedef struct pjsip_pgp_credential pjsip_pgp_credential; */ struct pjsip_authorization_hdr { - PJSIP_DECL_HDR_MEMBER(struct pjsip_authorization_hdr) + PJSIP_DECL_HDR_MEMBER(struct pjsip_authorization_hdr); pj_str_t scheme; union { @@ -157,7 +156,7 @@ typedef struct pjsip_pgp_challenge pjsip_pgp_challenge; */ struct pjsip_www_authenticate_hdr { - PJSIP_DECL_HDR_MEMBER(struct pjsip_www_authenticate_hdr) + PJSIP_DECL_HDR_MEMBER(struct pjsip_www_authenticate_hdr); pj_str_t scheme; union { diff --git a/pjsip/include/pjsip/sip_auth_parser.h b/pjsip/include/pjsip/sip_auth_parser.h index 7f280ecd..c1d4f231 100644 --- a/pjsip/include/pjsip/sip_auth_parser.h +++ b/pjsip/include/pjsip/sip_auth_parser.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_AUTH_SIP_AUTH_PARSER_H__ #define __PJSIP_AUTH_SIP_AUTH_PARSER_H__ @@ -23,9 +22,11 @@ PJ_BEGIN_DECL * Initialize and register authorization parser module. * This will register parser handler for various Authorization related headers * such as Authorization, WWW-Authenticate, Proxy-Authorizization, and - * Proxy-Authenticate headers. + * Proxy-Authenticate headers. + * + * @return PJ_SUCCESS or the appropriate status code. */ -PJ_DECL(void) pjsip_auth_init_parser(); +PJ_DECL(pj_status_t) pjsip_auth_init_parser(void); /** * DeInitialize authorization parser module. diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h index a594d488..bba037cb 100644 --- a/pjsip/include/pjsip/sip_config.h +++ b/pjsip/include/pjsip/sip_config.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_CONFIG_H__ #define __PJSIP_SIP_CONFIG_H__ @@ -133,7 +132,6 @@ #include -#include #endif /* __PJSIP_SIP_CONFIG_H__ */ diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h index d950657d..e67e2863 100644 --- a/pjsip/include/pjsip/sip_endpoint.h +++ b/pjsip/include/pjsip/sip_endpoint.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_ENDPOINT_H__ #define __PJSIP_SIP_ENDPOINT_H__ @@ -28,13 +27,15 @@ PJ_BEGIN_DECL * SIP Endpoint instance (pjsip_endpoint) can be viewed as the master/owner of * all SIP objects in an application. It performs the following roles: * - it manages the allocation/deallocation of memory pools for all objects. - * - it manages listeners and transports, and how they are used by transactions. + * - it manages listeners and transports, and how they are used by + * transactions. * - it owns transaction hash table. * - it receives incoming messages from transport layer and automatically * dispatches them to the correct transaction (or create a new one). * - it has a single instance of timer management (timer heap). * - it manages modules, which is the primary means of extending the library. - * - it provides single polling function for all objects and distributes events. + * - it provides single polling function for all objects and distributes + * events. * - it provides SIP policy such as which outbound proxy to use for all * outgoing SIP request messages. * - it automatically handles incoming requests which can not be handled by @@ -49,15 +50,22 @@ PJ_BEGIN_DECL /** * Create an instance of SIP endpoint from the specified pool factory. - * The pool factory reference then will be kept by the endpoint, so that future - * memory allocations by SIP components will be taken from the same pool factory. - * - * @param pf Pool factory that will be used for the lifetime of endpoint. - * - * @return the endpoint instance on success. + * The pool factory reference then will be kept by the endpoint, so that + * future memory allocations by SIP components will be taken from the same + * pool factory. + * + * @param pf Pool factory that will be used for the lifetime of + * endpoint. + * @param name Optional name to be specified for the endpoint. + * If this parameter is NULL, then the name will use + * local host name. + * @param endpt Pointer to receive endpoint instance. + * + * @return PJ_SUCCESS on success. */ -PJ_DECL(pjsip_endpoint*) pjsip_endpt_create(pj_pool_factory *pf); - +PJ_DECL(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf, + pjsip_endpoint **endpt); + /** * Destroy endpoint instance. Application must make sure that all pending * transactions have been terminated properly, because this function does not @@ -66,6 +74,16 @@ PJ_DECL(pjsip_endpoint*) pjsip_endpt_create(pj_pool_factory *pf); * @param endpt The SIP endpoint to be destroyed. */ PJ_DECL(void) pjsip_endpt_destroy(pjsip_endpoint *endpt); + +/** + * Get endpoint name. + * + * @param endpt The SIP endpoint instance. + * + * @return Endpoint name, as was registered during endpoint + * creation. The string is NULL terminated. + */ +PJ_DECL(const pj_str_t*) pjsip_endpt_name(const pjsip_endpoint *endpt); /** * Poll for events. Application must call this function periodically to ensure @@ -153,10 +171,13 @@ PJ_DECL(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, * transaction to endpoint with #pjsip_endpt_register_tsx. * This function, like all other endpoint functions, is thread safe. * - * @param endpt The SIP endpoint. - * @return The new transaction, or NULL on failure. + * @param endpt The SIP endpoint. + * @param p_tsx Pointer to receive the transaction. + * + * @return PJ_SUCCESS or the appropriate error code. */ -PJ_DECL(pjsip_transaction*) pjsip_endpt_create_tsx(pjsip_endpoint *endpt); +PJ_DECL(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt, + pjsip_transaction **p_tsx); /** * Register the transaction to the endpoint's transaction table. @@ -187,10 +208,13 @@ PJ_DECL(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt, * Create a new transmit data buffer. * This function, like all other endpoint functions, is thread safe. * - * @param endpt the endpoint. - * @return new transmit data. + * @param endpt The endpoint. + * @param p_tdata Pointer to receive transmit data buffer. + * + * @return PJ_SUCCESS or the appropriate error code. */ -PJ_DECL(pjsip_tx_data*) pjsip_endpt_create_tdata( pjsip_endpoint *endpt ); +PJ_DECL(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt, + pjsip_tx_data **p_tdata); /** * Asynchronously resolve a SIP target host or domain according to rule @@ -330,6 +354,24 @@ PJ_DECL(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt, * @return List of "Route" header. */ PJ_DECL(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt ); + +/** + * Log an error. + */ +PJ_DECL(void) pjsip_endpt_log_error( pjsip_endpoint *endpt, + const char *sender, + pj_status_t error_code, + const char *format, + ... ); + +#define PJSIP_ENDPT_LOG_ERROR(expr) \ + pjsip_endpt_log_error expr + +#define PJSIP_ENDPT_TRACE(tracing,expr) \ + do { \ + if ((tracing)) \ + PJ_LOG(4,expr); \ + } while (0) /** * @} diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h new file mode 100644 index 00000000..6e4a6f72 --- /dev/null +++ b/pjsip/include/pjsip/sip_errno.h @@ -0,0 +1,86 @@ +/* $Id$ + */ +#ifndef __PJSIP_SIP_ERRNO_H__ +#define __PJSIP_SIP_ERRNO_H__ + +#include + +/** + * Start of error code relative to PJ_ERRNO_START_USER. + */ +#define PJSIP_ERRNO_START (PJ_ERRNO_START_USER+10000) + +/** + * Create error value from SIP status code. + * @param code SIP status code. + * @return Error code in pj_status_t namespace. + */ +#define PJSIP_ERRNO_FROM_SIP_STATUS(code) (PJSIP_ERRNO_START+code) + +/** + * Get SIP status code from error value. + * If conversion to SIP status code is not available, a SIP status code + * 599 will be returned. + * + * @param status Error code in pj_status_t namespace. + * @return SIP status code. + */ +#define PJSIP_ERRNO_TO_SIP_STATUS(status) \ + ((status>=PJSIP_ERRNO_FROM_SIP_STATUS(100) && \ + status -#include +#include #include PJ_BEGIN_DECL @@ -51,13 +50,24 @@ enum */ typedef struct pjsip_parser_err_report { - PJ_DECL_LIST_MEMBER(struct pjsip_parser_err_report) + PJ_DECL_LIST_MEMBER(struct pjsip_parser_err_report); int exception_code; /**< Error exception (e.g. PJSIP_SYN_ERR_EXCEPTION) */ int line; /**< Line number. */ int col; /**< Column number. */ pj_str_t hname; /**< Header name, if any. */ } pjsip_parser_err_report; + +/** + * Parsing context, the default argument for parsing functions. + */ +typedef struct pjsip_parse_ctx +{ + pj_scanner *scanner; /**< The scanner. */ + pj_pool_t *pool; /**< The pool. */ + pjsip_rx_data *rdata; /**< Optional rdata. */ +} pjsip_parse_ctx; + /** * Type of function to parse header. The parsing function must follow these @@ -76,7 +86,7 @@ typedef struct pjsip_parser_err_report * - for the last header, these separator is optional since parsing * can be terminated when seeing EOF. */ -typedef void* (pjsip_parse_hdr_func)(pj_scanner *scanner, pj_pool_t *pool); +typedef pjsip_hdr* (pjsip_parse_hdr_func)(pjsip_parse_ctx *context); /** * Type of function to parse URI scheme. @@ -94,8 +104,7 @@ typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool); * @param hshortname The short header name or NULL. * @param fptr The pointer to function to parser the header. * - * @return zero if success. - * @see pjsip_parse_hdr_func + * @return PJ_SUCCESS if success, or the appropriate error code. */ PJ_DECL(pj_status_t) pjsip_register_hdr_parser( const char *hname, const char *hshortname, @@ -183,6 +192,27 @@ PJ_DECL(pjsip_msg *) pjsip_parse_msg( pj_pool_t *pool, char *buf, pj_size_t size, pjsip_parser_err_report *err_list); + +/** + * Parse a packet buffer and build a rdata. The resulting message will be + * stored in \c msg field in the \c rdata. This behaves pretty much like + * #pjsip_parse_msg(), except that it will also initialize the header fields + * in the \c rdata. + * + * This function is normally called by the transport layer. + * + * @param buf The input buffer + * @param buf The input buffer, which size must be at least (size+1) + * because the function will temporarily put NULL + * termination at the end of the buffer during parsing. + * @param size The length of the string (not counting NULL terminator). + * @param rdata The receive data buffer to store the message and + * its elements. + * + * @return The message inside the rdata if successfull, or NULL. + */ +PJ_DECL(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size, + pjsip_rx_data *rdata ); /** * Check incoming packet to see if a (probably) valid SIP message has been @@ -193,10 +223,12 @@ PJ_DECL(pjsip_msg *) pjsip_parse_msg( pj_pool_t *pool, * @param msg_size [out] If message is valid, this parameter will contain * the size of the SIP message (including body, if any). * - * @return PJ_TRUE (1) if a message is found. + * @return PJ_SUCCESS if a message is found, or an error code. */ -PJ_DECL(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, - pj_bool_t is_datagram, pj_size_t *msg_size); +PJ_DECL(pj_status_t) pjsip_find_msg(const char *buf, + pj_size_t size, + pj_bool_t is_datagram, + pj_size_t *msg_size); /** * Parse the content of a header and return the header instance. @@ -247,7 +279,7 @@ PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, * parsers. */ extern -pj_char_spec pjsip_HOST_SPEC, /* For scanning host part. */ +pj_cis_t pjsip_HOST_SPEC, /* For scanning host part. */ pjsip_DIGIT_SPEC, /* Decimal digits */ pjsip_ALPHA_SPEC, /* Alpha (A-Z, a-z) */ pjsip_ALNUM_SPEC, /* Decimal + Alpha. */ diff --git a/pjsip/include/pjsip/sip_private.h b/pjsip/include/pjsip/sip_private.h index afcff08b..b2661350 100644 --- a/pjsip/include/pjsip/sip_private.h +++ b/pjsip/include/pjsip/sip_private.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_PRIVATE_H__ #define __PJSIP_SIP_PRIVATE_H__ @@ -26,16 +25,18 @@ PJ_BEGIN_DECL * @param endpt The endpoint * @param cb Callback to be called to receive messages from transport. */ -PJ_DECL(pjsip_transport_mgr*) pjsip_transport_mgr_create( pj_pool_t *pool, - pjsip_endpoint *endpt, - void (*cb)(pjsip_endpoint *,pjsip_rx_data *)); +PJ_DECL(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool, + pjsip_endpoint *endpt, + void (*cb)(pjsip_endpoint *, + pjsip_rx_data *), + pjsip_transport_mgr **); /** * Destroy transport manager and release all transports. * @param mgr Transport manager to be destroyed. */ -PJ_DECL(void) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ); +PJ_DECL(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ); /** * Poll for transport events. diff --git a/pjsip/include/pjsip/sip_resolve.h b/pjsip/include/pjsip/sip_resolve.h index 4a47c135..5464db91 100644 --- a/pjsip/include/pjsip/sip_resolve.h +++ b/pjsip/include/pjsip/sip_resolve.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_RESOLVE_H__ #define __PJSIP_SIP_RESOLVE_H__ diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h index 3ef6ad14..cdb11235 100644 --- a/pjsip/include/pjsip/sip_transaction.h +++ b/pjsip/include/pjsip/sip_transaction.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_TRANSACTION_H__ #define __PJSIP_SIP_TRANSACTION_H__ @@ -11,8 +10,6 @@ #include #include -//#include -//#include #include PJ_BEGIN_DECL @@ -22,7 +19,8 @@ PJ_BEGIN_DECL * @ingroup PJSIP * @{ */ - + +/* Forward decl. */ struct pjsip_transaction; @@ -60,68 +58,111 @@ typedef enum pjsip_tsx_transport_state_e * Transaction state. */ struct pjsip_transaction -{ - pj_pool_t *pool; - pjsip_endpoint *endpt; - char obj_name[PJ_MAX_OBJ_NAME]; - pjsip_role_e role; - int status_code; - pjsip_tsx_state_e state; - int (*state_handler)(struct pjsip_transaction *, pjsip_event *); - - pj_mutex_t *mutex; - pjsip_method method; - int cseq; - pj_str_t transaction_key; - pj_str_t branch; - - pjsip_tsx_transport_state_e transport_state; - pjsip_host_port dest_name; - int current_addr; - pjsip_server_addresses remote_addr; - pjsip_transport_t *transport; - - pjsip_tx_data *last_tx; - int has_unsent_msg; - int handle_ack; - int retransmit_count; - - pj_timer_entry retransmit_timer; - pj_timer_entry timeout_timer; +{ + /* + * Administrivia + */ + pj_pool_t *pool; /**< Pool owned by the tsx. */ + pjsip_endpoint *endpt; /**< Endpoint instance. */ + pj_mutex_t *mutex; /**< Mutex for this tsx. */ + char obj_name[PJ_MAX_OBJ_NAME]; /**< Tsx name. */ + int tracing; /**< Tracing enabled? */ + + /* + * Transaction identification. + */ + pjsip_role_e role; /**< Role (UAS or UAC) */ + pjsip_method method; /**< The method. */ + int cseq; /**< The CSeq */ + pj_str_t transaction_key;/**< hash table key. */ + pj_str_t branch; /**< The branch Id. */ + + /* + * State and status. + */ + int status_code; /**< Last status code seen. */ + pjsip_tsx_state_e state; /**< State. */ + int handle_ack; /**< Should we handle ACK? */ + + /** Handler according to current state. */ + pj_status_t (*state_handler)(struct pjsip_transaction *, pjsip_event *); + + /* + * Transport. + */ + pjsip_tsx_transport_state_e transport_state;/**< Transport's state. */ + pjsip_host_port dest_name; /**< Destination address. */ + pjsip_server_addresses remote_addr; /**< Addresses resolved. */ + int current_addr; /**< Address currently used. */ + + pjsip_transport_t *transport; /**< Transport to use. */ + + /* + * Messages and timer. + */ + pjsip_tx_data *last_tx; /**< Msg kept for retrans. */ + int has_unsent_msg; /**< Non-zero if tsx need to + transmit msg once resolver + completes. */ + int retransmit_count;/**< Retransmission count. */ + pj_timer_entry retransmit_timer;/**< Retransmit timer. */ + pj_timer_entry timeout_timer; /**< Timeout timer. */ + + /** Module specific data. */ void *module_data[PJSIP_MAX_MODULE]; }; /** - * Init transaction as UAC. - * @param tsx the transaction. - * @param tdata the transmit data. - * @return PJ_SUCCESS if successfull. + * Init transaction as UAC from the specified transmit data (\c tdata). + * The transmit data must have a valid \c Request-Line and \c CSeq header. + * If \c Route headers are present, it will be used to calculate remote + * destination. + * + * If \c Via header does not exist, it will be created along with a unique + * \c branch parameter. If it exists and contains branch parameter, then + * the \c branch parameter will be used as is as the transaction key. + * + * The \c Route headers in the transmit data, if present, are used to + * calculate remote destination. + * + * At the end of the function, the transaction will start resolving the + * addresses of remote server to contact. Transport will be acquired as soon + * as the resolving job completes. + * + * @param tsx The transaction. + * @param tdata The transmit data. + * + * @return PJ_SUCCESS if successfull. */ PJ_DECL(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, pjsip_tx_data *tdata); /** - * Init transaction as UAS. - * @param tsx the transaction to be initialized. - * @param rdata the received incoming request. + * Init transaction as UAS. + * + * @param tsx The transaction to be initialized. + * @param rdata The received incoming request. + * * @return PJ_SUCCESS if successfull. */ PJ_DECL(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, pjsip_rx_data *rdata); /** - * Process incoming message for this transaction. - * @param tsx the transaction. - * @param rdata the incoming message. + * Process incoming message for this transaction. + * + * @param tsx The transaction. + * @param rdata The incoming message. */ PJ_DECL(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx, pjsip_rx_data *rdata); /** - * Transmit message with this transaction. - * @param tsx the transaction. - * @param tdata the outgoing message. + * Transmit message with this transaction. + * + * @param tsx The transaction. + * @param tdata The outgoing message. */ PJ_DECL(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata); @@ -133,35 +174,41 @@ PJ_DECL(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx, * This operation is only valid if the transaction is configured to handle ACK * (tsx->handle_ack is non-zero). If this attribute is not set, then the * transaction will comply with RFC-3261, i.e. it will set itself to - * TERMINATED state when it receives 2xx/INVITE. - * @param tsx The transaction. - * @param tdata The ACK request. + * TERMINATED state when it receives 2xx/INVITE. + * + * @param tsx The transaction. + * @param tdata The ACK request. */ PJ_DECL(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx, pjsip_tx_data *tdata); /** - * Forcely terminate transaction. - * @param tsx the transaction. - * @param code the status code to report. + * Force terminate transaction. + * + * @param tsx The transaction. + * @param code The status code to report. */ PJ_DECL(void) pjsip_tsx_terminate( pjsip_transaction *tsx, int code ); /** * Create transaction key, which is used to match incoming requests - * or response (retransmissions) against transactions. - * @param pool The pool - * @param key Output key. - * @param role The role of the transaction. - * @param method The method to be put as a key. - * @param rdata The received data to calculate. - */ -PJ_DECL(void) pjsip_tsx_create_key( pj_pool_t *pool, - pj_str_t *key, - pjsip_role_e role, - const pjsip_method *method, - const pjsip_rx_data *rdata ); + * or response (retransmissions) against transactions. + * + * @param pool The pool + * @param key Output key. + * @param role The role of the transaction. + * @param method The method to be put as a key. + * @param rdata The received data to calculate. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, + pj_str_t *key, + pjsip_role_e role, + const pjsip_method *method, + const pjsip_rx_data *rdata ); + /** * @} @@ -183,7 +230,7 @@ PJ_DECL(const char *) pjsip_role_name(pjsip_role_e role); /* Thread Local Storage ID for transaction lock (initialized by endpoint) */ -extern int pjsip_tsx_lock_tls_id; +extern long pjsip_tsx_lock_tls_id; PJ_END_DECL diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 29b5d8d1..dd3baea9 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_TRANSPORT_H__ #define __PJSIP_SIP_TRANSPORT_H__ @@ -13,6 +12,7 @@ #include #include #include +#include PJ_BEGIN_DECL @@ -36,10 +36,13 @@ PJ_BEGIN_DECL */ struct pjsip_rx_data { - PJ_DECL_LIST_MEMBER(struct pjsip_rx_data) + //PJ_DECL_LIST_MEMBER(struct pjsip_rx_data); /** Memory pool for this buffer. */ pj_pool_t *pool; + + /** Ioqueue op key. */ + pj_ioqueue_op_key_t op_key; /** Time when the message was received. */ pj_time_val timestamp; @@ -73,21 +76,33 @@ struct pjsip_rx_data /** The From header as found in the message. */ pjsip_from_hdr *from; - /** The tag in the From header as found in the message. */ - pj_str_t from_tag; - /** The To header as found in the message. */ pjsip_to_hdr *to; - /** The To tag header as found in the message. */ - pj_str_t to_tag; - /** The topmost Via header as found in the message. */ pjsip_via_hdr *via; /** The CSeq header as found in the message. */ pjsip_cseq_hdr *cseq; - + + /** Max forwards header. */ + pjsip_max_forwards_hdr *max_fwd; + + /** The first route header. */ + pjsip_route_hdr *route; + + /** The first record-route header. */ + pjsip_rr_hdr *record_route; + + /** Content-type header. */ + pjsip_ctype_hdr *ctype; + + /** Content-length header. */ + pjsip_clen_hdr *clen; + + /** The first Require header. */ + pjsip_require_hdr *require; + /** The list of error generated by the parser when parsing this message. */ pjsip_parser_err_report parse_err; }; @@ -109,7 +124,7 @@ struct pjsip_rx_data */ struct pjsip_tx_data { - PJ_DECL_LIST_MEMBER(struct pjsip_tx_data) + PJ_DECL_LIST_MEMBER(struct pjsip_tx_data); /** Memory pool for this buffer. */ pj_pool_t *pool; @@ -126,6 +141,9 @@ struct pjsip_tx_data /** The transport manager for this buffer. */ pjsip_transport_mgr *mgr; + + /** Ioqueue asynchronous operation key. */ + pj_ioqueue_op_key_t op_key; /** The message in this buffer. */ pjsip_msg *msg; @@ -355,14 +373,16 @@ pjsip_transport_get_remote_addr( const pjsip_transport_t * tr ); * * @param tr The transport to send the message. * @param tdata The outgoing message buffer. - * @param addr The remote address. + * @param addr The remote address. + * @param sent If not null, it will be filled up with the length of + * data sent. * - * @return The number of bytes sent, or zero if the connection - * has closed, or -1 on error. + * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(int) pjsip_transport_send_msg( pjsip_transport_t *tr, - pjsip_tx_data *tdata, - const pj_sockaddr_in *addr); +PJ_DECL(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr, + pjsip_tx_data *tdata, + const pj_sockaddr_in *addr, + pj_ssize_t *sent); /** @@ -386,7 +406,8 @@ PJ_DECL(int) pjsip_transport_send_msg( pjsip_transport_t *tr, * @param mgr The transport manager. * @return The transmit buffer data, or NULL on error. */ -pjsip_tx_data* pjsip_tx_data_create( pjsip_transport_mgr *mgr ); +pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr, + pjsip_tx_data **tdata ); /** diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h index 33e8ca03..64f5f3ae 100644 --- a/pjsip/include/pjsip/sip_types.h +++ b/pjsip/include/pjsip/sip_types.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_TYPES_H__ #define __PJSIP_SIP_TYPES_H__ @@ -71,6 +70,11 @@ typedef struct pjsip_rx_data pjsip_rx_data; * Forward declaration for message (sip_msg.h). */ typedef struct pjsip_msg pjsip_msg; + +/** + * Forward declaration for header field (sip_msg.h). + */ +typedef struct pjsip_hdr pjsip_hdr; /** * Forward declaration for URI (sip_uri.h). @@ -132,7 +136,26 @@ typedef struct pjsip_host_port pj_str_t host; /**< Host part. */ int port; /**< Port number. */ } pjsip_host_port; - + + +/** + * Convert exception ID into pj_status_t status. + * + * @param exception_id Exception Id. + * + * @return Error code for the specified exception Id. + */ +PJ_DECL(pj_status_t) pjsip_exception_to_status(int exception_id); + +/** + * Return standard pj_status_t status from current exception. + */ +#define PJSIP_RETURN_EXCEPTION() pjsip_exception_to_status(PJ_GET_EXCEPTION()) + +/** + * Attributes to inform that the function may throw exceptions. + */ +#define PJSIP_THROW_SPEC(list) #endif /* __PJSIP_SIP_TYPES_H__ */ diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h index c43bc3df..8d72d0ae 100644 --- a/pjsip/include/pjsip/sip_uri.h +++ b/pjsip/include/pjsip/sip_uri.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_SIP_URI_H__ #define __PJSIP_SIP_URI_H__ diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip_core.h index acce9cc6..96b39488 100644 --- a/pjsip/include/pjsip_core.h +++ b/pjsip/include/pjsip_core.h @@ -1,5 +1,4 @@ /* $Id$ - * */ #ifndef __PJSIP_CORE_H__ #define __PJSIP_CORE_H__ diff --git a/pjsip/src/pjsip/print.h b/pjsip/src/pjsip/print.h deleted file mode 100644 index d1b9850c..00000000 --- a/pjsip/src/pjsip/print.h +++ /dev/null @@ -1,100 +0,0 @@ -/* $Id$ - * - */ -#ifndef __PJSIP_PRINT_H__ -#define __PJSIP_PRINT_H__ - -#define copy_advance_check(buf,str) \ - do { \ - if ((str).slen+10 >= (endbuf-buf)) return -1; \ - pj_memcpy(buf, (str).ptr, (str).slen); \ - buf += (str).slen; \ - } while (0) - -/* -static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, int len1, const pj_str_t *str2) -{ - if (str2->slen) { - int printed = len1+str2->slen; - if (printed+10 >= (endbuf-buf)) return NULL; - pj_memcpy(buf,str1,len1); - pj_memcpy(buf+len1, str2->ptr, str2->slen); - return buf + printed; - } else - return buf; -} -*/ - -#define copy_advance_pair_check(buf,str1,len1,str2) \ - do { \ - if (str2.slen) { \ - printed = len1+str2.slen; \ - if (printed+10 >= (endbuf-buf)) return -1; \ - pj_memcpy(buf,str1,len1); \ - pj_memcpy(buf+len1, str2.ptr, str2.slen); \ - buf += printed; \ - } \ - } while (0) -/* -#define copy_advance_pair(buf,str1,len1,str2) \ - do { \ - buf = imp_copy_advance_pair(buf, endbuf, str1, len1, &str2); \ - if (buf == NULL) return -1; \ - } while (0) -*/ - -#define copy_advance_pair_quote_check(buf,str1,len1,str2,quotebegin,quoteend) \ - do { \ - if (str2.slen) { \ - printed = len1+str2.slen+2; \ - if (printed+10 >= (endbuf-buf)) return -1; \ - pj_memcpy(buf,str1,len1); \ - *(buf+len1)=quotebegin; \ - pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \ - *(buf+printed-1) = quoteend; \ - buf += printed; \ - } \ - } while (0) - -#define copy_advance_no_check(buf,str) \ - pj_memcpy(buf, (str).ptr, (str).slen); \ - buf += (str).slen; - -#define copy_advance_pair_no_check(buf,str1,len1,str2) \ - if (str2.slen) { \ - pj_memcpy(buf,str1,len1); \ - pj_memcpy(buf+len1, str2.ptr, str2.slen); \ - buf += len1+str2.slen; \ - } - -#define copy_advance copy_advance_check -#define copy_advance_pair copy_advance_pair_check -#define copy_advance_pair_quote copy_advance_pair_quote_check - -#define copy_advance_pair_quote_cond(buf,str1,len1,str2,quotebegin,quoteend) \ - do { \ - if (str2.slen && *str2.ptr!=quotebegin) \ - copy_advance_pair_quote(buf,str1,len1,str2,quotebegin,quoteend); \ - else \ - copy_advance_pair(buf,str1,len1,str2); \ - } while (0) - -/* - * Internal type declarations. - */ -typedef void* (*pjsip_hdr_clone_fptr)(pj_pool_t *, const void*); -typedef int (*pjsip_hdr_print_fptr)(void *hdr, char *buf, pj_size_t len); - -extern const pj_str_t pjsip_hdr_names[]; - -PJ_INLINE(void) init_hdr(void *hptr, pjsip_hdr_e htype, void *vptr) -{ - pjsip_hdr *hdr = hptr; - hdr->type = htype; - hdr->name = hdr->sname = pjsip_hdr_names[htype]; - hdr->vptr = vptr; - pj_list_init(hdr); -} - -#endif /* __PJSIP_PRINT_H__ */ - diff --git a/pjsip/src/pjsip/sip_auth.c b/pjsip/src/pjsip/sip_auth.c index 91e91862..030b4a40 100644 --- a/pjsip/src/pjsip/sip_auth.c +++ b/pjsip/src/pjsip/sip_auth.c @@ -1,15 +1,16 @@ /* $Id$ - * */ #include #include /* just to get pjsip_DIGEST_STR */ #include #include -#include +#include #include #include #include -#include +#include +#include +#include /* Length of digest string. */ #define MD5STRLEN 32 @@ -146,7 +147,7 @@ static pj_bool_t has_auth_qop( pj_pool_t *pool, const pj_str_t *qop_offer) pj_strdup_with_null( pool, &qop, qop_offer); p = qop.ptr; while (*p) { - *p = (char)tolower(*p); + *p = (char)pj_tolower(*p); ++p; } @@ -217,7 +218,7 @@ static pj_status_t respond_digest( pj_pool_t *pool, */ cred->qop = pjsip_AUTH_STR; cred->nc.ptr = pj_pool_alloc(pool, 16); - sprintf(cred->nc.ptr, "%06u", nc); + pj_snprintf(cred->nc.ptr, 16, "%06u", nc); if (cnonce && cnonce->slen) { pj_strdup(pool, &cred->cnonce, cnonce); @@ -484,7 +485,7 @@ PJ_DEF(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count, const pj_str_t *scheme) { unsigned i; - PJ_UNUSED_ARG(scheme) + PJ_UNUSED_ARG(scheme); for (i=0; imsg->type == PJSIP_RESPONSE_MSG); pj_assert(rdata->msg->line.status.code == 401 || diff --git a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c index a5d52f10..9e88ef4a 100644 --- a/pjsip/src/pjsip/sip_auth_msg.c +++ b/pjsip/src/pjsip/sip_auth_msg.c @@ -1,12 +1,12 @@ /* $Id$ - * */ #include #include #include #include -#include -#include +#include +#include +#include /////////////////////////////////////////////////////////////////////////////// /* @@ -67,9 +67,9 @@ static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_ static int print_pgp_credential(pjsip_pgp_credential *cred, char *buf, pj_size_t size) { - PJ_UNUSED_ARG(cred) - PJ_UNUSED_ARG(buf) - PJ_UNUSED_ARG(size) + PJ_UNUSED_ARG(cred); + PJ_UNUSED_ARG(buf); + PJ_UNUSED_ARG(size); return -1; } @@ -212,9 +212,9 @@ static int print_digest_challenge( pjsip_digest_challenge *chal, static int print_pgp_challenge( pjsip_pgp_challenge *chal, char *buf, pj_size_t size) { - PJ_UNUSED_ARG(chal) - PJ_UNUSED_ARG(buf) - PJ_UNUSED_ARG(size) + PJ_UNUSED_ARG(chal); + PJ_UNUSED_ARG(buf); + PJ_UNUSED_ARG(size); return -1; } diff --git a/pjsip/src/pjsip/sip_auth_parser.c b/pjsip/src/pjsip/sip_auth_parser.c index 2f5a3baf..5e121b50 100644 --- a/pjsip/src/pjsip/sip_auth_parser.c +++ b/pjsip/src/pjsip/sip_auth_parser.c @@ -1,21 +1,25 @@ /* $Id$ - * */ #include #include -#include +#include +#include #include #include -static pjsip_authorization_hdr* parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool); -static pjsip_proxy_authorization_hdr* parse_hdr_proxy_authorization( pj_scanner *scanner, pj_pool_t *pool); -static pjsip_www_authenticate_hdr* parse_hdr_www_authenticate( pj_scanner *scanner, pj_pool_t *pool); -static pjsip_proxy_authenticate_hdr* parse_hdr_proxy_authenticate( pj_scanner *scanner, pj_pool_t *pool); +static pjsip_hdr* parse_hdr_authorization ( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_www_authenticate ( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_proxy_authenticate ( pjsip_parse_ctx *ctx ); -static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_credential *cred); -static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip_pgp_credential *cred); -static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_challenge *chal); -static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_pgp_challenge *chal); +static void parse_digest_credential ( pj_scanner *scanner, pj_pool_t *pool, + pjsip_digest_credential *cred); +static void parse_pgp_credential ( pj_scanner *scanner, pj_pool_t *pool, + pjsip_pgp_credential *cred); +static void parse_digest_challenge ( pj_scanner *scanner, pj_pool_t *pool, + pjsip_digest_challenge *chal); +static void parse_pgp_challenge ( pj_scanner *scanner, pj_pool_t *pool, + pjsip_pgp_challenge *chal); const pj_str_t pjsip_USERNAME_STR = { "username", 8 }, pjsip_REALM_STR = { "realm", 5}, @@ -43,12 +47,13 @@ const pj_str_t pjsip_USERNAME_STR = { "username", 8 }, pjsip_QUOTED_AUTH_STR = { "\"auth\"", 6 }; -static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_credential *cred) +static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, + pjsip_digest_credential *cred) { for (;;) { pj_str_t name, value; - pjsip_parse_param_imp(scanner, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); + pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) { cred->username = value; @@ -81,32 +86,34 @@ static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip cred->nc = value; } else { - pjsip_concat_param_imp(&cred->other_param, pool, &name, &value, ','); + pjsip_concat_param_imp(&cred->other_param,pool,&name,&value, ','); } /* Eat comma */ - if (!pj_scan_is_eof(scanner) && *scanner->current == ',') + if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') pj_scan_get_char(scanner); else break; } } -static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, pjsip_pgp_credential *cred) +static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, + pjsip_pgp_credential *cred) { - PJ_UNUSED_ARG(scanner) - PJ_UNUSED_ARG(pool) - PJ_UNUSED_ARG(cred) + PJ_UNUSED_ARG(scanner); + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(cred); PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); } -static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_digest_challenge *chal) +static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, + pjsip_digest_challenge *chal) { for (;;) { pj_str_t name, value; - pjsip_parse_param_imp(scanner, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); + pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp(&name, &pjsip_REALM_STR)) { chal->realm = value; @@ -121,8 +128,11 @@ static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_ chal->opaque = value; } else if (!pj_stricmp(&name, &pjsip_STALE_STR)) { - if (!pj_stricmp(&value, &pjsip_TRUE_STR) || !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR)) - chal->stale = 1; + if (!pj_stricmp(&value, &pjsip_TRUE_STR) || + !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR)) + { + chal->stale = 1; + } } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { chal->algorithm = value; @@ -132,35 +142,37 @@ static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_ chal->qop = value; } else { - pjsip_concat_param_imp(&chal->other_param, pool, &name, &value, ','); + pjsip_concat_param_imp(&chal->other_param, pool, + &name, &value, ','); } /* Eat comma */ - if (!pj_scan_is_eof(scanner) && *scanner->current == ',') + if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') pj_scan_get_char(scanner); else break; } } -static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, pjsip_pgp_challenge *chal) +static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, + pjsip_pgp_challenge *chal) { - PJ_UNUSED_ARG(scanner) - PJ_UNUSED_ARG(pool) - PJ_UNUSED_ARG(chal) + PJ_UNUSED_ARG(scanner); + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(chal); PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); } -static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool, +static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool, pjsip_authorization_hdr *hdr) { - if (*scanner->current == '"') { + if (*scanner->curptr == '"') { pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); hdr->scheme.ptr++; hdr->scheme.slen -= 2; } else { - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->scheme); + pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme); } if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { @@ -181,12 +193,12 @@ static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool, static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, pjsip_www_authenticate_hdr *hdr) { - if (*scanner->current == '"') { + if (*scanner->curptr == '"') { pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); hdr->scheme.ptr++; hdr->scheme.slen -= 2; } else { - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->scheme); + pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme); } if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { @@ -205,41 +217,56 @@ static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, } -static pjsip_authorization_hdr *parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx ) { - pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(pool); - int_parse_hdr_authorization(scanner, pool, hdr); - return hdr; + pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool); + int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); + return (pjsip_hdr*)hdr; } -static pjsip_proxy_authorization_hdr *parse_hdr_proxy_authorization( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx ) { - pjsip_proxy_authorization_hdr *hdr = pjsip_proxy_authorization_hdr_create(pool); - int_parse_hdr_authorization(scanner, pool, hdr); - return hdr; + pjsip_proxy_authorization_hdr *hdr = + pjsip_proxy_authorization_hdr_create(ctx->pool); + int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); + return (pjsip_hdr*)hdr; } -static pjsip_www_authenticate_hdr *parse_hdr_www_authenticate( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx ) { - pjsip_www_authenticate_hdr *hdr = pjsip_www_authenticate_hdr_create(pool); - int_parse_hdr_authenticate(scanner, pool, hdr); - return hdr; + pjsip_www_authenticate_hdr *hdr = + pjsip_www_authenticate_hdr_create(ctx->pool); + int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); + return (pjsip_hdr*)hdr; } -static pjsip_proxy_authenticate_hdr *parse_hdr_proxy_authenticate( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx ) { - pjsip_proxy_authenticate_hdr *hdr = pjsip_proxy_authenticate_hdr_create(pool); - int_parse_hdr_authenticate(scanner, pool, hdr); - return hdr; + pjsip_proxy_authenticate_hdr *hdr = + pjsip_proxy_authenticate_hdr_create(ctx->pool); + int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); + return (pjsip_hdr*)hdr; } -PJ_DEF(void) pjsip_auth_init_parser() -{ - pjsip_register_hdr_parser( "Authorization", NULL, (pjsip_parse_hdr_func*) &parse_hdr_authorization); - pjsip_register_hdr_parser( "Proxy-Authorization", NULL, (pjsip_parse_hdr_func*) &parse_hdr_proxy_authorization); - pjsip_register_hdr_parser( "WWW-Authenticate", NULL, (pjsip_parse_hdr_func*) &parse_hdr_www_authenticate); - pjsip_register_hdr_parser( "Proxy-Authenticate", NULL, (pjsip_parse_hdr_func*) &parse_hdr_proxy_authenticate); +PJ_DEF(pj_status_t) pjsip_auth_init_parser() +{ + pj_status_t status; + + status = pjsip_register_hdr_parser( "Authorization", NULL, + &parse_hdr_authorization); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL, + &parse_hdr_proxy_authorization); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL, + &parse_hdr_www_authenticate); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL, + &parse_hdr_proxy_authenticate); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); + + return PJ_SUCCESS; } PJ_DEF(void) pjsip_auth_deinit_parser() diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c index 321d2e34..49c70b1b 100644 --- a/pjsip/src/pjsip/sip_endpoint.c +++ b/pjsip/src/pjsip/sip_endpoint.c @@ -1,5 +1,4 @@ /* $Id$ - * */ #include #include @@ -7,17 +6,20 @@ #include #include #include -#include +#include +#include #include #include #include #include #include #include +#include +#include #define PJSIP_EX_NO_MEMORY PJ_NO_MEMORY_EXCEPTION -#define LOG_THIS "endpoint..." +#define THIS_FILE "endpoint" #define MAX_METHODS 32 @@ -84,7 +86,8 @@ static void endpt_transport_callback( pjsip_endpoint *, pjsip_rx_data *rdata ); * Create transaction. * Defined in sip_transaction.c */ -pjsip_transaction * pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt); +pj_status_t pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt, + pjsip_transaction **tsx ); /* * This is the global handler for memory allocation failure, for pools that @@ -94,8 +97,8 @@ pjsip_transaction * pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt); */ static void pool_callback( pj_pool_t *pool, pj_size_t size ) { - PJ_UNUSED_ARG(pool) - PJ_UNUSED_ARG(size) + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(size); PJ_THROW(PJSIP_EX_NO_MEMORY); } @@ -111,7 +114,7 @@ static pj_status_t init_modules( pjsip_endpoint *endpt ) //pj_str_t str_COMMA = { ", ", 2 }; extern pjsip_module aux_tsx_module; - PJ_LOG(5, (LOG_THIS, "init_modules()")); + PJ_LOG(5, (THIS_FILE, "init_modules()")); /* Load static modules. */ endpt->mod_count = PJSIP_MAX_MODULE; @@ -164,7 +167,7 @@ static pj_status_t init_modules( pjsip_endpoint *endpt ) if (endpt->method_cnt < MAX_METHODS) { endpt->methods[endpt->method_cnt++] = mod->methods[j]; } else { - PJ_LOG(1,(LOG_THIS, "Too many methods")); + PJ_LOG(1,(THIS_FILE, "Too many methods")); return -1; } } @@ -200,7 +203,7 @@ static pj_status_t init_modules( pjsip_endpoint *endpt ) PJ_DEF(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt, pjsip_transaction *tsx) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_destroy_tsx(%s)", tsx->obj_name)); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_tsx(%s)", tsx->obj_name)); pj_assert(tsx->state == PJSIP_TSX_STATE_DESTROYED); @@ -226,7 +229,7 @@ PJ_DEF(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt, /* Release the pool for the transaction. */ pj_pool_release(tsx->pool); - PJ_LOG(4, (LOG_THIS, "tsx%p destroyed", tsx)); + PJ_LOG(4, (THIS_FILE, "tsx%p destroyed", tsx)); } @@ -247,11 +250,11 @@ static void endpt_do_event( pjsip_endpoint *endpt, pjsip_event *evt) } /* Destroy transaction if it is terminated. */ - if (evt->type == PJSIP_EVENT_TSX_STATE_CHANGED && - evt->obj.tsx->state == PJSIP_TSX_STATE_DESTROYED) + if (evt->type == PJSIP_EVENT_TSX_STATE && + evt->body.tsx_state.tsx->state == PJSIP_TSX_STATE_DESTROYED) { /* No need to lock mutex. Mutex is locked inside the destroy function */ - pjsip_endpt_destroy_tsx( endpt, evt->obj.tsx ); + pjsip_endpt_destroy_tsx( endpt, evt->body.tsx_state.tsx ); } } @@ -260,7 +263,8 @@ static void endpt_do_event( pjsip_endpoint *endpt, pjsip_event *evt) * to be processed later. */ void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt ) -{ +{ + // Need to protect this with try/catch? endpt_do_event(endpt, evt); } @@ -301,7 +305,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt, hdr = pjsip_parse_hdr(endpt->pool, &str_ROUTE, dup, len, NULL); if (!hdr) { pj_mutex_unlock(endpt->mutex); - PJ_LOG(4,(LOG_THIS, "Invalid URL %s in proxy URL", dup)); + PJ_LOG(4,(THIS_FILE, "Invalid URL %s in proxy URL", dup)); return -1; } @@ -327,21 +331,24 @@ PJ_DEF(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt ) /* * Initialize endpoint. */ -PJ_DEF(pjsip_endpoint*) pjsip_endpt_create(pj_pool_factory *pf) +PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf, + pjsip_endpoint **p_endpt) { pj_status_t status; pj_pool_t *pool; pjsip_endpoint *endpt; pjsip_max_forwards_hdr *mf_hdr; - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create()")); + + *p_endpt = NULL; /* Create pool */ pool = pj_pool_create(pf, "pept%p", PJSIP_POOL_LEN_ENDPT, PJSIP_POOL_INC_ENDPT, &pool_callback); if (!pool) - return NULL; + return PJ_ENOMEM; /* Create endpoint. */ endpt = pj_pool_calloc(pool, 1, sizeof(*endpt)); @@ -349,53 +356,51 @@ PJ_DEF(pjsip_endpoint*) pjsip_endpt_create(pj_pool_factory *pf) endpt->pf = pf; /* Create mutex for the events, etc. */ - endpt->mutex = pj_mutex_create( endpt->pool, "ept%p", 0 ); - if (!endpt->mutex) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating endpoint mutex")); + status = pj_mutex_create_recursive( endpt->pool, "ept%p", &endpt->mutex ); + if (status != PJ_SUCCESS) { goto on_error; } /* Create mutex for the transaction table. */ - endpt->tsx_table_mutex = pj_mutex_create( endpt->pool, "mtbl%p", 0); - if (!endpt->tsx_table_mutex) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating endpoint mutex(2)")); + status = pj_mutex_create_recursive( endpt->pool, "mtbl%p", + &endpt->tsx_table_mutex); + if (status != PJ_SUCCESS) { goto on_error; } /* Create hash table for transaction. */ endpt->tsx_table = pj_hash_create( endpt->pool, PJSIP_MAX_TSX_COUNT ); if (!endpt->tsx_table) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating tsx hash table")); + status = PJ_ENOMEM; goto on_error; } /* Create timer heap to manage all timers within this endpoint. */ - endpt->timer_heap = pj_timer_heap_create( endpt->pool, PJSIP_MAX_TIMER_COUNT, 0); - if (!endpt->timer_heap) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating timer heap")); + status = pj_timer_heap_create( endpt->pool, PJSIP_MAX_TIMER_COUNT, + &endpt->timer_heap); + if (status != PJ_SUCCESS) { goto on_error; } /* Create transport manager. */ - endpt->transport_mgr = pjsip_transport_mgr_create( endpt->pool, - endpt, - &endpt_transport_callback); - if (!endpt->transport_mgr) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating transport mgr")); + status = pjsip_transport_mgr_create( endpt->pool, + endpt, + &endpt_transport_callback, + &endpt->transport_mgr); + if (status != PJ_SUCCESS) { goto on_error; } /* Create asynchronous DNS resolver. */ endpt->resolver = pjsip_resolver_create(endpt->pool); if (!endpt->resolver) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error creating resolver")); + PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error creating resolver")); goto on_error; } /* Initialize TLS ID for transaction lock. */ - pjsip_tsx_lock_tls_id = pj_thread_local_alloc(); - if (pjsip_tsx_lock_tls_id == -1) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error allocating TLS")); + status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id); + if (status != PJ_SUCCESS) { goto on_error; } pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL); @@ -414,12 +419,13 @@ PJ_DEF(pjsip_endpoint*) pjsip_endpt_create(pj_pool_factory *pf) /* Load and init modules. */ status = init_modules(endpt); if (status != PJ_SUCCESS) { - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init(): error in init_modules()")); - return NULL; + PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error in init_modules()")); + return status; } - /* Done. */ - return endpt; + /* Done. */ + *p_endpt = endpt; + return status; on_error: if (endpt->transport_mgr) { @@ -436,8 +442,8 @@ on_error: } pj_pool_release( endpt->pool ); - PJ_LOG(4, (LOG_THIS, "pjsip_endpt_init() failed")); - return NULL; + PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init() failed")); + return status; } /* @@ -445,7 +451,7 @@ on_error: */ PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_destroy()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy()")); /* Shutdown and destroy all transports. */ pjsip_transport_mgr_destroy(endpt->transport_mgr); @@ -470,7 +476,7 @@ PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt, { pj_pool_t *pool; - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create_pool()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_pool()")); /* Lock endpoint mutex. */ pj_mutex_lock(endpt->mutex); @@ -483,9 +489,9 @@ PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt, pj_mutex_unlock(endpt->mutex); if (pool) { - PJ_LOG(5, (LOG_THIS, " pool %s created", pj_pool_getobjname(pool))); + PJ_LOG(5, (THIS_FILE, " pool %s created", pj_pool_getobjname(pool))); } else { - PJ_LOG(4, (LOG_THIS, "Unable to create pool %s!", pool_name)); + PJ_LOG(4, (THIS_FILE, "Unable to create pool %s!", pool_name)); } return pool; @@ -497,7 +503,7 @@ PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt, */ PJ_DEF(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt, pj_pool_t *pool ) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_destroy_pool(%s)", pj_pool_getobjname(pool))); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_pool(%s)", pj_pool_getobjname(pool))); pj_mutex_lock(endpt->mutex); pj_pool_release( pool ); @@ -513,7 +519,7 @@ PJ_DEF(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt, pj_time_val timeout; int i; - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_handle_events()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_handle_events()")); /* Poll the timer. The timer heap has its own mutex for better * granularity, so we don't need to lock end endpoint. We also keep @@ -543,7 +549,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt, pj_timer_entry *entry, const pj_time_val *delay ) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)", + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)", entry, delay->sec, delay->msec)); return pj_timer_heap_schedule( endpt->timer_heap, entry, delay ); } @@ -554,7 +560,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt, PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, pj_timer_entry *entry ) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_cancel_timer(entry=%p)", entry)); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry)); pj_timer_heap_cancel( endpt->timer_heap, entry ); } @@ -563,26 +569,24 @@ PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, * Endpoint must then initialize the new transaction as either UAS or UAC, and * register it to the hash table. */ -PJ_DEF(pjsip_transaction*) pjsip_endpt_create_tsx(pjsip_endpoint *endpt) +PJ_DEF(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt, + pjsip_transaction **p_tsx) { pj_pool_t *pool; - pjsip_transaction *tsx; + + PJ_ASSERT_RETURN(endpt && p_tsx, PJ_EINVAL); - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create_tsx()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tsx()")); /* Request one pool for the transaction. Mutex is locked there. */ pool = pjsip_endpt_create_pool(endpt, "ptsx%p", PJSIP_POOL_LEN_TSX, PJSIP_POOL_INC_TSX); if (pool == NULL) { - PJ_LOG(2, (LOG_THIS, "failed to create transaction (no pool)")); - return NULL; + return PJ_ENOMEM; } /* Create the transaction. */ - tsx = pjsip_tsx_create(pool, endpt); - - /* Return */ - return tsx; + return pjsip_tsx_create(pool, endpt, p_tsx); } /* @@ -594,7 +598,7 @@ PJ_DEF(pjsip_transaction*) pjsip_endpt_create_tsx(pjsip_endpoint *endpt) PJ_DEF(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt, pjsip_transaction *tsx) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_register_tsx(%s)", tsx->obj_name)); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_register_tsx(%s)", tsx->obj_name)); pj_assert(tsx->transaction_key.slen != 0); //pj_assert(tsx->state != PJSIP_TSX_STATE_NULL); @@ -618,7 +622,7 @@ PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt, { pjsip_transaction *tsx; - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_find_tsx()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_find_tsx()")); /* Start lock mutex in the endpoint. */ pj_mutex_lock(endpt->tsx_table_mutex); @@ -658,7 +662,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, pjsip_transaction *tsx; pj_bool_t a_new_transaction_just_been_created = PJ_FALSE; - PJ_LOG(5, (LOG_THIS, "endpt_transport_callback(rdata=%p)", rdata)); + PJ_LOG(5, (THIS_FILE, "endpt_transport_callback(rdata=%p)", rdata)); /* For response, check that the value in Via sent-by match the transport. * If not matched, silently drop the response. @@ -675,10 +679,10 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, port = pjsip_transport_get_default_port_for_type(type); } addr = pjsip_transport_get_addr_name(rdata->transport); - addr_addr = pj_sockaddr_get_str_addr(addr); + addr_addr = pj_inet_ntoa(addr->sin_addr); if (pj_strcmp2(&rdata->via->sent_by.host, addr_addr) != 0) mismatch = PJ_TRUE; - else if (port != pj_sockaddr_get_port(addr)) { + else if (port != pj_ntohs(addr->sin_port)) { /* Port or address mismatch, we should discard response */ /* But we saw one implementation (we don't want to name it to * protect the innocence) which put wrong sent-by port although @@ -686,10 +690,10 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, * So we discard the response only if the port doesn't match * both the port in sent-by and rport. We try to be lenient here! */ - if (rdata->via->rport_param != pj_sockaddr_get_port(addr)) + if (rdata->via->rport_param != pj_sockaddr_in_get_port(addr)) mismatch = PJ_TRUE; else { - PJ_LOG(4,(LOG_THIS, "Response %p has mismatch port in sent-by" + PJ_LOG(4,(THIS_FILE, "Response %p has mismatch port in sent-by" " but the rport parameter is correct", rdata)); } @@ -698,13 +702,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, if (mismatch) { pjsip_event e; - PJ_LOG(3, (LOG_THIS, "Response %p discarded: sent-by mismatch", - rdata)); - - e.type = PJSIP_EVENT_DISCARD_MSG; - e.src_type = PJSIP_EVENT_RX_MSG; - e.src.rdata = rdata; - e.obj.ptr = NULL; + PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, PJSIP_EINVALIDVIA); endpt_do_event( endpt, &e ); return; } @@ -714,7 +712,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, rdata_create_key( rdata); /* Find the transaction for the received message. */ - PJ_LOG(5, (LOG_THIS, "finding tsx with key=%.*s", + PJ_LOG(5, (THIS_FILE, "finding tsx with key=%.*s", rdata->key.slen, rdata->key.ptr)); /* Start lock mutex in the endpoint. */ @@ -747,34 +745,32 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, */ pj_assert(0); - e.type = PJSIP_EVENT_RX_200_RESPONSE; - e.src_type = PJSIP_EVENT_RX_MSG; - e.src.rdata = rdata; - e.obj.ptr = NULL; + PJSIP_EVENT_INIT_RX_200_MSG(e, rdata); endpt_do_event( endpt, &e ); } else { /* Just discard the response, inform TU. */ pjsip_event e; - PJ_LOG(3, (LOG_THIS, "Response %p discarded: transaction not found", - rdata)); - - e.type = PJSIP_EVENT_DISCARD_MSG; - e.src_type = PJSIP_EVENT_RX_MSG; - e.src.rdata = rdata; - e.obj.ptr = NULL; + PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, + PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_CALL_TSX_DOES_NOT_EXIST)); endpt_do_event( endpt, &e ); } /* * For non-ACK request message, create a new transaction. */ - } else if (rdata->msg->line.req.method.id != PJSIP_ACK_METHOD) { + } else if (rdata->msg->line.req.method.id != PJSIP_ACK_METHOD) { + + pj_status_t status; + /* Create transaction, mutex is locked there. */ - tsx = pjsip_endpt_create_tsx(endpt); - if (!tsx) - return; + status = pjsip_endpt_create_tsx(endpt, &tsx); + if (status != PJ_SUCCESS) { + PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, + "Unable to create transaction")); + return; + } /* Initialize transaction as UAS. */ pjsip_tsx_init_uas( tsx, rdata ); @@ -802,10 +798,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, */ pjsip_event event; - event.type = PJSIP_EVENT_RX_ACK_MSG; - event.src_type = PJSIP_EVENT_RX_MSG; - event.src.rdata = rdata; - event.obj.ptr = NULL; + PJSIP_EVENT_INIT_RX_ACK_MSG(event,rdata); endpt_do_event( endpt, &event ); } @@ -833,14 +826,24 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, /* No modules have attached itself to the transaction. * Terminate the transaction with 501/Not Implemented. */ - pjsip_tx_data *tdata; + pjsip_tx_data *tdata; + pj_status_t status; if (tsx->method.id == PJSIP_OPTIONS_METHOD) { - tdata = pjsip_endpt_create_response(endpt, rdata, 200); + status = pjsip_endpt_create_response(endpt, rdata, 200, + &tdata); } else { - tdata = pjsip_endpt_create_response(endpt, rdata, - PJSIP_SC_METHOD_NOT_ALLOWED); - } + status = pjsip_endpt_create_response(endpt, rdata, + PJSIP_SC_METHOD_NOT_ALLOWED, + &tdata); + } + + if (status != PJ_SUCCESS) { + PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, + "Unable to create response")); + return; + } + if (endpt->allow_hdr) { pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, endpt->allow_hdr)); @@ -854,8 +857,16 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, * respond to the request at all. We terminate the request here * with 500/Internal Server Error, to be safe. */ - pjsip_tx_data *tdata; - tdata = pjsip_endpt_create_response(endpt, rdata, 500); + pjsip_tx_data *tdata; + pj_status_t status; + + status = pjsip_endpt_create_response(endpt, rdata, 500, &tdata); + if (status != PJ_SUCCESS) { + PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, + "Unable to create response")); + return; + } + pjsip_tsx_on_tx_msg(tsx, tdata); } } @@ -864,10 +875,11 @@ static void endpt_transport_callback( pjsip_endpoint *endpt, /* * Create transmit data buffer. */ -PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_tdata( pjsip_endpoint *endpt ) +PJ_DEF(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt, + pjsip_tx_data **p_tdata) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create_tdata()")); - return pjsip_tx_data_create(endpt->transport_mgr); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tdata()")); + return pjsip_tx_data_create(endpt->transport_mgr, p_tdata); } /* @@ -879,7 +891,7 @@ PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt, void *token, pjsip_resolver_callback *cb) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_resolve()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_resolve()")); pjsip_resolve( endpt->resolver, pool, target, token, cb); } @@ -893,7 +905,7 @@ PJ_DEF(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt, void *token, pjsip_transport_completion_callback *cb) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_get_transport()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_get_transport()")); pjsip_transport_get( endpt->transport_mgr, pool, type, remote, token, cb); } @@ -904,7 +916,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt, pj_sockaddr_in *addr, const pj_sockaddr_in *addr_name) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create_listener()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_listener()")); return pjsip_create_listener( endpt->transport_mgr, type, addr, addr_name ); } @@ -912,7 +924,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt, pj_sock_t sock, const pj_sockaddr_in *addr_name) { - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_create_udp_listener()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_udp_listener()")); return pjsip_create_udp_listener( endpt->transport_mgr, sock, addr_name ); } @@ -923,31 +935,31 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) pj_hash_iterator_t itr_val; pj_hash_iterator_t *itr; - PJ_LOG(5, (LOG_THIS, "pjsip_endpt_dump()")); + PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()")); /* Lock mutex. */ pj_mutex_lock(endpt->mutex); - PJ_LOG(3, (LOG_THIS, "Dumping endpoint %p:", endpt)); + PJ_LOG(3, (THIS_FILE, "Dumping endpoint %p:", endpt)); /* Dumping pool factory. */ (*endpt->pf->dump_status)(endpt->pf, detail); /* Pool health. */ - PJ_LOG(3, (LOG_THIS," Endpoint pool capacity=%u, used_size=%u", + PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%u, used_size=%u", pj_pool_get_capacity(endpt->pool), pj_pool_get_used_size(endpt->pool))); /* Transaction tables. */ count = pj_hash_count(endpt->tsx_table); - PJ_LOG(3, (LOG_THIS, " Number of transactions: %u", count)); + PJ_LOG(3, (THIS_FILE, " Number of transactions: %u", count)); if (count && detail) { pj_hash_iterator_t it_val; pj_hash_iterator_t *it; pj_time_val now; - PJ_LOG(3, (LOG_THIS, " Dumping transaction tables:")); + PJ_LOG(3, (THIS_FILE, " Dumping transaction tables:")); pj_gettimeofday(&now); it = pj_hash_first(endpt->tsx_table, &it_val); @@ -974,7 +986,7 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) timeout_diff = -1; } - PJ_LOG(3, (LOG_THIS, " %s %s %10.*s %.9u %s t=%ds", + PJ_LOG(3, (THIS_FILE, " %s %s %10.*s %.9u %s t=%ds", tsx->obj_name, role, tsx->method.name.slen, tsx->method.name.ptr, tsx->cseq, @@ -991,7 +1003,7 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) */ itr = pjsip_transport_first( endpt->transport_mgr, &itr_val ); if (itr) { - PJ_LOG(3, (LOG_THIS, " Dumping transports:")); + PJ_LOG(3, (THIS_FILE, " Dumping transports:")); do { char src_addr[128], dst_addr[128]; @@ -1001,14 +1013,14 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) t = pjsip_transport_this(endpt->transport_mgr, itr); addr = pjsip_transport_get_local_addr(t); - strcpy(src_addr, pj_sockaddr_get_str_addr(addr)); - src_port = pj_sockaddr_get_port(addr); + pj_native_strcpy(src_addr, pj_inet_ntoa(addr->sin_addr)); + src_port = pj_ntohs(addr->sin_port); addr = pjsip_transport_get_remote_addr(t); - strcpy(dst_addr, pj_sockaddr_get_str_addr(addr)); - dst_port = pj_sockaddr_get_port(addr); + pj_native_strcpy(dst_addr, pj_inet_ntoa(addr->sin_addr)); + dst_port = pj_ntohs(addr->sin_port); - PJ_LOG(3, (LOG_THIS, " %s %s %s:%d --> %s:%d (refcnt=%d)", + PJ_LOG(3, (THIS_FILE, " %s %s %s:%d --> %s:%d (refcnt=%d)", pjsip_transport_get_type_name(t), pjsip_transport_get_obj_name(t), src_addr, src_port, @@ -1020,13 +1032,13 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) } /* Timer. */ - PJ_LOG(3,(LOG_THIS, " Timer heap has %u entries", + PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries", pj_timer_heap_count(endpt->timer_heap))); /* Unlock mutex. */ pj_mutex_unlock(endpt->mutex); #else - PJ_LOG(3,(LOG_THIS, "pjsip_end_dump: can't dump because it's disabled.")); + PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled.")); #endif } diff --git a/pjsip/src/pjsip/sip_misc.c b/pjsip/src/pjsip/sip_misc.c index 38a2e95c..a9562397 100644 --- a/pjsip/src/pjsip/sip_misc.c +++ b/pjsip/src/pjsip/sip_misc.c @@ -1,5 +1,4 @@ /* $Id$ - * */ #include #include @@ -13,8 +12,11 @@ #include #include #include +#include +#include +#include -#define LOG_THIS "endpoint..." +#define THIS_FILE "endpoint" static const char *event_str[] = { @@ -44,8 +46,8 @@ struct aux_tsx_data static pj_status_t aux_tsx_init( pjsip_endpoint *endpt, struct pjsip_module *mod, pj_uint32_t id ) { - PJ_UNUSED_ARG(endpt) - PJ_UNUSED_ARG(mod) + PJ_UNUSED_ARG(endpt); + PJ_UNUSED_ARG(mod); aux_mod_id = id; return 0; @@ -53,13 +55,16 @@ static pj_status_t aux_tsx_init( pjsip_endpoint *endpt, static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event ) { - pjsip_transaction *tsx = event->obj.tsx; + pjsip_transaction *tsx; struct aux_tsx_data *tsx_data; - PJ_UNUSED_ARG(mod) + PJ_UNUSED_ARG(mod); - if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED) - return; + if (event->type != PJSIP_EVENT_TSX_STATE) + return; + + pj_assert(event->body.tsx_state.tsx != NULL); + tsx = event->body.tsx_state.tsx; if (tsx == NULL) return; if (tsx->module_data[aux_mod_id] == NULL) @@ -99,9 +104,10 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, void (*cb)(void*,pjsip_event*)) { pjsip_transaction *tsx; - struct aux_tsx_data *tsx_data; + struct aux_tsx_data *tsx_data; + pj_status_t status; - tsx = pjsip_endpt_create_tsx(endpt); + status = pjsip_endpt_create_tsx(endpt, &tsx); if (!tsx) { pjsip_tx_data_dec_ref(tdata); return -1; @@ -134,7 +140,8 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, * That's why the session will shallow_clone it's headers before calling * this function. */ -static void init_request_throw( pjsip_tx_data *tdata, +static void init_request_throw( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, pjsip_method *method, pjsip_uri *param_target, pjsip_from_hdr *param_from, @@ -146,6 +153,7 @@ static void init_request_throw( pjsip_tx_data *tdata, { pjsip_msg *msg; pjsip_msg_body *body; + const pjsip_hdr *endpt_hdr; /* Create the message. */ msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG); @@ -153,7 +161,15 @@ static void init_request_throw( pjsip_tx_data *tdata, /* Init request URI. */ pj_memcpy(&msg->line.req.method, method, sizeof(*method)); msg->line.req.uri = param_target; - + + /* Add additional request headers from endpoint. */ + endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next; + while (endpt_hdr != pjsip_endpt_get_request_headers(endpt)) { + pjsip_hdr *hdr = pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr); + pjsip_msg_add_hdr( tdata->msg, hdr ); + endpt_hdr = endpt_hdr->next; + } + /* Add From header. */ if (param_from->tag.slen == 0) pj_create_unique_string(tdata->pool, ¶m_from->tag); @@ -189,15 +205,16 @@ static void init_request_throw( pjsip_tx_data *tdata, /* * Create arbitrary request. */ -PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, - const pjsip_method *method, - const pj_str_t *param_target, - const pj_str_t *param_from, - const pj_str_t *param_to, - const pj_str_t *param_contact, - const pj_str_t *param_call_id, - int param_cseq, - const pj_str_t *param_text) +PJ_DEF(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, + const pjsip_method *method, + const pj_str_t *param_target, + const pj_str_t *param_from, + const pj_str_t *param_to, + const pj_str_t *param_contact, + const pj_str_t *param_call_id, + int param_cseq, + const pj_str_t *param_text, + pjsip_tx_data **p_tdata) { pjsip_uri *target; pjsip_tx_data *tdata; @@ -206,14 +223,15 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, pjsip_contact_hdr *contact; pjsip_cseq_hdr *cseq = NULL; /* = NULL, warning in VC6 */ pjsip_cid_hdr *call_id; - pj_str_t tmp; + pj_str_t tmp; + pj_status_t status; PJ_USE_EXCEPTION; - PJ_LOG(5,(LOG_THIS, "Entering pjsip_endpt_create_request()")); + PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()")); - tdata = pjsip_endpt_create_tdata(endpt); - if (!tdata) - return NULL; + status = pjsip_endpt_create_tdata(endpt, &tdata); + if (status != PJ_SUCCESS) + return status; /* Init reference counter to 1. */ pjsip_tx_data_add_ref(tdata); @@ -223,7 +241,7 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, pj_strdup_with_null(tdata->pool, &tmp, param_target); target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0); if (target == NULL) { - PJ_LOG(4,(LOG_THIS, "Error creating request: invalid target %s", + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid target %s", tmp.ptr)); goto on_error; } @@ -234,7 +252,7 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (from->uri == NULL) { - PJ_LOG(4,(LOG_THIS, "Error creating request: invalid 'From' URI '%s'", + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'", tmp.ptr)); goto on_error; } @@ -246,7 +264,7 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (to->uri == NULL) { - PJ_LOG(4,(LOG_THIS, "Error creating request: invalid 'To' URI '%s'", + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'", tmp.ptr)); goto on_error; } @@ -258,7 +276,7 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (contact->uri == NULL) { - PJ_LOG(4,(LOG_THIS, + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'Contact' URI '%s'", tmp.ptr)); goto on_error; @@ -285,30 +303,30 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_request( pjsip_endpoint *endpt, pjsip_method_copy(tdata->pool, &cseq->method, method); /* Create the request. */ - init_request_throw( tdata, &cseq->method, target, from, to, contact, - call_id, cseq, param_text); + init_request_throw( endpt, tdata, &cseq->method, target, from, to, + contact, call_id, cseq, param_text); } PJ_DEFAULT { - PJ_LOG(4,(LOG_THIS, "Caught exception %d when creating request", - PJ_GET_EXCEPTION())); + status = PJ_ENOMEM; goto on_error; } PJ_END - PJ_LOG(4,(LOG_THIS, "Request %s (%d %.*s) created.", + PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", tdata->obj_name, cseq->cseq, cseq->method.name.slen, cseq->method.name.ptr)); - - return tdata; + + *p_tdata = tdata; + return PJ_SUCCESS; on_error: pjsip_tx_data_dec_ref(tdata); - return NULL; + return status; } -PJ_DEF(pjsip_tx_data*) +PJ_DEF(pj_status_t) pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, const pjsip_method *method, const pjsip_uri *param_target, @@ -317,7 +335,8 @@ pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, const pjsip_contact_hdr *param_contact, const pjsip_cid_hdr *param_call_id, int param_cseq, - const pj_str_t *param_text ) + const pj_str_t *param_text, + pjsip_tx_data **p_tdata) { pjsip_uri *target; pjsip_tx_data *tdata; @@ -325,14 +344,15 @@ pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, pjsip_to_hdr *to; pjsip_contact_hdr *contact; pjsip_cid_hdr *call_id; - pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */ + pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */ + pj_status_t status; PJ_USE_EXCEPTION; - PJ_LOG(5,(LOG_THIS, "Entering pjsip_endpt_create_request_from_hdr()")); + PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()")); - tdata = pjsip_endpt_create_tdata(endpt); - if (!tdata) - return NULL; + status = pjsip_endpt_create_tdata(endpt, &tdata); + if (status != PJ_SUCCESS) + return status; pjsip_tx_data_add_ref(tdata); @@ -354,53 +374,56 @@ pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, cseq->cseq = pj_rand() % 0xFFFF; pjsip_method_copy(tdata->pool, &cseq->method, method); - init_request_throw(tdata, &cseq->method, target, from, to, contact, - call_id, cseq, param_text); + init_request_throw(endpt, tdata, &cseq->method, target, from, to, + contact, call_id, cseq, param_text); } PJ_DEFAULT { - PJ_LOG(4,(LOG_THIS, "Caught exception %d when creating request", - PJ_GET_EXCEPTION())); + status = PJ_ENOMEM; goto on_error; } PJ_END; - PJ_LOG(4,(LOG_THIS, "Request %s (%d %.*s) created.", + PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", tdata->obj_name, cseq->cseq, cseq->method.name.slen, - cseq->method.name.ptr)); - return tdata; + cseq->method.name.ptr)); + + *p_tdata = tdata; + return PJ_SUCCESS; on_error: pjsip_tx_data_dec_ref(tdata); - return NULL; + return status; } /* * Construct a minimal response message for the received request. */ -PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_response( pjsip_endpoint *endpt, - const pjsip_rx_data *rdata, - int code) +PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt, + const pjsip_rx_data *rdata, + int code, + pjsip_tx_data **p_tdata) { pjsip_tx_data *tdata; pjsip_msg *msg, *req_msg; pjsip_hdr *hdr; pjsip_via_hdr *via; - pjsip_rr_hdr *rr; + pjsip_rr_hdr *rr; + pj_status_t status; /* rdata must be a request message. */ req_msg = rdata->msg; pj_assert(req_msg->type == PJSIP_REQUEST_MSG); /* Log this action. */ - PJ_LOG(5,(LOG_THIS, "pjsip_endpt_create_response(rdata=%p, code=%d)", + PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", rdata, code)); /* Create a new transmit buffer. */ - tdata = pjsip_endpt_create_tdata( endpt ); - if (!tdata) - return NULL; + status = pjsip_endpt_create_tdata( endpt, &tdata); + if (status != PJ_SUCCESS) + return status; /* Create new response message. */ tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG); @@ -450,8 +473,9 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_response( pjsip_endpoint *endpt, hdr = pjsip_hdr_clone(tdata->pool, rdata->cseq); pjsip_msg_add_hdr( msg, hdr); - /* All done. */ - return tdata; + /* All done. */ + *p_tdata = tdata; + return PJ_SUCCESS; } @@ -478,7 +502,7 @@ PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt, rdata->msg->line.status.code >= 300); /* Log this action. */ - PJ_LOG(5,(LOG_THIS, "pjsip_endpt_create_ack(rdata=%p)", rdata)); + PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata)); /* Create new request message. */ ack_msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG); @@ -502,7 +526,7 @@ PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt, /* Copy To header from the original INVITE. */ to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_TO, NULL); - pj_strdup(tdata->pool, &to->tag, &rdata->to_tag); + pj_strdup(tdata->pool, &to->tag, &rdata->to->tag); pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to ); /* Must contain single Via, just as the original INVITE. */ @@ -542,30 +566,33 @@ PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt, * Construct CANCEL request for the previously sent request, according to * chapter 9.1 of RFC3261. */ -PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, - pjsip_tx_data *req_tdata ) +PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, + pjsip_tx_data *req_tdata, + pjsip_tx_data **p_tdata) { pjsip_msg *req_msg; /* the original request. */ pjsip_tx_data *cancel_tdata; pjsip_msg *cancel_msg; pjsip_hdr *hdr; pjsip_cseq_hdr *req_cseq, *cseq; - pjsip_uri *req_uri; + pjsip_uri *req_uri; + pj_status_t status; /* Log this action. */ - PJ_LOG(5,(LOG_THIS, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata)); + PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata)); /* Get the original request. */ req_msg = req_tdata->msg; /* The transmit buffer must INVITE request. */ - pj_assert(req_msg->type == PJSIP_REQUEST_MSG && - req_msg->line.req.method.id == PJSIP_INVITE_METHOD ); + PJ_ASSERT_RETURN(req_msg->type == PJSIP_REQUEST_MSG && + req_msg->line.req.method.id == PJSIP_INVITE_METHOD, + PJ_EINVAL); /* Create new transmit buffer. */ - cancel_tdata = pjsip_endpt_create_tdata( endpt ); - if (!cancel_tdata) { - return NULL; + status = pjsip_endpt_create_tdata( endpt, &cancel_tdata); + if (status != PJ_SUCCESS) { + return status; } /* Create CANCEL request message. */ @@ -622,8 +649,9 @@ PJ_DEF(pjsip_tx_data*) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, /* Done. * Return the transmit buffer containing the CANCEL request. - */ - return cancel_tdata; + */ + *p_tdata = cancel_tdata; + return PJ_SUCCESS; } /* Get the address parameters (host, port, flag, TTL, etc) to send the @@ -650,8 +678,8 @@ PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool, const pj_sockaddr_in *remote_addr; remote_addr = pjsip_transport_get_remote_addr(req_transport); pj_strdup2(pool, &send_addr->host, - pj_sockaddr_get_str_addr(remote_addr)); - send_addr->port = pj_sockaddr_get_port(remote_addr); + pj_inet_ntoa(remote_addr->sin_addr)); + send_addr->port = pj_sockaddr_in_get_port(remote_addr); } else { /* Set the host part */ diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c index fff7bacc..587df864 100644 --- a/pjsip/src/pjsip/sip_msg.c +++ b/pjsip/src/pjsip/sip_msg.c @@ -1,8 +1,7 @@ /* $Id$ - * */ #include -#include +#include #include #include @@ -264,7 +263,7 @@ PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, return hdr; } -PJ_DEF(int) pjsip_msg_print( pjsip_msg *msg, char *buf, pj_size_t size) +PJ_DEF(pj_ssize_t) pjsip_msg_print( pjsip_msg *msg, char *buf, pj_size_t size) { char *p=buf, *end=buf+size; int len; diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c index 4d439120..63cc3b53 100644 --- a/pjsip/src/pjsip/sip_parser.c +++ b/pjsip/src/pjsip/sip_parser.c @@ -1,25 +1,28 @@ /* $Id$ - * */ #include #include #include -#include -#include +#include +#include +#include /* rdata structure */ +#include #include #include #include #include #include #include -#include /* tolower() */ +#include +#include #define RESERVED ";/?:@&=+$," #define MARK "-_.!~*'()" #define ESCAPED "%" #define USER "&=+$,;?/" #define PASS "&=+$," -#define TOKEN "-.!%*_=`'~+" /* '+' is because of application/pidf+xml in Content-Type! */ +#define TOKEN "-.!%*_=`'~+" /* '+' is because of application/pidf+xml + * in Content-Type! */ #define HOST "_-." #define HEX_DIGIT "abcdefABCDEF" #define PARAM_CHAR "[]/:&+$" MARK "%" @@ -45,109 +48,98 @@ static int parser_is_initialized; /* * Global vars (also extern). */ -const pj_str_t pjsip_USER_STR = { "user", 4}; -const pj_str_t pjsip_METHOD_STR = { "method", 6}; +const pj_str_t pjsip_USER_STR = { "user", 4}; +const pj_str_t pjsip_METHOD_STR = { "method", 6}; const pj_str_t pjsip_TRANSPORT_STR = { "transport", 9}; -const pj_str_t pjsip_MADDR_STR = { "maddr", 5 }; -const pj_str_t pjsip_LR_STR = { "lr", 2 }; -const pj_str_t pjsip_SIP_STR = { "sip", 3 }; -const pj_str_t pjsip_SIPS_STR = { "sips", 4 }; -const pj_str_t pjsip_TEL_STR = { "tel", 3 }; -const pj_str_t pjsip_BRANCH_STR = { "branch", 6 }; -const pj_str_t pjsip_TTL_STR = { "ttl", 3 }; -const pj_str_t pjsip_PNAME_STR = { "received", 8 }; -const pj_str_t pjsip_Q_STR = { "q", 1 }; -const pj_str_t pjsip_EXPIRES_STR = { "expires", 7 }; -const pj_str_t pjsip_TAG_STR = { "tag", 3 }; -const pj_str_t pjsip_RPORT_STR = { "rport", 5}; - -pj_char_spec pjsip_HOST_SPEC, /* For scanning host part. */ - pjsip_DIGIT_SPEC, /* Decimal digits */ - pjsip_ALPHA_SPEC, /* Alpha (A-Z, a-z) */ - pjsip_ALNUM_SPEC, /* Decimal + Alpha. */ - pjsip_TOKEN_SPEC, /* Token. */ - pjsip_HEX_SPEC, /* Hexadecimal digits. */ - pjsip_PARAM_CHAR_SPEC, /* For scanning pname (or pvalue when it's not quoted.) */ - pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */ - pjsip_PASSWD_SPEC, /* Password. */ - pjsip_USER_SPEC, /* User */ - pjsip_ARRAY_ELEMENTS, /* Array separator. */ - pjsip_NEWLINE_OR_EOF_SPEC, /* For eating up header.*/ - pjsip_DISPLAY_SCAN_SPEC; /* Used when searching for display name in URL. */ +const pj_str_t pjsip_MADDR_STR = { "maddr", 5 }; +const pj_str_t pjsip_LR_STR = { "lr", 2 }; +const pj_str_t pjsip_SIP_STR = { "sip", 3 }; +const pj_str_t pjsip_SIPS_STR = { "sips", 4 }; +const pj_str_t pjsip_TEL_STR = { "tel", 3 }; +const pj_str_t pjsip_BRANCH_STR = { "branch", 6 }; +const pj_str_t pjsip_TTL_STR = { "ttl", 3 }; +const pj_str_t pjsip_PNAME_STR = { "received", 8 }; +const pj_str_t pjsip_Q_STR = { "q", 1 }; +const pj_str_t pjsip_EXPIRES_STR = { "expires", 7 }; +const pj_str_t pjsip_TAG_STR = { "tag", 3 }; +const pj_str_t pjsip_RPORT_STR = { "rport", 5}; + +/* Character Input Specification buffer. */ +static pj_cis_buf_t cis_buf; + +/* Character Input Specifications. */ +pj_cis_t pjsip_HOST_SPEC, /* For scanning host part. */ + pjsip_DIGIT_SPEC, /* Decimal digits */ + pjsip_ALPHA_SPEC, /* Alpha (A-Z, a-z) */ + pjsip_ALNUM_SPEC, /* Decimal + Alpha. */ + pjsip_TOKEN_SPEC, /* Token. */ + pjsip_HEX_SPEC, /* Hexadecimal digits. */ + pjsip_PARAM_CHAR_SPEC, /* For scanning pname (or pvalue when + * it's not quoted.) */ + pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */ + pjsip_PASSWD_SPEC, /* Password. */ + pjsip_USER_SPEC, /* User */ + pjsip_ARRAY_ELEMENTS, /* Array separator. */ + pjsip_NEWLINE_OR_EOF_SPEC, /* For eating up header.*/ + pjsip_DISPLAY_SCAN_SPEC; /* Used when searching for display name + * in URL. */ /* * Forward decl. */ -static pjsip_msg * int_parse_msg( pj_scanner *scanner, - pj_pool_t *pool, - pjsip_parser_err_report *err_list); -static void int_parse_param( pj_scanner *scanner, - pj_str_t *pname, - pj_str_t *pvalue); -static void int_parse_req_line( pj_scanner *scanner, - pj_pool_t *pool, - pjsip_request_line *req_line); -static int int_is_next_user( pj_scanner *scanner); -static void int_parse_status_line( pj_scanner *scanner, - pjsip_status_line *line); -static void int_parse_user_pass( pj_scanner *scanner, - pj_str_t *user, - pj_str_t *pass); -static void int_parse_uri_host_port( pj_scanner *scanner, - pj_str_t *p_host, - int *p_port); -static pjsip_uri * int_parse_uri_or_name_addr( pj_scanner *scanner, - pj_pool_t *pool, unsigned option); -static pjsip_url * int_parse_sip_url( pj_scanner *scanner, - pj_pool_t *pool, - pj_bool_t parse_params); -static pjsip_name_addr* int_parse_name_addr( pj_scanner *scanner, - pj_pool_t *pool ); -static void parse_hdr_end( pj_scanner *scanner ); -static pjsip_accept_hdr* parse_hdr_accept( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_allow_hdr* parse_hdr_allow( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_cid_hdr* parse_hdr_call_id( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_contact_hdr* parse_hdr_contact( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_clen_hdr* parse_hdr_content_length( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_ctype_hdr* parse_hdr_content_type( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_cseq_hdr* parse_hdr_cseq( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_expires_hdr* parse_hdr_expires( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_from_hdr* parse_hdr_from( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_max_forwards_hdr* parse_hdr_max_forwards( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_min_expires_hdr* parse_hdr_min_expires( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_rr_hdr* parse_hdr_rr( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_route_hdr* parse_hdr_route( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_require_hdr* parse_hdr_require( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_retry_after_hdr* parse_hdr_retry_after( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_supported_hdr* parse_hdr_supported( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_to_hdr* parse_hdr_to( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_unsupported_hdr* parse_hdr_unsupported( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_via_hdr* parse_hdr_via( pj_scanner *scanner, - pj_pool_t *pool); -static pjsip_generic_string_hdr* parse_hdr_generic_string( pj_scanner *scanner, - pj_pool_t *pool); +static pjsip_msg * int_parse_msg( pjsip_parse_ctx *ctx, + pjsip_parser_err_report *err_list); +static void int_parse_param( pj_scanner *scanner, + pj_str_t *pname, + pj_str_t *pvalue); +static void int_parse_req_line( pj_scanner *scanner, + pj_pool_t *pool, + pjsip_request_line *req_line); +static int int_is_next_user( pj_scanner *scanner); +static void int_parse_status_line( pj_scanner *scanner, + pjsip_status_line *line); +static void int_parse_user_pass( pj_scanner *scanner, + pj_str_t *user, + pj_str_t *pass); +static void int_parse_uri_host_port( pj_scanner *scanner, + pj_str_t *p_host, + int *p_port); +static pjsip_uri * int_parse_uri_or_name_addr( pj_scanner *scanner, + pj_pool_t *pool, + unsigned option); +static pjsip_url * int_parse_sip_url( pj_scanner *scanner, + pj_pool_t *pool, + pj_bool_t parse_params); +static pjsip_name_addr * + int_parse_name_addr( pj_scanner *scanner, + pj_pool_t *pool ); +static void parse_hdr_end( pj_scanner *scanner ); + +static pjsip_hdr* parse_hdr_accept( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_allow( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_call_id( pjsip_parse_ctx *ctx); +static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx); +static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_expires( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx); +static pjsip_hdr* parse_hdr_min_expires( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_retry_after( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_supported( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_unsupported( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx ); +static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx); /* Convert non NULL terminated string to integer. */ -static unsigned long pj_strtoul_mindigit(const pj_str_t *str, unsigned mindig) +static unsigned long pj_strtoul_mindigit(const pj_str_t *str, + unsigned mindig) { unsigned long value; unsigned i; @@ -163,20 +155,20 @@ static unsigned long pj_strtoul_mindigit(const pj_str_t *str, unsigned mindig) } /* Case insensitive comparison */ -#define parser_stricmp(str1, str2) \ - (str1.slen != str2.slen ? -1 : \ - !(memcmp(str1.ptr, str2.ptr, str1.slen)==0 || stricmp(str1.ptr, str2.ptr)==0)) +#define parser_stricmp(str1, str2) pj_stricmp(&str1, &str2) + /* Syntax error handler for parser. */ static void on_syntax_error(pj_scanner *scanner) { - PJ_UNUSED_ARG(scanner) + PJ_UNUSED_ARG(scanner); PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); } /* Concatenate unrecognized params into single string. */ void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, - const pj_str_t *pname, const pj_str_t *pvalue, int sepchar) + const pj_str_t *pname, const pj_str_t *pvalue, + int sepchar) { char *new_param, *p; int len; @@ -213,75 +205,144 @@ static void concat_param( pj_str_t *param, pj_pool_t *pool, } /* Initialize static properties of the parser. */ -static void init_parser() +static pj_status_t init_parser() { - static int initialized; - + static int initialized; + pj_status_t status; + if (initialized) - return; + return PJ_SUCCESS; initialized = 1; - - pj_cs_add_num( pjsip_DIGIT_SPEC ); - pj_cs_add_alpha( pjsip_ALPHA_SPEC ); - - pj_cs_add_alpha( pjsip_ALNUM_SPEC ); - pj_cs_add_num( pjsip_ALNUM_SPEC ); - - pj_cs_add_str(pjsip_NEWLINE_OR_EOF_SPEC, "\r\n"); + + pj_cis_buf_init(&cis_buf); + + status = pj_cis_init(&cis_buf, &pjsip_DIGIT_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_num(&pjsip_DIGIT_SPEC); + + status = pj_cis_init(&cis_buf, &pjsip_ALPHA_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_alpha( &pjsip_ALPHA_SPEC ); + + status = pj_cis_init(&cis_buf, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_alpha( &pjsip_ALNUM_SPEC ); + pj_cis_add_num( &pjsip_ALNUM_SPEC ); + + status = pj_cis_init(&cis_buf, &pjsip_NEWLINE_OR_EOF_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str(&pjsip_NEWLINE_OR_EOF_SPEC, "\r\n"); //pj_cs_set(pjsip_NEWLINE_OR_EOF_SPEC, 0); - - pj_cs_add_str( pjsip_ARRAY_ELEMENTS, ",\r\n"); - - pj_memcpy(pjsip_TOKEN_SPEC, pjsip_ALNUM_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_TOKEN_SPEC, TOKEN); - - pj_memcpy(pjsip_HOST_SPEC, pjsip_ALNUM_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_HOST_SPEC, HOST); - - pj_memcpy(pjsip_HEX_SPEC, pjsip_DIGIT_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_HEX_SPEC, HEX_DIGIT); - - pj_memcpy(pjsip_PARAM_CHAR_SPEC, pjsip_ALNUM_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_PARAM_CHAR_SPEC, PARAM_CHAR); - - pj_memcpy(pjsip_USER_SPEC, pjsip_ALNUM_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_USER_SPEC, MARK ESCAPED USER ); - - pj_memcpy(pjsip_PASSWD_SPEC, pjsip_ALNUM_SPEC, sizeof(pj_char_spec)); - pj_cs_add_str( pjsip_PASSWD_SPEC, MARK ESCAPED PASS); - - pj_cs_add_str( pjsip_PROBE_USER_HOST_SPEC, "@ \n>"); - pj_cs_invert( pjsip_PROBE_USER_HOST_SPEC ); - - pj_cs_add_str( pjsip_DISPLAY_SCAN_SPEC, ":\r\n<"); - - pjsip_register_hdr_parser( "Accept", NULL, (pjsip_parse_hdr_func*) &parse_hdr_accept); - pjsip_register_hdr_parser( "Allow", NULL, (pjsip_parse_hdr_func*) &parse_hdr_allow); - pjsip_register_hdr_parser( "Call-ID", NULL, (pjsip_parse_hdr_func*) &parse_hdr_call_id); - pjsip_register_hdr_parser( "Contact", "m", (pjsip_parse_hdr_func*) &parse_hdr_contact); - pjsip_register_hdr_parser( "Content-Length", NULL, (pjsip_parse_hdr_func*) &parse_hdr_content_length); - pjsip_register_hdr_parser( "Content-Type", NULL, (pjsip_parse_hdr_func*) &parse_hdr_content_type); - pjsip_register_hdr_parser( "CSeq", NULL, (pjsip_parse_hdr_func*) &parse_hdr_cseq); - pjsip_register_hdr_parser( "Expires", NULL, (pjsip_parse_hdr_func*) &parse_hdr_expires); - pjsip_register_hdr_parser( "From", "f", (pjsip_parse_hdr_func*) &parse_hdr_from); - pjsip_register_hdr_parser( "Max-Forwards", NULL, (pjsip_parse_hdr_func*) &parse_hdr_max_forwards); - pjsip_register_hdr_parser( "Min-Expires", NULL, (pjsip_parse_hdr_func*) &parse_hdr_min_expires); - pjsip_register_hdr_parser( "Record-Route", NULL, (pjsip_parse_hdr_func*) &parse_hdr_rr); - pjsip_register_hdr_parser( "Route", NULL, (pjsip_parse_hdr_func*) &parse_hdr_route); - pjsip_register_hdr_parser( "Require", NULL, (pjsip_parse_hdr_func*) &parse_hdr_require); - pjsip_register_hdr_parser( "Retry-After", NULL, (pjsip_parse_hdr_func*) &parse_hdr_retry_after); - pjsip_register_hdr_parser( "Supported", "k", (pjsip_parse_hdr_func*) &parse_hdr_supported); - pjsip_register_hdr_parser( "To", "t", (pjsip_parse_hdr_func*) &parse_hdr_to); - pjsip_register_hdr_parser( "Unsupported", NULL, (pjsip_parse_hdr_func*) &parse_hdr_unsupported); - pjsip_register_hdr_parser( "Via", NULL, (pjsip_parse_hdr_func*) &parse_hdr_via); + + status = pj_cis_init(&cis_buf, &pjsip_ARRAY_ELEMENTS); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_ARRAY_ELEMENTS, ",\r\n"); + + status = pj_cis_dup(&pjsip_TOKEN_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_TOKEN_SPEC, TOKEN); + + status = pj_cis_dup(&pjsip_HOST_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_HOST_SPEC, HOST); + + status = pj_cis_dup(&pjsip_HEX_SPEC, &pjsip_DIGIT_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_HEX_SPEC, HEX_DIGIT); + + status = pj_cis_dup(&pjsip_PARAM_CHAR_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR); + + status = pj_cis_dup(&pjsip_USER_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_USER_SPEC, MARK ESCAPED USER ); + + status = pj_cis_dup(&pjsip_PASSWD_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_PASSWD_SPEC, MARK ESCAPED PASS); + + status = pj_cis_init(&cis_buf, &pjsip_PROBE_USER_HOST_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_PROBE_USER_HOST_SPEC, "@ \n>"); + pj_cis_invert( &pjsip_PROBE_USER_HOST_SPEC ); + + status = pj_cis_init(&cis_buf, &pjsip_DISPLAY_SCAN_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pjsip_DISPLAY_SCAN_SPEC, ":\r\n<"); + + status = pjsip_register_hdr_parser( "Accept", NULL, &parse_hdr_accept); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Allow", NULL, &parse_hdr_allow); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Call-ID", NULL, &parse_hdr_call_id); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Contact", "m", &parse_hdr_contact); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Content-Length", NULL, + &parse_hdr_content_len); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Content-Type", NULL, + &parse_hdr_content_type); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "CSeq", NULL, &parse_hdr_cseq); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Expires", NULL, &parse_hdr_expires); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "From", "f", &parse_hdr_from); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Max-Forwards", NULL, + &parse_hdr_max_forwards); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Min-Expires", NULL, + &parse_hdr_min_expires); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Record-Route", NULL, &parse_hdr_rr); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Route", NULL, &parse_hdr_route); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Require", NULL, &parse_hdr_require); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Retry-After", NULL, + &parse_hdr_retry_after); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Supported", "k", + &parse_hdr_supported); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "To", "t", &parse_hdr_to); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Unsupported", NULL, + &parse_hdr_unsupported); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + status = pjsip_register_hdr_parser( "Via", NULL, &parse_hdr_via); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Register auth parser. */ - pjsip_auth_init_parser(); - + status = pjsip_auth_init_parser(); + + return status; } -static void init_sip_parser() +static void init_sip_parser(void) { if (!parser_is_initialized) { /* Prevent race cond. */ @@ -317,29 +378,30 @@ static int compare_handler( const handler_rec *r1, return 1; /* Equal length and equal hash. compare the strings. */ - return strcmp(r1->hname, name); + return pj_native_strcmp(r1->hname, name); } /* Register one handler for one header name. */ -static int int_register_parser( const char *name, pjsip_parse_hdr_func *fptr ) +static pj_status_t int_register_parser( const char *name, + pjsip_parse_hdr_func *fptr ) { unsigned pos; handler_rec rec; unsigned i; if (handler_count >= PJ_ARRAY_SIZE(handler)) { - return -1; + return PJ_ETOOMANY; } /* Initialize temporary handler. */ rec.handler = fptr; rec.hname_len = strlen(name); if (rec.hname_len >= sizeof(rec.hname)) { - return -1; + return PJ_ENAMETOOLONG; } /* Name is copied in lowercase. */ for (i=0; i 0) { break; @@ -360,13 +423,14 @@ static int int_register_parser( const char *name, pjsip_parse_hdr_func *fptr ) /* Shift handlers. */ if (pos != handler_count) { - pj_memmove( &handler[pos+1], &handler[pos], (handler_count-pos)*sizeof(handler_rec)); + pj_memmove( &handler[pos+1], &handler[pos], + (handler_count-pos)*sizeof(handler_rec)); } /* Add new handler. */ pj_memcpy( &handler[pos], &rec, sizeof(handler_rec)); ++handler_count; - return 0; + return PJ_SUCCESS; } /* Register parser handler. If both header name and short name are valid, @@ -375,14 +439,19 @@ static int int_register_parser( const char *name, pjsip_parse_hdr_func *fptr ) PJ_DEF(pj_status_t) pjsip_register_hdr_parser( const char *hname, const char *hshortname, pjsip_parse_hdr_func *fptr) -{ - if (int_register_parser(hname, fptr)) { - return -1; +{ + pj_status_t status; + + status = int_register_parser(hname, fptr); + if (status != PJ_SUCCESS) { + return status; } - if (hshortname && int_register_parser(hshortname, fptr)) { - return -1; + if (hshortname) { + status = int_register_parser(hshortname, fptr); + if (status != PJ_SUCCESS) + return status; } - return 0; + return PJ_SUCCESS; } /* Find handler to parse the header name. */ @@ -392,17 +461,18 @@ static pjsip_parse_hdr_func * find_handler(const pj_str_t *hname) char hname_copy[PJSIP_MAX_HNAME_LEN]; pj_uint32_t hash; int comp; - unsigned i, n; + unsigned n; + + if (hname->slen >= PJSIP_MAX_HNAME_LEN) { + pj_assert(!"Header name is too long!"); + return NULL; + } /* Calculate hash value while converting the header to lowercase. * Don't assume that 'hname' is NULL terminated. */ - hash = 0; - for (i=0; i<(unsigned)hname->slen; ++i) { - hname_copy[i] = (char)tolower(hname->ptr[i]); - hash = hash * PJ_HASH_MULTIPLIER + hname_copy[i]; - } - hname_copy[i] = '\0'; + hash = pj_hash_calc_tolower(0, hname_copy, hname); + hname_copy[hname->slen] = '\0'; /* Binary search for the handler. */ comp = -1; @@ -428,19 +498,26 @@ static pjsip_parse_hdr_func * find_handler(const pj_str_t *hname) } /* Public function to parse SIP message. */ -PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool, char *buf, pj_size_t size, +PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool, + char *buf, pj_size_t size, pjsip_parser_err_report *err_list) { pjsip_msg *msg = NULL; - pj_scanner scanner; + pj_scanner scanner; + pjsip_parse_ctx context; PJ_USE_EXCEPTION; init_sip_parser(); - pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error); + pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, + &on_syntax_error); + + context.scanner = &scanner; + context.pool = pool; + context.rdata = NULL; PJ_TRY { - msg = int_parse_msg(&scanner, pool, err_list); + msg = int_parse_msg(&context, err_list); } PJ_DEFAULT { msg = NULL; @@ -450,6 +527,35 @@ PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool, char *buf, pj_size_t size, pj_scan_fini(&scanner); return msg; } + +/* Public function to parse as rdata.*/ +PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size, + pjsip_rx_data *rdata ) +{ + pj_scanner scanner; + pjsip_parse_ctx context; + PJ_USE_EXCEPTION; + + init_sip_parser(); + + pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, + &on_syntax_error); + + context.scanner = &scanner; + context.pool = rdata->pool; + context.rdata = rdata; + + PJ_TRY { + rdata->msg = int_parse_msg(&context, &rdata->parse_err); + } + PJ_DEFAULT { + rdata->msg = NULL; + } + PJ_END + + pj_scan_fini(&scanner); + return rdata->msg; +} /* Determine if a message has been received. */ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, @@ -466,24 +572,26 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, /* For datagram, the whole datagram IS the message. */ if (is_datagram) { - return PJ_TRUE; + return PJ_SUCCESS; } /* Find the end of header area by finding an empty line. */ - if ((pos = strstr(buf, "\n\r\n")) == NULL) { - return PJ_FALSE; + if ((pos = pj_native_strstr(buf, "\n\r\n")) == NULL) { + return PJSIP_EPARTIALMSG; } hdr_end = pos+1; body_start = pos+3; /* Find "Content-Length" header the hard way. */ - line = strchr(buf, '\n'); + line = pj_native_strchr(buf, '\n'); while (line && line < hdr_end-14) { ++line; - if ( ((*line=='C' || *line=='c') && strncasecmp(line, "Content-Length", 14) == 0) || - ((*line=='l' || *line=='L') && (*(line+1)==' ' || *(line+1)=='\t' || *(line+1)==':'))) + if ( ((*line=='C' || *line=='c') && + pj_native_strncasecmp(line, "Content-Length", 14) == 0) || + ((*line=='l' || *line=='L') && + (*(line+1)==' ' || *(line+1)=='\t' || *(line+1)==':'))) { /* Try to parse the header. */ pj_scanner scanner; @@ -509,7 +617,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, } /* Get number */ - pj_scan_get(&scanner, pjsip_DIGIT_SPEC, &str_clen); + pj_scan_get(&scanner, &pjsip_DIGIT_SPEC, &str_clen); /* Get newline. */ pj_scan_get_newline(&scanner); @@ -527,24 +635,22 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, break; /* Go to next line. */ - line = strchr(line, '\n'); + line = pj_native_strchr(line, '\n'); } /* Found Content-Length? */ if (content_length == -1) { - PJ_LOG(4, ("sipparser", "pjsip_find_msg: incoming TCP packet has missing " - "Content-Length header, treated as incomplete.")); - return PJ_FALSE; + return PJSIP_EMISSINGHDR; } /* Enough packet received? */ *msg_size = (body_start - buf) + content_length; - return (*msg_size) <= size; + return (*msg_size) <= size ? PJ_SUCCESS : PJSIP_EPARTIALMSG; #else - PJ_UNUSED_ARG(buf) - PJ_UNUSED_ARG(is_datagram) + PJ_UNUSED_ARG(buf); + PJ_UNUSED_ARG(is_datagram); *msg_size = size; - return 1; + return PJ_SUCCESS; #endif } @@ -557,10 +663,7 @@ PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, pj_scanner scanner; pjsip_uri *uri = NULL; - if (!parser_is_initialized) { - init_parser(); - parser_is_initialized = 1; - } + init_sip_parser(); pj_scan_init(&scanner, buf, size, 0, &on_syntax_error); @@ -571,7 +674,9 @@ PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, PJ_END; /* Must have exhausted all inputs. */ - if (pj_scan_is_eof(&scanner) || *scanner.current=='\r' || *scanner.current=='\n') { + if (pj_scan_is_eof(&scanner) || *scanner.curptr=='\r' || + *scanner.curptr=='\n') + { /* Success. */ pj_scan_fini(&scanner); return uri; @@ -586,7 +691,8 @@ PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, * This assumes that the 'data' member points to a contigous memory where the * actual body is laid. */ -static int generic_print_body (pjsip_msg_body *msg_body, char *buf, pj_size_t size) +static int generic_print_body (pjsip_msg_body *msg_body, + char *buf, pj_size_t size) { pjsip_msg_body *body = msg_body; if (size < body->len) @@ -597,19 +703,21 @@ static int generic_print_body (pjsip_msg_body *msg_body, char *buf, pj_size_t si } /* Internal function to parse SIP message */ -static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, +static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx, pjsip_parser_err_report *err_list) { PJ_USE_EXCEPTION; int ch; pjsip_msg *msg; pjsip_ctype_hdr *ctype_hdr = NULL; + pj_scanner *scanner = ctx->scanner; + pj_pool_t *pool = ctx->pool; /* Skip leading newlines. */ - ch = *scanner->current; + ch = *scanner->curptr; while (ch=='\r' || ch=='\n') { pj_scan_get_char(scanner); - ch = *scanner->current; + ch = *scanner->curptr; } msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG); @@ -630,7 +738,7 @@ static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, pjsip_hdr *hdr = NULL; /* Get hname. */ - pj_scan_get( scanner, pjsip_TOKEN_SPEC, &hname); + pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hname); ch = pj_scan_get_char( scanner ); if (ch != ':') { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); @@ -645,12 +753,11 @@ static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, * hname/hvalue pair. */ if (handler) { - hdr = (*handler)(scanner, pool); + hdr = (*handler)(ctx); } else { - pjsip_generic_string_hdr *ghdr = parse_hdr_generic_string(scanner, pool); - ghdr->type = PJSIP_H_OTHER; - ghdr->name = ghdr->sname = hname; - hdr = (pjsip_hdr*)ghdr; + hdr = parse_hdr_generic_string(ctx); + hdr->type = PJSIP_H_OTHER; + hdr->name = hdr->sname = hname; } /* Check if we've just parsed a Content-Type header. @@ -668,8 +775,9 @@ static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, pj_str_t token; hdr = NULL; - PJ_LOG(4,("sipparser", "Syntax error in line %d col %d (hname=%.*s)", - scanner->line, scanner->col, hname.slen, hname.ptr)); + //PJ_LOG(4,("sipparser", + // "Syntax error in line %d col %d (hname=%.*s)", + // scanner->line, scanner->col, hname.slen, hname.ptr)); if (err_list) { pjsip_parser_err_report *err_info; @@ -684,7 +792,7 @@ static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, } if (!pj_scan_is_eof(scanner)) { - pj_scan_get_until(scanner, pjsip_NEWLINE_OR_EOF_SPEC, &token); + pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &token); parse_hdr_end(scanner); } } @@ -702,23 +810,23 @@ static pjsip_msg *int_parse_msg( pj_scanner *scanner, pj_pool_t *pool, /* Parse until EOF or an empty line is found. */ } while (!pj_scan_is_eof(scanner) && - *scanner->current != '\r' && *scanner->current != '\n'); + *scanner->curptr != '\r' && *scanner->curptr != '\n'); /* If empty line is found, eat it. */ if (!pj_scan_is_eof(scanner)) { - if (*scanner->current=='\r' || *scanner->current=='\n') { + if (*scanner->curptr=='\r' || *scanner->curptr=='\n') { pj_scan_get_newline(scanner); } } - /* If we have Content-Type header, treat the rest of the message as body. */ + /* If we have Content-Type header, treat the rest of the message as body.*/ if (ctype_hdr) { pjsip_msg_body *body = pj_pool_alloc(pool, sizeof(pjsip_msg_body)); - pj_strdup (pool, &body->content_type.type, &ctype_hdr->media.type); - pj_strdup (pool, &body->content_type.subtype, &ctype_hdr->media.subtype); - pj_strdup (pool, &body->content_type.param, &ctype_hdr->media.param); - body->data = scanner->current; - body->len = scanner->end - scanner->current; + pj_strdup(pool, &body->content_type.type, &ctype_hdr->media.type); + pj_strdup(pool, &body->content_type.subtype, &ctype_hdr->media.subtype); + pj_strdup(pool, &body->content_type.param, &ctype_hdr->media.param); + body->data = scanner->curptr; + body->len = scanner->end - scanner->curptr; body->print_body = &generic_print_body; msg->body = body; @@ -733,20 +841,20 @@ void pjsip_parse_param_imp( pj_scanner *scanner, unsigned option) { /* pname */ - pj_scan_get(scanner, pjsip_PARAM_CHAR_SPEC, pname); + pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pname); /* pvalue, if any */ - if (*scanner->current == '=') { + if (*scanner->curptr == '=') { pj_scan_get_char(scanner); /* pvalue can be a quoted string. */ - if (*scanner->current == '"') { + if (*scanner->curptr == '"') { pj_scan_get_quote( scanner, '"', '"', pvalue); if (option & PJSIP_PARSE_REMOVE_QUOTE) { pvalue->ptr++; pvalue->slen -= 2; } } else { - pj_scan_get(scanner, pjsip_PARAM_CHAR_SPEC, pvalue); + pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pvalue); } } else { pvalue->ptr = NULL; @@ -769,11 +877,11 @@ static void int_parse_param( pj_scanner *scanner, static void int_parse_uri_host_port( pj_scanner *scanner, pj_str_t *host, int *p_port) { - pj_scan_get( scanner, pjsip_HOST_SPEC, host); - if (*scanner->current == ':') { + pj_scan_get( scanner, &pjsip_HOST_SPEC, host); + if (*scanner->curptr == ':') { pj_str_t port; pj_scan_get_char(scanner); - pj_scan_get(scanner, pjsip_DIGIT_SPEC, &port); + pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port); *p_port = pj_strtoul(&port); } else { *p_port = 0; @@ -789,7 +897,7 @@ static int int_is_next_user(pj_scanner *scanner) /* Find character '@'. If this character exist, then the token * must be a username. */ - if (pj_scan_peek( scanner, pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@') + if (pj_scan_peek( scanner, &pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@') is_user = 1; else is_user = 0; @@ -801,10 +909,10 @@ static int int_is_next_user(pj_scanner *scanner) static void int_parse_user_pass( pj_scanner *scanner, pj_str_t *user, pj_str_t *pass) { - pj_scan_get( scanner, pjsip_USER_SPEC, user); - if ( *scanner->current == ':') { + pj_scan_get( scanner, &pjsip_USER_SPEC, user); + if ( *scanner->curptr == ':') { pj_scan_get_char( scanner ); - pj_scan_get( scanner, pjsip_PASSWD_SPEC, pass); + pj_scan_get( scanner, &pjsip_PASSWD_SPEC, pass); } else { pass->ptr = NULL; pass->slen = 0; @@ -815,13 +923,13 @@ static void int_parse_user_pass( pj_scanner *scanner, } /* Parse all types of URI. */ -static pjsip_uri *int_parse_uri_or_name_addr(pj_scanner *scanner, pj_pool_t *pool, - unsigned option) +static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *pool, + unsigned opt) { pjsip_uri *uri; int is_name_addr = 0; - if (*scanner->current=='"' || *scanner->current=='<') { + if (*scanner->curptr=='"' || *scanner->curptr=='<') { uri = (pjsip_uri*)int_parse_name_addr( scanner, pool ); is_name_addr = 1; } else { @@ -830,14 +938,17 @@ static pjsip_uri *int_parse_uri_or_name_addr(pj_scanner *scanner, pj_pool_t *poo int colon; pj_scan_save_state( scanner, &backtrack); - pj_scan_get( scanner, pjsip_TOKEN_SPEC, &scheme); + pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &scheme); colon = pj_scan_get_char( scanner ); pj_scan_restore_state( scanner, &backtrack); - if (colon==':' && (parser_stricmp(scheme, pjsip_SIP_STR)==0 || parser_stricmp(scheme, pjsip_SIPS_STR)==0)) + if (colon==':' && + (parser_stricmp(scheme, pjsip_SIP_STR)==0 || + parser_stricmp(scheme, pjsip_SIPS_STR)==0)) { - uri = (pjsip_uri*)int_parse_sip_url( scanner, pool, - (option & PJSIP_PARSE_URI_IN_FROM_TO_HDR) == 0 ); + uri = (pjsip_uri*) + int_parse_sip_url( scanner, pool, + (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0); } else if (colon==':' && parser_stricmp( scheme, pjsip_TEL_STR)==0) { @@ -852,7 +963,7 @@ static pjsip_uri *int_parse_uri_or_name_addr(pj_scanner *scanner, pj_pool_t *poo } /* Should we return the URI object as name address? */ - if (option & PJSIP_PARSE_URI_AS_NAMEADDR) { + if (opt & PJSIP_PARSE_URI_AS_NAMEADDR) { if (is_name_addr == 0) { pjsip_name_addr *name_addr; @@ -870,21 +981,22 @@ static pjsip_uri *int_parse_uri_or_name_addr(pj_scanner *scanner, pj_pool_t *poo static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool, pj_bool_t parse_params) { - if (*scanner->current=='"' || *scanner->current=='<') { + if (*scanner->curptr=='"' || *scanner->curptr=='<') { return (pjsip_uri*)int_parse_name_addr( scanner, pool ); } else { pj_str_t scheme; int colon; /* Get scheme. */ - colon = pj_scan_peek(scanner, pjsip_TOKEN_SPEC, &scheme); + colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme); if (colon != ':') { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); } - if ((parser_stricmp(scheme, pjsip_SIP_STR)==0 || parser_stricmp(scheme, pjsip_SIPS_STR)==0)) + if ((parser_stricmp(scheme, pjsip_SIP_STR)==0 || + parser_stricmp(scheme, pjsip_SIPS_STR)==0)) { - return (pjsip_uri*)int_parse_sip_url( scanner, pool, parse_params ); + return (pjsip_uri*)int_parse_sip_url( scanner, pool, parse_params); } else if (parser_stricmp(scheme, pjsip_TEL_STR)==0) { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); @@ -908,7 +1020,7 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, int skip_ws = scanner->skip_ws; scanner->skip_ws = 0; - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &scheme); + pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme); colon = pj_scan_get_char(scanner); if (colon != ':') { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); @@ -937,7 +1049,7 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, int_parse_uri_host_port(scanner, &url->host, &url->port); /* Get URL parameters. */ - while ( parse_params && *scanner->current == ';' ) { + while ( parse_params && *scanner->curptr == ';' ) { pj_str_t pname, pvalue; int_parse_param( scanner, &pname, &pvalue); @@ -948,7 +1060,7 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, } else if (!parser_stricmp(pname, pjsip_METHOD_STR) && pvalue.slen) { url->method_param = pvalue; - } else if (!parser_stricmp(pname, pjsip_TRANSPORT_STR) && pvalue.slen) { + } else if (!parser_stricmp(pname,pjsip_TRANSPORT_STR) && pvalue.slen) { url->transport_param = pvalue; } else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) { @@ -966,8 +1078,9 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, } /* Get header params. */ - if (parse_params && *scanner->current == '?') { - pj_scan_get_until(scanner, pjsip_NEWLINE_OR_EOF_SPEC, &url->header_param); + if (parse_params && *scanner->curptr == '?') { + pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, + &url->header_param); } scanner->skip_ws = skip_ws; @@ -984,10 +1097,10 @@ static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, name_addr = pjsip_name_addr_create(pool); - if (*scanner->current == '"') { + if (*scanner->curptr == '"') { pj_scan_get_quote( scanner, '"', '"', &name_addr->display); - } else if (*scanner->current != '<') { + } else if (*scanner->curptr != '<') { int next; pj_str_t dummy; @@ -996,7 +1109,7 @@ static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, * We're only interested in display name, because SIP URL * will be parser later. */ - next = pj_scan_peek_until(scanner, pjsip_DISPLAY_SCAN_SPEC, &dummy); + next = pj_scan_peek_until(scanner, &pjsip_DISPLAY_SCAN_SPEC, &dummy); if (next == '<') { /* Ok, this is what we're looking for, a display name. */ pj_scan_get_until_ch( scanner, '<', &name_addr->display); @@ -1008,7 +1121,7 @@ static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, pj_scan_skip_whitespace(scanner); /* Get the SIP-URL */ - has_bracket = (*scanner->current == '<'); + has_bracket = (*scanner->curptr == '<'); if (has_bracket) pj_scan_get_char(scanner); name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE ); @@ -1025,7 +1138,7 @@ static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool, { pj_str_t token; - pj_scan_get( scanner, pjsip_TOKEN_SPEC, &token); + pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &token); pjsip_method_init_np( &req_line->method, &token); req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE); @@ -1045,9 +1158,10 @@ static void int_parse_status_line( pj_scanner *scanner, PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); pj_scan_advance_n( scanner, 7, 1); - pj_scan_get( scanner, pjsip_DIGIT_SPEC, &token); + pj_scan_get( scanner, &pjsip_DIGIT_SPEC, &token); status_line->code = pj_strtoul(&token); - pj_scan_get_until( scanner, pjsip_NEWLINE_OR_EOF_SPEC, &status_line->reason); + pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, + &status_line->reason); pj_scan_get_newline( scanner ); } @@ -1056,7 +1170,7 @@ static void parse_hdr_end( pj_scanner *scanner ) { if (pj_scan_is_eof(scanner)) { ; /* Do nothing. */ - } else if (*scanner->current == '&') { + } else if (*scanner->curptr == '&') { pj_scan_get_char(scanner); } else { pj_scan_get_newline(scanner); @@ -1073,12 +1187,13 @@ void pjsip_parse_end_hdr_imp( pj_scanner *scanner ) static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr, pj_scanner *scanner) { - pj_scan_get_until( scanner, pjsip_ARRAY_ELEMENTS, &hdr->values[0]); + pj_scan_get_until( scanner, &pjsip_ARRAY_ELEMENTS, &hdr->values[0]); hdr->count++; - while (*scanner->current == ',') { + while (*scanner->curptr == ',') { pj_scan_get_char(scanner); - pj_scan_get_until( scanner, pjsip_ARRAY_ELEMENTS, &hdr->values[hdr->count]); + pj_scan_get_until( scanner, &pjsip_ARRAY_ELEMENTS, + &hdr->values[hdr->count]); hdr->count++; } parse_hdr_end(scanner); @@ -1088,7 +1203,7 @@ static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr, static void parse_generic_string_hdr( pjsip_generic_string_hdr *hdr, pj_scanner *scanner ) { - pj_scan_get_until( scanner, pjsip_NEWLINE_OR_EOF_SPEC, &hdr->hvalue); + pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->hvalue); parse_hdr_end(scanner); } @@ -1097,38 +1212,39 @@ static void parse_generic_int_hdr( pjsip_generic_int_hdr *hdr, pj_scanner *scanner ) { pj_str_t tmp; - pj_scan_get_until( scanner, pjsip_NEWLINE_OR_EOF_SPEC, &tmp); + pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &tmp); hdr->ivalue = pj_strtoul(&tmp); parse_hdr_end(scanner); } /* Parse Accept header. */ -static pjsip_accept_hdr* parse_hdr_accept( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_accept(pjsip_parse_ctx *ctx) { - pjsip_accept_hdr *accept = pjsip_accept_hdr_create(pool); - parse_generic_array_hdr(accept, scanner); - return accept; + pjsip_accept_hdr *accept = pjsip_accept_hdr_create(ctx->pool); + parse_generic_array_hdr(accept, ctx->scanner); + return (pjsip_hdr*)accept; } /* Parse Allow header. */ -static pjsip_allow_hdr* parse_hdr_allow( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_allow(pjsip_parse_ctx *ctx) { - pjsip_allow_hdr *allow = pjsip_allow_hdr_create(pool); - parse_generic_array_hdr(allow, scanner); - return allow; + pjsip_allow_hdr *allow = pjsip_allow_hdr_create(ctx->pool); + parse_generic_array_hdr(allow, ctx->scanner); + return (pjsip_hdr*)allow; } /* Parse Call-ID header. */ -static pjsip_cid_hdr* parse_hdr_call_id( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_call_id(pjsip_parse_ctx *ctx) { - pjsip_cid_hdr *hdr = pjsip_cid_hdr_create(pool); - pj_scan_get_until( scanner, pjsip_NEWLINE_OR_EOF_SPEC, &hdr->id); - parse_hdr_end(scanner); - return hdr; + pjsip_cid_hdr *hdr = pjsip_cid_hdr_create(ctx->pool); + pj_scan_get_until( ctx->scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->id); + parse_hdr_end(ctx->scanner); + + if (ctx->rdata) + ctx->rdata->call_id = hdr->id; + + return (pjsip_hdr*)hdr; } /* Parse and interpret Contact param. */ @@ -1136,7 +1252,7 @@ static void int_parse_contact_param( pjsip_contact_hdr *hdr, pj_scanner *scanner, pj_pool_t *pool) { - while ( *scanner->current == ';' ) { + while ( *scanner->curptr == ';' ) { pj_str_t pname, pvalue; int_parse_param( scanner, &pname, &pvalue); @@ -1159,103 +1275,114 @@ static void int_parse_contact_param( pjsip_contact_hdr *hdr, } /* Parse Contact header. */ -PJ_DEF(pjsip_contact_hdr*) parse_hdr_contact( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx ) { - pjsip_contact_hdr *first = NULL; + pjsip_contact_hdr *first = NULL; + pj_scanner *scanner = ctx->scanner; do { - pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(pool); + pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(ctx->pool); if (first == NULL) first = hdr; else pj_list_insert_before(first, hdr); - if (*scanner->current == '*') { + if (*scanner->curptr == '*') { pj_scan_get_char(scanner); hdr->star = 1; } else { hdr->star = 0; - hdr->uri = int_parse_uri_or_name_addr(scanner, pool, PJSIP_PARSE_URI_AS_NAMEADDR); + hdr->uri = int_parse_uri_or_name_addr(scanner, ctx->pool, + PJSIP_PARSE_URI_AS_NAMEADDR); - int_parse_contact_param(hdr, scanner, pool); + int_parse_contact_param(hdr, scanner, ctx->pool); } - if (*scanner->current != ',') + if (*scanner->curptr != ',') break; pj_scan_get_char(scanner); } while (1); - parse_hdr_end(scanner); - return first; + parse_hdr_end(scanner); + + return (pjsip_hdr*)first; } /* Parse Content-Length header. */ -PJ_DEF(pjsip_clen_hdr*) parse_hdr_content_length( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx ) { pj_str_t digit; pjsip_clen_hdr *hdr; - hdr = pjsip_clen_hdr_create(pool); - pj_scan_get(scanner, pjsip_DIGIT_SPEC, &digit); + hdr = pjsip_clen_hdr_create(ctx->pool); + pj_scan_get(ctx->scanner, &pjsip_DIGIT_SPEC, &digit); hdr->len = pj_strtoul(&digit); - parse_hdr_end(scanner); - return hdr; + parse_hdr_end(ctx->scanner); + + if (ctx->rdata) + ctx->rdata->clen = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Content-Type header. */ -PJ_DEF(pjsip_ctype_hdr*) parse_hdr_content_type( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx ) { pjsip_ctype_hdr *hdr; + pj_scanner *scanner = ctx->scanner; - hdr = pjsip_ctype_hdr_create(pool); + hdr = pjsip_ctype_hdr_create(ctx->pool); /* Parse media type and subtype. */ - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->media.type); + pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.type); pj_scan_get_char(scanner); - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->media.subtype); + pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.subtype); /* Parse media parameters */ - while (*scanner->current == ';') { + while (*scanner->curptr == ';') { pj_str_t pname, pvalue; int_parse_param(scanner, &pname, &pvalue); - concat_param(&hdr->media.param, pool, &pname, &pvalue); + concat_param(&hdr->media.param, ctx->pool, &pname, &pvalue); } - parse_hdr_end(scanner); - return hdr; + parse_hdr_end(ctx->scanner); + + if (ctx->rdata) + ctx->rdata->ctype = hdr; + + return (pjsip_hdr*)hdr; } /* Parse CSeq header. */ -PJ_DEF(pjsip_cseq_hdr*) parse_hdr_cseq( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx ) { pj_str_t cseq, method; pjsip_cseq_hdr *hdr; - hdr = pjsip_cseq_hdr_create(pool); - pj_scan_get( scanner, pjsip_DIGIT_SPEC, &cseq); + hdr = pjsip_cseq_hdr_create(ctx->pool); + pj_scan_get( ctx->scanner, &pjsip_DIGIT_SPEC, &cseq); hdr->cseq = pj_strtoul(&cseq); - pj_scan_get( scanner, pjsip_TOKEN_SPEC, &method); + pj_scan_get( ctx->scanner, &pjsip_TOKEN_SPEC, &method); pjsip_method_init_np(&hdr->method, &method); - parse_hdr_end( scanner ); - return hdr; + parse_hdr_end( ctx->scanner ); + + if (ctx->rdata) + ctx->rdata->cseq = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Expires header. */ -static pjsip_expires_hdr* parse_hdr_expires(pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx) { - pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(pool); - parse_generic_int_hdr(hdr, scanner); - return hdr; + pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool); + parse_generic_int_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } /* Parse From: or To: header. */ @@ -1267,7 +1394,7 @@ static void parse_hdr_fromto( pj_scanner *scanner, PJSIP_PARSE_URI_AS_NAMEADDR | PJSIP_PARSE_URI_IN_FROM_TO_HDR); - while ( *scanner->current == ';' ) { + while ( *scanner->curptr == ';' ) { pj_str_t pname, pvalue; int_parse_param( scanner, &pname, &pvalue); @@ -1284,66 +1411,71 @@ static void parse_hdr_fromto( pj_scanner *scanner, } /* Parse From: header. */ -PJ_DEF(pjsip_from_hdr*) parse_hdr_from( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx ) { - pjsip_from_hdr *hdr = pjsip_from_hdr_create(pool); - parse_hdr_fromto(scanner, pool, hdr); - return hdr; + pjsip_from_hdr *hdr = pjsip_from_hdr_create(ctx->pool); + parse_hdr_fromto(ctx->scanner, ctx->pool, hdr); + if (ctx->rdata) + ctx->rdata->from = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Require: header. */ -static pjsip_require_hdr* parse_hdr_require( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx ) { - pjsip_require_hdr *hdr = pjsip_require_hdr_create(pool); - parse_generic_array_hdr(hdr, scanner); - return hdr; + pjsip_require_hdr *hdr = pjsip_require_hdr_create(ctx->pool); + parse_generic_array_hdr(hdr, ctx->scanner); + + if (ctx->rdata && ctx->rdata->require == NULL) + ctx->rdata->require = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Retry-After: header. */ -static pjsip_retry_after_hdr* parse_hdr_retry_after(pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx) { pjsip_retry_after_hdr *hdr; - hdr = pjsip_retry_after_hdr_create(pool); - parse_generic_int_hdr(hdr, scanner); - return hdr; + hdr = pjsip_retry_after_hdr_create(ctx->pool); + parse_generic_int_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } /* Parse Supported: header. */ -static pjsip_supported_hdr* parse_hdr_supported(pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_supported(pjsip_parse_ctx *ctx) { - pjsip_supported_hdr *hdr = pjsip_supported_hdr_create(pool); - parse_generic_array_hdr(hdr, scanner); - return hdr; + pjsip_supported_hdr *hdr = pjsip_supported_hdr_create(ctx->pool); + parse_generic_array_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } /* Parse To: header. */ -PJ_DEF(pjsip_to_hdr*) parse_hdr_to( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx ) { - pjsip_to_hdr *hdr = pjsip_to_hdr_create(pool); - parse_hdr_fromto(scanner, pool, hdr); - return hdr; + pjsip_to_hdr *hdr = pjsip_to_hdr_create(ctx->pool); + parse_hdr_fromto(ctx->scanner, ctx->pool, hdr); + + if (ctx->rdata) + ctx->rdata->to = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Unsupported: header. */ -static pjsip_unsupported_hdr* parse_hdr_unsupported(pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_unsupported(pjsip_parse_ctx *ctx) { - pjsip_unsupported_hdr *hdr = pjsip_unsupported_hdr_create(pool); - parse_generic_array_hdr(hdr, scanner); - return hdr; + pjsip_unsupported_hdr *hdr = pjsip_unsupported_hdr_create(ctx->pool); + parse_generic_array_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } /* Parse and interpret Via parameters. */ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner, pj_pool_t *pool) { - while ( *scanner->current == ';' ) { + while ( *scanner->curptr == ';' ) { pj_str_t pname, pvalue; int_parse_param( scanner, &pname, &pvalue); @@ -1373,23 +1505,25 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner, } /* Parse Max-Forwards header. */ -static pjsip_max_forwards_hdr* parse_hdr_max_forwards( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx ) { pjsip_max_forwards_hdr *hdr; - hdr = pjsip_max_forwards_hdr_create(pool); - parse_generic_int_hdr(hdr, scanner); - return hdr; + hdr = pjsip_max_forwards_hdr_create(ctx->pool); + parse_generic_int_hdr(hdr, ctx->scanner); + + if (ctx->rdata) + ctx->rdata->max_fwd = hdr; + + return (pjsip_hdr*)hdr; } /* Parse Min-Expires header. */ -static pjsip_min_expires_hdr* parse_hdr_min_expires(pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_min_expires(pjsip_parse_ctx *ctx) { pjsip_min_expires_hdr *hdr; - hdr = pjsip_min_expires_hdr_create(pool); - parse_generic_int_hdr(hdr, scanner); - return hdr; + hdr = pjsip_min_expires_hdr_create(ctx->pool); + parse_generic_int_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } @@ -1400,65 +1534,76 @@ static void parse_hdr_rr_route( pj_scanner *scanner, pj_pool_t *pool, pjsip_name_addr *temp=int_parse_name_addr(scanner, pool); pj_memcpy(&hdr->name_addr, temp, sizeof(*temp)); - if (*scanner->current == ';') { - pj_scan_get_until(scanner, pjsip_NEWLINE_OR_EOF_SPEC, &hdr->other_param); + if (*scanner->curptr == ';') { + pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, + &hdr->other_param); } } /* Parse Record-Route header. */ -PJ_DEF(pjsip_rr_hdr*) parse_hdr_rr( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx) { - pjsip_rr_hdr *first = NULL; + pjsip_rr_hdr *first = NULL; + pj_scanner *scanner = ctx->scanner; do { - pjsip_rr_hdr *hdr = pjsip_rr_hdr_create(pool); + pjsip_rr_hdr *hdr = pjsip_rr_hdr_create(ctx->pool); if (!first) { first = hdr; } else { pj_list_insert_before(first, hdr); } - parse_hdr_rr_route(scanner, pool, hdr); - if (*scanner->current == ',') { + parse_hdr_rr_route(scanner, ctx->pool, hdr); + if (*scanner->curptr == ',') { pj_scan_get_char(scanner); } else { break; } } while (1); - parse_hdr_end(scanner); - return first; + parse_hdr_end(scanner); + + if (ctx->rdata && ctx->rdata->record_route==NULL) + ctx->rdata->record_route = first; + + return (pjsip_hdr*)first; } /* Parse Route: header. */ -PJ_DEF(pjsip_route_hdr*) parse_hdr_route( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx ) { - pjsip_route_hdr *first = NULL; + pjsip_route_hdr *first = NULL; + pj_scanner *scanner = ctx->scanner; do { - pjsip_route_hdr *hdr = pjsip_route_hdr_create(pool); + pjsip_route_hdr *hdr = pjsip_route_hdr_create(ctx->pool); if (!first) { first = hdr; } else { pj_list_insert_before(first, hdr); } - parse_hdr_rr_route(scanner, pool, hdr); - if (*scanner->current == ',') { + parse_hdr_rr_route(scanner, ctx->pool, hdr); + if (*scanner->curptr == ',') { pj_scan_get_char(scanner); } else { break; } } while (1); - parse_hdr_end(scanner); - return first; + parse_hdr_end(scanner); + + if (ctx->rdata && ctx->rdata->route==NULL) + ctx->rdata->route = first; + + return (pjsip_hdr*)first; } /* Parse Via: header. */ -PJ_DEF(pjsip_via_hdr*) parse_hdr_via( pj_scanner *scanner, pj_pool_t *pool) +static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx ) { - pjsip_via_hdr *first = NULL; + pjsip_via_hdr *first = NULL; + pj_scanner *scanner = ctx->scanner; do { - pjsip_via_hdr *hdr = pjsip_via_hdr_create(pool); + pjsip_via_hdr *hdr = pjsip_via_hdr_create(ctx->pool); if (!first) first = hdr; else @@ -1469,46 +1614,49 @@ PJ_DEF(pjsip_via_hdr*) parse_hdr_via( pj_scanner *scanner, pj_pool_t *pool) pj_scan_advance_n( scanner, 8, 1); - pj_scan_get( scanner, pjsip_TOKEN_SPEC, &hdr->transport); - pj_scan_get( scanner, pjsip_HOST_SPEC, &hdr->sent_by.host); + pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hdr->transport); + pj_scan_get( scanner, &pjsip_HOST_SPEC, &hdr->sent_by.host); - if (*scanner->current==':') { + if (*scanner->curptr==':') { pj_str_t digit; pj_scan_get_char(scanner); - pj_scan_get(scanner, pjsip_DIGIT_SPEC, &digit); + pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &digit); hdr->sent_by.port = pj_strtoul(&digit); } else { hdr->sent_by.port = 5060; } - int_parse_via_param(hdr, scanner, pool); + int_parse_via_param(hdr, scanner, ctx->pool); - if (*scanner->current == '(') { + if (*scanner->curptr == '(') { pj_scan_get_char(scanner); pj_scan_get_until_ch( scanner, ')', &hdr->comment); pj_scan_get_char( scanner ); } - if (*scanner->current != ',') + if (*scanner->curptr != ',') break; pj_scan_get_char(scanner); } while (1); - parse_hdr_end(scanner); - return first; + parse_hdr_end(scanner); + + if (ctx->rdata && ctx->rdata->via == NULL) + ctx->rdata->via = first; + + return (pjsip_hdr*)first; } /* Parse generic header. */ -PJ_DEF(pjsip_generic_string_hdr*) parse_hdr_generic_string( pj_scanner *scanner, - pj_pool_t *pool) +static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx ) { pjsip_generic_string_hdr *hdr; - hdr = pjsip_generic_string_hdr_create(pool, NULL); - parse_generic_string_hdr(hdr, scanner); - return hdr; + hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL); + parse_generic_string_hdr(hdr, ctx->scanner); + return (pjsip_hdr*)hdr; } @@ -1517,23 +1665,28 @@ PJ_DEF(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname, char *buf, pj_size_t size, int *parsed_len ) { pj_scanner scanner; - pjsip_hdr *hdr = NULL; + pjsip_hdr *hdr = NULL; + pjsip_parse_ctx context; PJ_USE_EXCEPTION; init_sip_parser(); - pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error); + pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, + &on_syntax_error); + + context.scanner = &scanner; + context.pool = pool; + context.rdata = NULL; PJ_TRY { pjsip_parse_hdr_func *handler = find_handler(hname); if (handler) { - hdr = (*handler)(&scanner, pool); + hdr = (*handler)(&context); } else { - pjsip_generic_string_hdr *ghdr = parse_hdr_generic_string(&scanner, pool); - ghdr->type = PJSIP_H_OTHER; - pj_strdup(pool, &ghdr->name, hname); - ghdr->sname = ghdr->name; - hdr = (pjsip_hdr*)ghdr; + hdr = parse_hdr_generic_string(&context); + hdr->type = PJSIP_H_OTHER; + pj_strdup(pool, &hdr->name, hname); + hdr->sname = hdr->name; } } @@ -1543,7 +1696,7 @@ PJ_DEF(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname, PJ_END if (parsed_len) { - *parsed_len = (scanner.current - scanner.begin); + *parsed_len = (scanner.curptr - scanner.begin); } pj_scan_fini(&scanner); diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c index 1267b8b4..b199eaba 100644 --- a/pjsip/src/pjsip/sip_resolve.c +++ b/pjsip/src/pjsip/sip_resolve.c @@ -1,11 +1,11 @@ /* $Id$ - * */ #include #include #include -#include +#include +#include struct pjsip_resolver_t { @@ -21,7 +21,7 @@ PJ_DEF(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool) PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver) { - PJ_UNUSED_ARG(resolver) + PJ_UNUSED_ARG(resolver); } static int is_str_ip(const pj_str_t *host) @@ -30,7 +30,7 @@ static int is_str_ip(const pj_str_t *host) const char *end = ((const char*)host->ptr) + host->slen; while (p != end) { - if (isdigit(*p) || *p=='.') { + if (pj_isdigit(*p) || *p=='.') { ++p; } else { return 0; @@ -50,8 +50,8 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, int is_ip_addr; pjsip_transport_type_e type = target->type; - PJ_UNUSED_ARG(resolver) - PJ_UNUSED_ARG(pool) + PJ_UNUSED_ARG(resolver); + PJ_UNUSED_ARG(pool); /* We only do synchronous resolving at this moment. */ PJ_TODO(SUPPORT_RFC3263_SERVER_RESOLUTION) @@ -94,9 +94,11 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, /* Resolve hostname. */ if (!is_ip_addr) { - status = pj_sockaddr_init(&svr_addr.entry[0].addr, &target->host, target->port); + status = pj_sockaddr_in_init(&svr_addr.entry[0].addr, &target->host, + (pj_uint16_t)target->port); } else { - status = pj_sockaddr_init(&svr_addr.entry[0].addr, &target->host, target->port); + status = pj_sockaddr_in_init(&svr_addr.entry[0].addr, &target->host, + (pj_uint16_t)target->port); pj_assert(status == PJ_SUCCESS); } diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index cdb20626..ebc0a803 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -1,5 +1,4 @@ /* $Id$ - * */ #include #include @@ -7,14 +6,16 @@ #include #include #include +#include #include #include #include #include #include +#include /* Thread Local Storage ID for transaction lock (initialized by endpoint) */ -int pjsip_tsx_lock_tls_id; +long pjsip_tsx_lock_tls_id; /* State names */ static const char *state_str[] = @@ -43,10 +44,14 @@ typedef struct tsx_lock_data { int is_alive; } tsx_lock_data; + /* Timer timeout value constants */ -static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, PJSIP_T1_TIMEOUT%1000 }; -static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000, PJSIP_T4_TIMEOUT%1000 }; -static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000, PJSIP_TD_TIMEOUT%1000 }; +static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, + PJSIP_T1_TIMEOUT%1000 }; +static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000, + PJSIP_T4_TIMEOUT%1000 }; +static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000, + PJSIP_TD_TIMEOUT%1000 }; static const pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000, (64*PJSIP_T1_TIMEOUT)%1000 }; @@ -58,35 +63,39 @@ enum Transaction_Timer_Id }; /* Function Prototypes */ -static int pjsip_tsx_on_state_null( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_trying( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_terminated( pjsip_transaction *tsx, - pjsip_event *event); -static int pjsip_tsx_on_state_destroyed( pjsip_transaction *tsx, - pjsip_event *event); -static void tsx_timer_callback( pj_timer_heap_t *theap, - pj_timer_entry *entry); -static int tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata); -static void lock_tsx( pjsip_transaction *tsx, struct tsx_lock_data *lck ); -static pj_status_t unlock_tsx( pjsip_transaction *tsx, struct tsx_lock_data *lck ); +static pj_status_t pjsip_tsx_on_state_null( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_calling( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_trying( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_confirmed(pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_terminated(pjsip_transaction *tsx, + pjsip_event *event); +static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx, + pjsip_event *event); + +static void tsx_timer_callback( pj_timer_heap_t *theap, + pj_timer_entry *entry); +static int tsx_send_msg( pjsip_transaction *tsx, + pjsip_tx_data *tdata); +static void lock_tsx( pjsip_transaction *tsx, struct + tsx_lock_data *lck ); +static pj_status_t unlock_tsx( pjsip_transaction *tsx, + struct tsx_lock_data *lck ); /* State handlers for UAC, indexed by state */ -static int (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *tsx, - pjsip_event *event ) = +static int (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *, + pjsip_event *) = { &pjsip_tsx_on_state_null, &pjsip_tsx_on_state_calling, @@ -99,8 +108,8 @@ static int (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *tsx }; /* State handlers for UAS */ -static int (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *tsx, - pjsip_event *event ) = +static int (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *, + pjsip_event *) = { &pjsip_tsx_on_state_null, &pjsip_tsx_on_state_calling, @@ -153,11 +162,11 @@ PJ_DEF(const char *) pjsip_role_name(pjsip_role_e role) * The transaction key is constructed from the common components of above * components. Additional comparison is needed to fully match a transaction. */ -void create_tsx_key_2543( pj_pool_t *pool, - pj_str_t *str, - pjsip_role_e role, - const pjsip_method *method, - const pjsip_rx_data *rdata ) +static pj_status_t create_tsx_key_2543( pj_pool_t *pool, + pj_str_t *str, + pjsip_role_e role, + const pjsip_method *method, + const pjsip_rx_data *rdata ) { #define SEPARATOR '$' char *key, *p, *end; @@ -166,17 +175,22 @@ void create_tsx_key_2543( pj_pool_t *pool, pjsip_uri *req_uri; pj_str_t *host; + PJ_ASSERT_RETURN(pool && str && method && rdata, PJ_EINVAL); + PJ_ASSERT_RETURN(rdata->msg, PJ_EINVAL); + PJ_ASSERT_RETURN(rdata->via, PJSIP_EMISSINGHDR); + PJ_ASSERT_RETURN(rdata->cseq, PJSIP_EMISSINGHDR); + PJ_ASSERT_RETURN(rdata->from, PJSIP_EMISSINGHDR); + host = &rdata->via->sent_by.host; req_uri = (pjsip_uri*)rdata->msg->line.req.uri; /* Calculate length required. */ - len_required = PJSIP_MAX_URL_SIZE + /* URI */ - 9 + /* CSeq number */ - rdata->from_tag.slen + /* From tag. */ + len_required = 9 + /* CSeq number */ + rdata->from->tag.slen + /* From tag. */ rdata->call_id.slen + /* Call-ID */ host->slen + /* Via host. */ 9 + /* Via port. */ - 32; /* Separator+Allowance. */ + 16; /* Separator+Allowance. */ key = p = pj_pool_alloc(pool, len_required); end = p + len_required; @@ -223,9 +237,6 @@ void create_tsx_key_2543( pj_pool_t *pool, * only used to match request retransmission, and we expect that the * request retransmissions will contain the same port. */ - if ((end-p) < host->slen + 12) { - goto on_error; - } pj_memcpy(p, host->ptr, host->slen); p += host->slen; *p++ = ':'; @@ -240,27 +251,22 @@ void create_tsx_key_2543( pj_pool_t *pool, str->ptr = key; str->slen = p-key; - return; - -on_error: - PJ_LOG(2,("tsx........", "Not enough buffer (%d) for transaction key", - len_required)); - pj_assert(0); - str->ptr = NULL; - str->slen = 0; + return PJ_SUCCESS; } /* * Create transaction key for RFC3161 compliant system. */ -void create_tsx_key_3261( pj_pool_t *pool, - pj_str_t *key, - pjsip_role_e role, - const pjsip_method *method, - const pj_str_t *branch ) +static pj_status_t create_tsx_key_3261( pj_pool_t *pool, + pj_str_t *key, + pjsip_role_e role, + const pjsip_method *method, + const pj_str_t *branch) { char *p; + PJ_ASSERT_RETURN(pool && key && method && branch, PJ_EINVAL); + p = key->ptr = pj_pool_alloc(pool, branch->slen + method->name.slen + 4 ); /* Add role. */ @@ -280,18 +286,22 @@ void create_tsx_key_3261( pj_pool_t *pool, /* Set length */ key->slen = p - key->ptr; + + return PJ_SUCCESS; } /* * Create key from the incoming data, to be used to search the transaction * in the transaction hash table. */ -PJ_DEF(void) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, - pjsip_role_e role, - const pjsip_method *method, - const pjsip_rx_data *rdata ) +PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, + pjsip_role_e role, + const pjsip_method *method, + const pjsip_rx_data *rdata) { - pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID, PJSIP_RFC3261_BRANCH_LEN}; + pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID, + PJSIP_RFC3261_BRANCH_LEN}; + /* Get the branch parameter in the top-most Via. * If branch parameter is started with "z9hG4bK", then the message was @@ -300,17 +310,18 @@ PJ_DEF(void) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, */ const pj_str_t *branch = &rdata->via->branch_param; - if (pj_strncmp(branch, &rfc3261_branch, PJSIP_RFC3261_BRANCH_LEN) == 0) { + if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) { /* Create transaction key. */ - create_tsx_key_3261(pool, key, role, method, branch); + return create_tsx_key_3261(pool, key, role, method, branch); } else { - /* Create the key for the message. This key will be matched up with the - * transaction key. For RFC2563 transactions, the transaction key - * was created by the same function, so it will match the message. + /* Create the key for the message. This key will be matched up + * with the transaction key. For RFC2563 transactions, the + * transaction key was created by the same function, so it will + * match the message. */ - create_tsx_key_2543( pool, key, role, method, rdata ); + return create_tsx_key_2543( pool, key, role, method, rdata ); } } @@ -318,10 +329,12 @@ PJ_DEF(void) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, /* * Create new transaction. */ -PJ_DEF(pjsip_transaction *) pjsip_tsx_create(pj_pool_t *pool, - pjsip_endpoint *endpt) +pj_status_t pjsip_tsx_create( pj_pool_t *pool, + pjsip_endpoint *endpt, + pjsip_transaction **p_tsx) { pjsip_transaction *tsx; + pj_status_t status; tsx = pj_pool_calloc(pool, 1, sizeof(pjsip_transaction)); @@ -335,13 +348,14 @@ PJ_DEF(pjsip_transaction *) pjsip_tsx_create(pj_pool_t *pool, tsx->timeout_timer._timer_id = -1; tsx->timeout_timer.user_data = tsx; tsx->timeout_timer.cb = &tsx_timer_callback; - sprintf(tsx->obj_name, "tsx%p", tsx); - tsx->mutex = pj_mutex_create(pool, "mtsx%p", 0); - if (!tsx->mutex) { - return NULL; + pj_sprintf(tsx->obj_name, "tsx%p", tsx); + status = pj_mutex_create_recursive(pool, "mtsx%p", &tsx->mutex); + if (status != PJ_SUCCESS) { + return status; } - return tsx; + *p_tsx = tsx; + return PJ_SUCCESS; } /* @@ -352,7 +366,8 @@ static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) struct tsx_lock_data *prev_data; pj_mutex_lock(tsx->mutex); - prev_data = (struct tsx_lock_data *) pj_thread_local_get(pjsip_tsx_lock_tls_id); + prev_data = (struct tsx_lock_data *) + pj_thread_local_get(pjsip_tsx_lock_tls_id); lck->prev = prev_data; lck->tsx = tsx; lck->is_alive = 1; @@ -367,7 +382,8 @@ static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) * because when transaction is destroyed the is_alive flag for the transaction * will be set to zero. */ -static pj_status_t unlock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) +static pj_status_t unlock_tsx( pjsip_transaction *tsx, + struct tsx_lock_data *lck) { pj_assert( (void*)pj_thread_local_get(pjsip_tsx_lock_tls_id) == lck); pj_assert( lck->tsx == tsx ); @@ -375,7 +391,7 @@ static pj_status_t unlock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) if (lck->is_alive) pj_mutex_unlock(tsx->mutex); - return lck->is_alive ? 0 : -1; + return lck->is_alive ? PJ_SUCCESS : PJSIP_ETSXDESTROYED; } /* @@ -383,13 +399,14 @@ static pj_status_t unlock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck) */ static void tsx_set_state( pjsip_transaction *tsx, pjsip_tsx_state_e state, - const pjsip_event *event ) + pjsip_event_id_e event_src_type, + void *event_src ) { pjsip_event e; - PJ_LOG(4, (tsx->obj_name, "STATE %s-->%s, ev=%s (src:%s)", - state_str[tsx->state], state_str[state], pjsip_event_str(event->type), - pjsip_event_str(event->src_type))); + PJ_LOG(4, (tsx->obj_name, "STATE %s-->%s, cause = %s", + state_str[tsx->state], state_str[state], + pjsip_event_str(event_src_type))); /* Change state. */ tsx->state = state; @@ -402,9 +419,7 @@ static void tsx_set_state( pjsip_transaction *tsx, } /* Inform TU */ - pj_memcpy(&e, event, sizeof(*event)); - e.type = PJSIP_EVENT_TSX_STATE_CHANGED; - e.obj.tsx = tsx; + PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src); pjsip_endpt_send_tsx_event( tsx->endpt, &e ); /* When the transaction is terminated, release transport, and free the @@ -413,7 +428,9 @@ static void tsx_set_state( pjsip_transaction *tsx, if (state == PJSIP_TSX_STATE_TERMINATED) { /* Decrement transport reference counter. */ - if (tsx->transport && tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) { + if (tsx->transport && + tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) + { pjsip_transport_dec_ref( tsx->transport ); tsx->transport = NULL; } @@ -483,7 +500,8 @@ static pj_status_t tsx_process_route( pjsip_transaction *tsx, topmost_route_uri = &first_route_hdr->name_addr; while (last_route_hdr->next != (void*)&tdata->msg->hdr) { pjsip_route_hdr *hdr; - hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, last_route_hdr->next); + hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, + last_route_hdr->next); if (!hdr) break; last_route_hdr = hdr; @@ -563,14 +581,16 @@ static pj_status_t tsx_process_route( pjsip_transaction *tsx, send_addr->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE); pj_strdup(tdata->pool, &send_addr->host, &url->host); send_addr->port = url->port; - send_addr->type = pjsip_transport_get_type_from_name(&url->transport_param); + send_addr->type = + pjsip_transport_get_type_from_name(&url->transport_param); } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) { pjsip_uri *uri = (pjsip_uri*) target_uri; const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri); pj_strdup(tdata->pool, &send_addr->host, &url->host); send_addr->port = url->port; - send_addr->type = pjsip_transport_get_type_from_name(&url->transport_param); + send_addr->type = + pjsip_transport_get_type_from_name(&url->transport_param); #if PJ_HAS_TCP if (send_addr->type == PJSIP_TRANSPORT_TCP || send_addr->type == PJSIP_TRANSPORT_SCTP) @@ -579,9 +599,8 @@ static pj_status_t tsx_process_route( pjsip_transaction *tsx, } #endif } else { - PJ_LOG(2, (tsx->obj_name, "Unable to lookup destination address for " - "non SIP-URL")); - return -1; + pj_assert(!"Unsupported URI scheme!"); + return PJSIP_EINVALIDSCHEME; } /* If target URI is different than request URI, replace @@ -598,7 +617,7 @@ static pj_status_t tsx_process_route( pjsip_transaction *tsx, } /* Success. */ - return 0; + return PJ_SUCCESS; } @@ -624,7 +643,7 @@ static void tsx_transport_callback(pjsip_transport_t *tr, pjsip_transport_get_type_name(tr), addr, tsx->dest_name.port)); } else { - PJ_LOG(3, (tsx->obj_name, "%s unable to connect to %s:%d, status=%d", + PJ_LOG(4, (tsx->obj_name, "%s unable to connect to %s:%d, status=%d", pjsip_transport_get_type_name(tr), addr, tsx->dest_name.port, status)); } @@ -633,23 +652,19 @@ static void tsx_transport_callback(pjsip_transport_t *tr, lock_tsx(tsx, &lck); if (status != PJ_SUCCESS) { - pjsip_event event; - - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tsx->last_tx; - tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL; tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR; - tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, &event); + + tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); /* Unlock transaction. */ unlock_tsx(tsx, &lck); return; } - /* See if transaction has already been terminated. If so, schedule to destroy - * the transaction. + /* See if transaction has already been terminated. + * If so, schedule to destroy the transaction. */ if (tsx->state == PJSIP_TSX_STATE_TERMINATED) { pj_time_val timeout = {0, 0}; @@ -690,15 +705,10 @@ static void tsx_resolver_callback(pj_status_t status, PJ_LOG(4, (tsx->obj_name, "resolver job complete, status=%d", status)); if (status != PJ_SUCCESS || addr->count == 0) { - pjsip_event event; - - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tsx->last_tx; - lock_tsx(tsx, &lck); tsx->status_code = PJSIP_SC_TSX_RESOLVE_ERROR; - tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, &event); + tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); unlock_tsx(tsx, &lck); return; } @@ -711,8 +721,8 @@ static void tsx_resolver_callback(pj_status_t status, /* Create/find the transport for the remote address. */ PJ_LOG(5,(tsx->obj_name, "tsx getting transport for %s:%d", - pj_sockaddr_get_str_addr(&addr->entry[0].addr), - pj_sockaddr_get_port(&addr->entry[0].addr))); + pj_inet_ntoa(addr->entry[0].addr.sin_addr), + pj_ntohs(addr->entry[0].addr.sin_port))); tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_CONNECTING; pjsip_endpt_get_transport(tsx->endpt, tsx->pool, @@ -738,8 +748,8 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, pjsip_msg *msg; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; + pj_status_t status; struct tsx_lock_data lck; - const pjsip_hdr *endpt_hdr; PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAC (tdata=%p)", tdata)); @@ -755,7 +765,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, /* Save method. */ pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method); - /* Generate branch parameter if it doesn't exist. */ + /* Generate Via header if it doesn't exist. */ via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL); if (via == NULL) { via = pjsip_via_hdr_create(tdata->pool); @@ -771,23 +781,23 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN; pj_generate_unique_string( &tmp ); - } - /* Copy branch parameter. */ - tsx->branch = via->branch_param; - - /* Add additional request headers from endpoint. */ - endpt_hdr = pjsip_endpt_get_request_headers(tsx->endpt)->next; - while (endpt_hdr != pjsip_endpt_get_request_headers(tsx->endpt)) { - pjsip_hdr *hdr = pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr); - pjsip_msg_add_hdr( tdata->msg, hdr ); - endpt_hdr = endpt_hdr->next; + /* Save branch parameter. */ + tsx->branch = via->branch_param; + } else { + /* Copy branch parameter. */ + pj_strdup(tsx->pool, &tsx->branch, &via->branch_param); } + /* Generate transaction key. */ - create_tsx_key_3261( tsx->pool, &tsx->transaction_key, - PJSIP_ROLE_UAC, &tsx->method, - &via->branch_param); + status = create_tsx_key_3261( tsx->pool, &tsx->transaction_key, + PJSIP_ROLE_UAC, &tsx->method, + &via->branch_param); + if (status != PJ_SUCCESS) { + unlock_tsx(tsx, &lck); + return status; + } PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen, tsx->transaction_key.ptr)); @@ -795,8 +805,9 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, /* Save CSeq. */ cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL); if (!cseq) { - PJ_LOG(4,(tsx->obj_name, "CSeq header not present in outgoing message!")); - return -1; + pj_assert(!"CSeq header not present in outgoing message!"); + unlock_tsx(tsx, &lck); + return PJSIP_EMISSINGHDR; } tsx->cseq = cseq->cseq; @@ -805,22 +816,17 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, * Manually set-up the state becase we don't want to call the callback. */ tsx->state = PJSIP_TSX_STATE_NULL; - tsx->state_handler = pjsip_tsx_on_state_null; + tsx->state_handler = &pjsip_tsx_on_state_null; /* Get destination name from the message. */ - if (tsx_process_route(tsx, tdata, &tsx->dest_name) != 0) { - pjsip_event event; - PJ_LOG(3,(tsx->obj_name, "Error: unable to get destination address for request")); - - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tsx->last_tx; - + status = tsx_process_route(tsx, tdata, &tsx->dest_name); + if (status != PJ_SUCCESS) { tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL; tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR; - tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, &event); + tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); unlock_tsx(tsx, &lck); - return -1; + return status; } /* Resolve destination. @@ -858,6 +864,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, pjsip_msg *msg = rdata->msg; pj_str_t *branch; pjsip_cseq_hdr *cseq; + pj_status_t status; struct tsx_lock_data lck; PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAS (rdata=%p)", rdata)); @@ -877,8 +884,12 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, /* Get transaction key either from branch for RFC3261 message, or * create transaction key. */ - pjsip_tsx_create_key(tsx->pool, &tsx->transaction_key, PJSIP_ROLE_UAS, - &tsx->method, rdata); + status = pjsip_tsx_create_key(tsx->pool, &tsx->transaction_key, + PJSIP_ROLE_UAS, &tsx->method, rdata); + if (status != PJ_SUCCESS) { + unlock_tsx(tsx, &lck); + return status; + } /* Duplicate branch parameter for transaction. */ branch = &rdata->via->branch_param; @@ -913,7 +924,8 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, tsx->current_addr = 0; tsx->remote_addr.count = 1; - tsx->remote_addr.entry[0].type = pjsip_transport_get_type(tsx->transport); + tsx->remote_addr.entry[0].type = + pjsip_transport_get_type(tsx->transport); pj_memcpy(&tsx->remote_addr.entry[0].addr, &rdata->addr, rdata->addr_len); @@ -923,17 +935,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, status = pjsip_get_response_addr(tsx->pool, rdata->transport, rdata->via, &tsx->dest_name); if (status != PJ_SUCCESS) { - pjsip_event event; - PJ_LOG(2,(tsx->obj_name, "Unable to get destination address " - "for response")); - - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tsx->last_tx; - tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL; tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR; - tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, &event); + tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); unlock_tsx(tsx, &lck); return status; } @@ -943,7 +948,8 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, * the callback will be called. */ PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d", - tsx->dest_name.host.slen, tsx->dest_name.host.ptr, + tsx->dest_name.host.slen, + tsx->dest_name.host.ptr, tsx->dest_name.port)); tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING; @@ -975,11 +981,14 @@ static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry) PJ_UNUSED_ARG(theap); PJ_LOG(5,(tsx->obj_name, "got timer event (%s timer)", - (entry->id == TSX_TIMER_RETRANSMISSION ? "Retransmit" : "Timeout"))); + (entry->id==TSX_TIMER_RETRANSMISSION ? "Retransmit" : "Timeout"))); - event.type = event.src_type = PJSIP_EVENT_TIMER; - event.src.timer = (entry->id == TSX_TIMER_RETRANSMISSION ? - &tsx->retransmit_timer : &tsx->timeout_timer); + + if (entry->id == TSX_TIMER_RETRANSMISSION) { + PJSIP_EVENT_INIT_TIMER(event, &tsx->retransmit_timer); + } else { + PJSIP_EVENT_INIT_TIMER(event, &tsx->timeout_timer); + } /* Dispatch event to transaction. */ lock_tsx(tsx, &lck); @@ -999,10 +1008,11 @@ PJ_DEF(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx, pjsip_tx_data *tdata) { pjsip_msg *msg; pjsip_host_port dest_addr; - pjsip_event event; pjsip_via_hdr *via; struct tsx_lock_data lck; + pj_status_t status = PJ_SUCCESS; + /* Lock tsx. */ lock_tsx(tsx, &lck); pj_assert(tsx->handle_ack != 0); @@ -1023,8 +1033,8 @@ PJ_DEF(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx, pjsip_tx_data *tdata) } /* Get destination name from the message. */ - if (tsx_process_route(tsx, tdata, &dest_addr) != 0){ - PJ_LOG(2,(tsx->obj_name, "Unable to get destination address for request")); + status = tsx_process_route(tsx, tdata, &dest_addr); + if (status != 0){ goto on_error; } @@ -1088,10 +1098,9 @@ on_error: * Send TERMINATED event. */ tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR; - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tdata; - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, &event); + + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); unlock_tsx(tsx, &lck); } @@ -1105,19 +1114,16 @@ PJ_DEF(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx, { pjsip_event event; struct tsx_lock_data lck; + pj_status_t status; - PJ_LOG(5,(tsx->obj_name, "on transmit msg (tdata=%p)", tdata)); - - event.type = event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tdata; + PJ_LOG(5,(tsx->obj_name, "Request to transmit msg on state %s (tdata=%p)", + state_str[tsx->state], tdata)); - PJ_LOG(5,(tsx->obj_name, "on state %s (ev=%s, src=%s, data=%p)", - state_str[tsx->state], pjsip_event_str(event.type), - pjsip_event_str(event.src_type), event.src.data)); + PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata); /* Dispatch to transaction. */ lock_tsx(tsx, &lck); - (*tsx->state_handler)(tsx, &event); + status = (*tsx->state_handler)(tsx, &event); unlock_tsx(tsx, &lck); } @@ -1130,17 +1136,16 @@ PJ_DEF(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx, { pjsip_event event; struct tsx_lock_data lck; + pj_status_t status; - event.type = event.src_type = PJSIP_EVENT_RX_MSG; - event.src.rdata = rdata; + PJ_LOG(5,(tsx->obj_name, "Incoming msg on state %s (rdata=%p)", + state_str[tsx->state], rdata)); - PJ_LOG(5,(tsx->obj_name, "on state %s (ev=%s, src=%s, data=%p)", - state_str[tsx->state], pjsip_event_str(event.type), - pjsip_event_str(event.src_type), event.src.data)); + PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata); /* Dispatch to transaction. */ lock_tsx(tsx, &lck); - (*tsx->state_handler)(tsx, &event); + status = (*tsx->state_handler)(tsx, &event); unlock_tsx(tsx, &lck); } @@ -1149,17 +1154,12 @@ PJ_DEF(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx, */ PJ_DEF(void) pjsip_tsx_terminate( pjsip_transaction *tsx, int code ) { - pjsip_event event; struct tsx_lock_data lck; lock_tsx(tsx, &lck); - tsx->status_code = code; - event.type = PJSIP_EVENT_USER; - event.src_type = PJSIP_EVENT_USER; - event.src.data = 0; - event.obj.tsx = tsx; - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, &event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_USER, NULL); unlock_tsx(tsx, &lck); } @@ -1169,14 +1169,15 @@ PJ_DEF(void) pjsip_tsx_terminate( pjsip_transaction *tsx, int code ) * If transport is not yet available, then do nothing. The message will be * transmitted when transport connection completion callback is called. */ -static int tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata) +static pj_status_t tsx_send_msg( pjsip_transaction *tsx, + pjsip_tx_data *tdata) { - pjsip_event event; + pj_status_t status = PJ_SUCCESS; PJ_LOG(5,(tsx->obj_name, "sending msg (tdata=%p)", tdata)); if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) { - int sent; + pj_ssize_t sent; pjsip_event before_tx_event; pj_assert(tsx->transport != NULL); @@ -1199,25 +1200,22 @@ static int tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata) pj_strdup2(tdata->pool, &via->transport, pjsip_transport_get_type_name(tsx->transport)); pj_strdup2(tdata->pool, &via->sent_by.host, - pj_sockaddr_get_str_addr(addr_name)); - via->sent_by.port = pj_sockaddr_get_port(addr_name); + pj_inet_ntoa(addr_name->sin_addr)); + via->sent_by.port = pj_ntohs(addr_name->sin_port); } } /* Notify everybody we're about to send message. */ - before_tx_event.type = PJSIP_EVENT_BEFORE_TX; - before_tx_event.src_type = PJSIP_EVENT_TX_MSG; - before_tx_event.obj.tsx = tsx; - before_tx_event.src.tdata = tdata; - before_tx_event.data.long_data = tsx->retransmit_count; - pjsip_endpt_send_tsx_event( tsx->endpt, &before_tx_event ); + PJSIP_EVENT_INIT_PRE_TX_MSG(before_tx_event, tsx, tdata, + tsx->retransmit_count); + pjsip_endpt_send_tsx_event( tsx->endpt, &before_tx_event ); tsx->has_unsent_msg = 0; - sent = pjsip_transport_send_msg( - tsx->transport, tdata, - &tsx->remote_addr.entry[tsx->current_addr].addr - ); - if (sent < 1) { + status = pjsip_transport_send_msg( + tsx->transport, tdata, + &tsx->remote_addr.entry[tsx->current_addr].addr, + &sent); + if (status != PJ_SUCCESS) { goto on_error; } } else { @@ -1228,11 +1226,9 @@ static int tsx_send_msg( pjsip_transaction *tsx, pjsip_tx_data *tdata) on_error: tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR; - event.type = PJSIP_EVENT_TRANSPORT_ERROR; - event.src_type = PJSIP_EVENT_TX_MSG; - event.src.tdata = tdata; - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, &event); - return -1; + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TRANSPORT_ERROR, (void*)status); + return status; } /* @@ -1241,6 +1237,8 @@ on_error: static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx, int should_restart_timer) { + pj_status_t status; + PJ_LOG(4,(tsx->obj_name, "retransmiting (tdata=%p, count=%d, restart?=%d)", tsx->last_tx, tsx->retransmit_count, should_restart_timer)); @@ -1248,8 +1246,9 @@ static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx, ++tsx->retransmit_count; - if (tsx_send_msg( tsx, tsx->last_tx) != 0) { - return -1; + status = tsx_send_msg( tsx, tsx->last_tx); + if (status != PJ_SUCCESS) { + return status; } /* Restart timer T1. */ @@ -1257,12 +1256,13 @@ static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx, pj_time_val timeout; int msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT; - if (tsx->method.id != PJSIP_INVITE_METHOD && msec_time > PJSIP_T2_TIMEOUT) + if (tsx->method.id!=PJSIP_INVITE_METHOD && msec_time>PJSIP_T2_TIMEOUT) msec_time = PJSIP_T2_TIMEOUT; timeout.sec = msec_time / 1000; timeout.msec = msec_time % 1000; - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, &timeout); + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, + &timeout); } return PJ_SUCCESS; @@ -1271,8 +1271,11 @@ static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx, /* * Handler for events in state Null. */ -static int pjsip_tsx_on_state_null( pjsip_transaction *tsx, pjsip_event *event ) +static pj_status_t pjsip_tsx_on_state_null( pjsip_transaction *tsx, + pjsip_event *event ) { + pj_status_t status; + pj_assert( tsx->state == PJSIP_TSX_STATE_NULL); pj_assert( tsx->last_tx == NULL ); pj_assert( tsx->has_unsent_msg == 0); @@ -1281,24 +1284,27 @@ static int pjsip_tsx_on_state_null( pjsip_transaction *tsx, pjsip_event *event /* Set state to Trying. */ pj_assert(event->type == PJSIP_EVENT_RX_MSG); - tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); } else { - pjsip_tx_data *tdata = event->src.tdata; + pjsip_tx_data *tdata = event->body.tx_msg.tdata; /* Save the message for retransmission. */ tsx->last_tx = tdata; pjsip_tx_data_add_ref(tdata); /* Send the message. */ - if (tsx_send_msg( tsx, tdata) != 0) { - return -1; + status = tsx_send_msg( tsx, tdata); + if (status != PJ_SUCCESS) { + return status; } /* Start Timer B (or called timer F for non-INVITE) for transaction * timeout. */ - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout_timer_val); + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, + &timeout_timer_val); /* Start Timer A (or timer E) for retransmission only if unreliable * transport is being used. @@ -1306,12 +1312,14 @@ static int pjsip_tsx_on_state_null( pjsip_transaction *tsx, pjsip_event *event if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL && PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) { - pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, &t1_timer_val); + pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, + &t1_timer_val); tsx->retransmit_count = 0; } /* Move state. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, + PJSIP_EVENT_TX_MSG, tdata); } return PJ_SUCCESS; @@ -1321,23 +1329,25 @@ static int pjsip_tsx_on_state_null( pjsip_transaction *tsx, pjsip_event *event * State Calling is for UAC after it sends request but before any responses * is received. */ -static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, - pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_calling( pjsip_transaction *tsx, + pjsip_event *event ) { pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING); pj_assert(tsx->role == PJSIP_ROLE_UAC); if (event->type == PJSIP_EVENT_TIMER && - event->src.timer == &tsx->retransmit_timer) + event->body.timer.entry == &tsx->retransmit_timer) { + pj_status_t status; /* Retransmit the request. */ - if (pjsip_tsx_retransmit( tsx, 1 ) != 0) { - return -1; + status = pjsip_tsx_retransmit( tsx, 1 ); + if (status != PJ_SUCCESS) { + return status; } } else if (event->type == PJSIP_EVENT_TIMER && - event->src.timer == &tsx->timeout_timer) + event->body.timer.entry == &tsx->timeout_timer) { /* Cancel retransmission timer. */ @@ -1349,10 +1359,11 @@ static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, tsx->status_code = PJSIP_SC_TSX_TIMEOUT; /* Inform TU. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event ); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, &tsx->timeout_timer); /* Transaction is destroyed */ - return -1; + return PJSIP_ETSXDESTROYED; } else if (event->type == PJSIP_EVENT_RX_MSG) { int code; @@ -1369,7 +1380,7 @@ static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, * the final response. */ /* Keep last_tx for authorization. */ - code = event->src.rdata->msg->line.status.code; + code = event->body.rx_msg.rdata->msg->line.status.code; if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) { pjsip_tx_data_dec_ref(tsx->last_tx); tsx->last_tx = NULL; @@ -1380,6 +1391,7 @@ static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, } else { pj_assert(0); + return PJ_EBUG; } return PJ_SUCCESS; @@ -1391,9 +1403,10 @@ static int pjsip_tsx_on_state_calling( pjsip_transaction *tsx, * Note: this is different than RFC3261, which can use Trying state for * non-INVITE client transaction (bug in RFC?). */ -static int pjsip_tsx_on_state_trying( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_trying( pjsip_transaction *tsx, + pjsip_event *event) { - int result; + pj_status_t status; pj_assert(tsx->state == PJSIP_TSX_STATE_TRYING); @@ -1414,21 +1427,23 @@ static int pjsip_tsx_on_state_trying( pjsip_transaction *tsx, pjsip_event *even /* The rest of the processing of the event is exactly the same as in * "Proceeding" state. */ - result = pjsip_tsx_on_state_proceeding_uas( tsx, event); + status = pjsip_tsx_on_state_proceeding_uas( tsx, event); /* Inform the TU of the state transision if state is still State_Trying */ - if (result==0 && tsx->state == PJSIP_TSX_STATE_TRYING) { - tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, event); + if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) { + tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, + PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata); } - return result; + return status; } /* * Handler for events in Proceeding for UAS * This state happens after the TU sends provisional response. */ -static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || tsx->state == PJSIP_TSX_STATE_TRYING); @@ -1439,13 +1454,17 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even /* Receive request retransmission. */ if (event->type == PJSIP_EVENT_RX_MSG) { + pj_status_t status; + /* Send last response. */ - if (pjsip_tsx_retransmit( tsx, 0 ) != 0) { - return -1; + status = pjsip_tsx_retransmit( tsx, 0 ); + if (status != PJ_SUCCESS) { + return status; } } else if (event->type == PJSIP_EVENT_TX_MSG ) { - pjsip_tx_data *tdata = event->src.tdata; + pjsip_tx_data *tdata = event->body.tx_msg.tdata; + pj_status_t status; /* The TU sends response message to the request. Save this message so * that we can retransmit the last response in case we receive request @@ -1471,8 +1490,9 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even } /* Send the message. */ - if (tsx_send_msg(tsx, tdata) != 0) { - return -1; + status = tsx_send_msg(tsx, tdata); + if (status != PJ_SUCCESS) { + return status; } // Update To tag header for RFC2543 transaction. @@ -1485,26 +1505,29 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even tsx->last_tx = tdata; pjsip_tx_data_add_ref( tdata ); } - tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, + PJSIP_EVENT_TX_MSG, tdata ); } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) { if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack==0) { - /* 2xx class message is not saved, because retransmission is handled - * by the TU. + /* 2xx class message is not saved, because retransmission + * is handled by TU. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TX_MSG, tdata ); /* Transaction is destroyed. */ - return -1; + return PJSIP_ETSXDESTROYED; } else { pj_time_val timeout; if (tsx->method.id == PJSIP_INVITE_METHOD) { tsx->retransmit_count = 0; - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, + pjsip_endpt_schedule_timer( tsx->endpt, + &tsx->retransmit_timer, &t1_timer_val); } @@ -1525,37 +1548,45 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even timeout.sec = timeout.msec = 0; } - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout); + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, + &timeout); /* Set state to "Completed" */ - tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, + PJSIP_EVENT_TX_MSG, tdata ); } } else if (tsx->status_code >= 300) { - /* 3xx-6xx class message causes transaction to move to "Completed" state. */ + /* 3xx-6xx class message causes transaction to move to + * "Completed" state. + */ if (tsx->last_tx != tdata) { tsx->last_tx = tdata; pjsip_tx_data_add_ref( tdata ); } /* Start timer H for transaction termination */ - pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,&timeout_timer_val); + pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer, + &timeout_timer_val); /* For INVITE, if unreliable transport is used, retransmission * timer G will be scheduled (retransmission). */ if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) { - pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL); + pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, + NULL); if (cseq->method.id == PJSIP_INVITE_METHOD) { tsx->retransmit_count = 0; - pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, + pjsip_endpt_schedule_timer(tsx->endpt, + &tsx->retransmit_timer, &t1_timer_val); } } /* Inform TU */ - tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, + PJSIP_EVENT_TX_MSG, tdata ); } else { pj_assert(0); @@ -1563,34 +1594,38 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even } else if (event->type == PJSIP_EVENT_TIMER && - event->src.timer == &tsx->retransmit_timer) { + event->body.timer.entry == &tsx->retransmit_timer) { /* Retransmission timer elapsed. */ + pj_status_t status; /* Must have last response to retransmit. */ pj_assert(tsx->last_tx != NULL); /* Retransmit the last response. */ - if (pjsip_tsx_retransmit( tsx, 1 ) != 0) { - return -1; + status = pjsip_tsx_retransmit( tsx, 1 ); + if (status != PJ_SUCCESS) { + return status; } } else if (event->type == PJSIP_EVENT_TIMER && - event->src.timer == &tsx->timeout_timer) { + event->body.timer.entry == &tsx->timeout_timer) { /* Timeout timer. should not happen? */ pj_assert(0); tsx->status_code = PJSIP_SC_TSX_TIMEOUT; - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, &tsx->timeout_timer); - return -1; + return PJ_EBUG; } else { pj_assert(0); + return PJ_EBUG; } - return 0; + return PJ_SUCCESS; } /* @@ -1598,7 +1633,8 @@ static int pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, pjsip_even * This state happens after provisional response(s) has been received from * UAS. */ -static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_proceeding_uac(pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || @@ -1610,10 +1646,10 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even */ pj_assert(event->type == PJSIP_EVENT_RX_MSG); if (event->type != PJSIP_EVENT_RX_MSG) { - return 0; + return PJ_EINVALIDOP; } - tsx->status_code = event->src.rdata->msg->line.status.code; + tsx->status_code = event->body.rx_msg.rdata->msg->line.status.code; } else { tsx->status_code = PJSIP_SC_TSX_TIMEOUT; } @@ -1621,7 +1657,8 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) { /* Inform the message to TU. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) { @@ -1632,8 +1669,9 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even * handled in TU). For non-INVITE, state moves to Completed. */ if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack == 0) { - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); - return -1; + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); + return PJSIP_ETSXDESTROYED; } else { pj_time_val timeout; @@ -1649,23 +1687,28 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even } else { timeout.sec = timeout.msec = 0; } - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout); + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, + &timeout); /* Move state to Completed, inform TU. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); } } else if (tsx->status_code >= 300 && tsx->status_code <= 699) { pj_time_val timeout; + pj_status_t status; /* Stop timer B. */ pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer ); /* Generate and send ACK for INVITE. */ if (tsx->method.id == PJSIP_INVITE_METHOD) { - pjsip_endpt_create_ack( tsx->endpt, tsx->last_tx, event->src.rdata ); - if (tsx_send_msg( tsx, tsx->last_tx) != 0) { - return -1; + pjsip_endpt_create_ack( tsx->endpt, tsx->last_tx, + event->body.rx_msg.rdata ); + status = tsx_send_msg( tsx, tsx->last_tx); + if (status != PJ_SUCCESS) { + return status; } } @@ -1682,11 +1725,13 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout); /* Inform TU. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); } else { // Shouldn't happen because there's no timer for this state. pj_assert(0); + return PJ_EBUG; } return PJ_SUCCESS; @@ -1695,18 +1740,22 @@ static int pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx, pjsip_even /* * Handler for events in Completed state for UAS */ -static int pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED); if (event->type == PJSIP_EVENT_RX_MSG) { - pjsip_msg *msg = event->src.rdata->msg; + pjsip_msg *msg = event->body.rx_msg.rdata->msg; pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL ); /* On receive request retransmission, retransmit last response. */ if (cseq->method.id != PJSIP_ACK_METHOD) { - if (pjsip_tsx_retransmit( tsx, 0 ) != 0) { - return -1; + pj_status_t status; + + status = pjsip_tsx_retransmit( tsx, 0 ); + if (status != PJ_SUCCESS) { + return status; } } else { @@ -1717,18 +1766,23 @@ static int pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, pjsip_event /* Start timer I in T4 interval (transaction termination). */ pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer ); - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &t4_timer_val); + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, + &t4_timer_val); /* Move state to "Confirmed" */ - tsx_set_state( tsx, PJSIP_TSX_STATE_CONFIRMED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_CONFIRMED, + PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); } } else if (event->type == PJSIP_EVENT_TIMER) { - if (event->src.timer == &tsx->retransmit_timer) { + if (event->body.timer.entry == &tsx->retransmit_timer) { /* Retransmit message. */ - if (pjsip_tsx_retransmit( tsx, 1 ) != 0) { - return -1; + pj_status_t status; + + status = pjsip_tsx_retransmit( tsx, 1 ); + if (status != PJ_SUCCESS) { + return status; } } else { @@ -1740,20 +1794,22 @@ static int pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, pjsip_event tsx->status_code = PJSIP_SC_TSX_TIMEOUT; - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, &tsx->timeout_timer ); - return -1; + return PJSIP_ETSXDESTROYED; } else { /* Transaction terminated, it can now be deleted. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); - return -1; + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, &tsx->timeout_timer ); + return PJSIP_ETSXDESTROYED; } } } else { /* Ignore request to transmit. */ - pj_assert(event->src.tdata == tsx->last_tx); + pj_assert(event->body.tx_msg.tdata == tsx->last_tx); } return PJ_SUCCESS; @@ -1762,32 +1818,37 @@ static int pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, pjsip_event /* * Handler for events in Completed state for UAC transaction. */ -static int pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED); if (event->type == PJSIP_EVENT_TIMER) { /* Must be the timeout timer. */ - pj_assert(event->src.timer == &tsx->timeout_timer); + pj_assert(event->body.timer.entry == &tsx->timeout_timer); /* Move to Terminated state. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, event->body.timer.entry ); /* Transaction has been destroyed. */ - return -1; + return PJSIP_ETSXDESTROYED; } else if (event->type == PJSIP_EVENT_RX_MSG) { if (tsx->method.id == PJSIP_INVITE_METHOD) { /* On received of final response retransmission, retransmit the ACK. * TU doesn't need to be informed. */ - pjsip_msg *msg = event->src.rdata->msg; + pjsip_msg *msg = event->body.rx_msg.rdata->msg; pj_assert(msg->type == PJSIP_RESPONSE_MSG); if (msg->type==PJSIP_RESPONSE_MSG && msg->line.status.code >= 200) { - if (pjsip_tsx_retransmit( tsx, 0 ) != 0) { - return -1; + pj_status_t status; + + status = pjsip_tsx_retransmit( tsx, 0 ); + if (status != PJ_SUCCESS) { + return status; } } else { /* Very late retransmission of privisional response. */ @@ -1798,34 +1859,41 @@ static int pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx, pjsip_event } } else if (tsx->method.id == PJSIP_INVITE_METHOD && event->type == PJSIP_EVENT_TX_MSG && - event->src.tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) { + event->body.tx_msg.tdata->msg->line.req.method.id==PJSIP_ACK_METHOD) { + + pj_status_t status; /* Set last transmitted message. */ - if (tsx->last_tx != event->src.tdata) { + if (tsx->last_tx != event->body.tx_msg.tdata) { pjsip_tx_data_dec_ref( tsx->last_tx ); - tsx->last_tx = event->src.tdata; + tsx->last_tx = event->body.tx_msg.tdata; pjsip_tx_data_add_ref( tsx->last_tx ); } /* No state changed, but notify app. * Must notify now, so app has chance to put SDP in outgoing ACK msg. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, event ); + tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, + PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata ); /* Send msg */ - tsx_send_msg(tsx, event->src.tdata); + status = tsx_send_msg(tsx, event->body.tx_msg.tdata); + if (status != PJ_SUCCESS) + return status; } else { pj_assert(0); + return PJ_EBUG; } - return 0; + return PJ_SUCCESS; } /* * Handler for events in state Confirmed. */ -static int pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_CONFIRMED); @@ -1835,25 +1903,36 @@ static int pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx, pjsip_event *ev /* Absorb any ACK received. */ if (event->type == PJSIP_EVENT_RX_MSG) { + + pjsip_method_e method_id = + event->body.rx_msg.rdata->msg->line.req.method.id; + /* Must be a request message. */ - pj_assert(event->src.rdata->msg->type == PJSIP_REQUEST_MSG); + pj_assert(event->body.rx_msg.rdata->msg->type == PJSIP_REQUEST_MSG); /* Must be an ACK request or a late INVITE retransmission. */ - pj_assert(event->src.rdata->msg->line.req.method.id == PJSIP_ACK_METHOD || - event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD); + pj_assert(method_id == PJSIP_ACK_METHOD || + method_id == PJSIP_INVITE_METHOD); + + /* Just so that compiler won't complain about unused vars when + * building release code. + */ + PJ_UNUSED_ARG(method_id); } else if (event->type == PJSIP_EVENT_TIMER) { /* Must be from timeout_timer_. */ - pj_assert(event->src.timer == &tsx->timeout_timer); + pj_assert(event->body.timer.entry == &tsx->timeout_timer); /* Move to Terminated state. */ - tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, event); + tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, + PJSIP_EVENT_TIMER, &tsx->timeout_timer ); /* Transaction has been destroyed. */ - return -1; + return PJSIP_ETSXDESTROYED; } else { pj_assert(0); + return PJ_EBUG; } return PJ_SUCCESS; @@ -1862,23 +1941,26 @@ static int pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx, pjsip_event *ev /* * Handler for events in state Terminated. */ -static int pjsip_tsx_on_state_terminated( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_terminated( pjsip_transaction *tsx, + pjsip_event *event) { pj_assert(tsx->state == PJSIP_TSX_STATE_TERMINATED); - PJ_UNUSED_ARG(event) + PJ_UNUSED_ARG(event); /* Destroy this transaction */ - tsx_set_state(tsx, PJSIP_TSX_STATE_DESTROYED, event); + tsx_set_state(tsx, PJSIP_TSX_STATE_DESTROYED, + event->type, event->body.user.user1 ); return PJ_SUCCESS; } -static int pjsip_tsx_on_state_destroyed( pjsip_transaction *tsx, pjsip_event *event) +static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx, + pjsip_event *event) { - PJ_UNUSED_ARG(tsx) - PJ_UNUSED_ARG(event) + PJ_UNUSED_ARG(tsx); + PJ_UNUSED_ARG(event); return PJ_SUCCESS; } diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 65b8ec45..09eb6cfb 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -1,17 +1,18 @@ /* $Id$ - * */ #include #include #include #include #include +#include #include #include #include #include #include #include +#include #define MGR_IDLE_CHECK_INTERVAL 30 #define MGR_HASH_TABLE_SIZE PJSIP_MAX_DIALOG_COUNT @@ -44,7 +45,7 @@ struct pjsip_transport_t /** Standard list members, for chaining the transport in the * listener list. */ - PJ_DECL_LIST_MEMBER(struct pjsip_transport_t) + PJ_DECL_LIST_MEMBER(struct pjsip_transport_t); /** Transport's pool. */ pj_pool_t *pool; @@ -66,10 +67,13 @@ struct pjsip_transport_t /** I/O Queue key */ pj_ioqueue_key_t *key; - + + /** Accept key. */ + pj_ioqueue_op_key_t accept_op; + /** Receive data buffer */ pjsip_rx_data *rdata; - + /** Pointer to transport manager */ pjsip_transport_mgr *mgr; @@ -114,7 +118,9 @@ struct pjsip_transport_mgr pj_mutex_t *mutex; pjsip_endpoint *endpt; pj_ioqueue_t *ioqueue; - pj_time_val next_idle_check; + pj_time_val next_idle_check; + pj_size_t send_buf_size; + pj_size_t recv_buf_size; void (*message_callback)(pjsip_endpoint*, pjsip_rx_data *rdata); }; @@ -144,7 +150,7 @@ typedef struct transport_key */ struct transport_callback { - PJ_DECL_LIST_MEMBER(struct transport_callback) + PJ_DECL_LIST_MEMBER(struct transport_callback); /** User defined token to be passed to the callback. */ void *token; @@ -173,10 +179,18 @@ const struct #endif }; -static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read); -static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent); -static void on_ioqueue_accept(pj_ioqueue_key_t *key, int status); -static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status); +static void on_ioqueue_read(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_read); +static void on_ioqueue_write(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_sent); +static void on_ioqueue_accept(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_sock_t newsock, + int status); +static void on_ioqueue_connect(pj_ioqueue_key_t *key, + int status); static pj_ioqueue_callback ioqueue_transport_callback = { @@ -194,11 +208,11 @@ static void init_key_from_transport(transport_key *key, key->type = (pj_uint8_t)tr->type; key->zero = 0; - key->addr = pj_sockaddr_get_addr(&tr->remote_addr); - key->port = pj_sockaddr_get_port(&tr->remote_addr); + key->addr = pj_sockaddr_in_get_addr(&tr->remote_addr).s_addr; + key->port = pj_sockaddr_in_get_port(&tr->remote_addr); /* if (key->port == 0) { - key->port = pj_sockaddr_get_port(&tr->local_addr); + key->port = pj_sockaddr_in_get_port(&tr->local_addr); } */ } @@ -212,15 +226,15 @@ static void init_tcp_key(transport_key *key, pjsip_transport_type_e type, key->type = (pj_uint8_t)type; key->zero = 0; - key->addr = pj_sockaddr_get_addr(addr); - key->port = pj_sockaddr_get_port(addr); + key->addr = pj_sockaddr_in_get_addr(addr).s_addr; + key->port = pj_sockaddr_in_get_port(addr); } #endif static void init_udp_key(transport_key *key, pjsip_transport_type_e type, const pj_sockaddr_in *addr) { - PJ_UNUSED_ARG(addr) + PJ_UNUSED_ARG(addr); /* This is to detect alignment problems. */ pj_assert(sizeof(transport_key) == 8); @@ -236,7 +250,7 @@ static void init_udp_key(transport_key *key, pjsip_transport_type_e type, pj_str_t localaddr = pj_str("127.0.0.1"); pj_sockaddr_in addr; pj_sockaddr_set_str_addr(&addr, &localaddr); - key->addr = pj_sockaddr_get_addr(&addr); + key->addr = pj_sockaddr_in_get_addr(&addr); } #endif } @@ -297,31 +311,36 @@ pjsip_transport_get_type_from_name(const pj_str_t *name) /* * Create new transmit buffer. */ -pjsip_tx_data* pjsip_tx_data_create( pjsip_transport_mgr *mgr ) +pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr, + pjsip_tx_data **p_tdata ) { pj_pool_t *pool; pjsip_tx_data *tdata; + pj_status_t status; PJ_LOG(5, ("", "pjsip_tx_data_create")); + + PJ_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL); pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p", PJSIP_POOL_LEN_TDATA, PJSIP_POOL_INC_TDATA ); if (!pool) { - return NULL; + return PJ_ENOMEM; } tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data)); tdata->pool = pool; tdata->mgr = mgr; - sprintf(tdata->obj_name,"txd%p", tdata); + pj_sprintf(tdata->obj_name,"txd%p", tdata); - tdata->ref_cnt = pj_atomic_create(tdata->pool, 0); - if (!tdata->ref_cnt) { + status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt); + if (status != PJ_SUCCESS) { pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool ); - return NULL; + return status; } - - return tdata; + + *p_tdata = tdata; + return PJ_SUCCESS; } /* @@ -339,7 +358,7 @@ PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata ) PJ_DEF(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata ) { pj_assert( pj_atomic_get(tdata->ref_cnt) > 0); - if (pj_atomic_dec(tdata->ref_cnt) <= 0) { + if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) { PJ_LOG(6,(tdata->obj_name, "destroying txdata")); pj_atomic_destroy( tdata->ref_cnt ); pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool ); @@ -375,7 +394,7 @@ PJ_DEF(pjsip_transport_type_e) pjsip_get_transport_type_from_flag(unsigned flag) return PJSIP_TRANSPORT_TCP; } else #else - PJ_UNUSED_ARG(flag) + PJ_UNUSED_ARG(flag); #endif { return PJSIP_TRANSPORT_UDP; @@ -452,7 +471,7 @@ PJ_DEF(void) pjsip_transport_add_ref( pjsip_transport_t * tr ) PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr ) { pj_assert(tr->ref_cnt > 0); - if (pj_atomic_dec(tr->ref_cnt) == 0) { + if (pj_atomic_dec_and_get(tr->ref_cnt) == 0) { pj_gettimeofday(&tr->close_time); tr->close_time.sec += PJSIP_TRANSPORT_CLOSE_TIMEOUT; } @@ -461,13 +480,15 @@ PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr ) /* * Open the underlying transport. */ -static pj_sock_t create_socket( pjsip_transport_type_e type, - pj_sockaddr_in *local ) +static pj_status_t create_socket( pjsip_transport_type_e type, + pj_sockaddr_in *local, + pj_sock_t *p_sock) { int sock_family; int sock_type; int sock_proto; - int len; + int len; + pj_status_t status; pj_sock_t sock; /* Set socket parameters */ @@ -483,30 +504,23 @@ static pj_sock_t create_socket( pjsip_transport_type_e type, sock_proto = 0; #endif } else { - PJ_LOG(2,("", "create_socket: unsupported transport type %s", - get_type_name(type))); - return PJ_INVALID_SOCKET; + return PJ_EINVAL; } /* Create socket. */ - sock = pj_sock_socket( sock_family, sock_type, sock_proto, PJ_SOCK_ASYNC); - if (sock == PJ_INVALID_SOCKET) { - PJ_PERROR((THIS_FILE, "%s socket()", get_type_name(type))); - return PJ_INVALID_SOCKET; - } + status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock); + if (status != PJ_SUCCESS) + return status; /* Bind the socket to the requested address, or if no address is * specified, let the operating system chooses the address. */ if (/*local->sin_addr.s_addr != 0 &&*/ local->sin_port != 0) { - /* Bind to the requested address. */ - if (pj_sock_bind(sock, local, sizeof(*local)) != 0) { - PJ_PERROR((THIS_FILE, "bind() to %s %s:%d", - get_type_name(type), - pj_sockaddr_get_str_addr(local), - pj_sockaddr_get_port(local))); + /* Bind to the requested address. */ + status = pj_sock_bind(sock, local, sizeof(*local)); + if (status != PJ_SUCCESS) { pj_sock_close(sock); - return PJ_INVALID_SOCKET; + return status; } } else if (type == PJSIP_TRANSPORT_UDP) { /* Only for UDP sockets: bind to any address so that the operating @@ -515,23 +529,24 @@ static pj_sock_t create_socket( pjsip_transport_type_e type, * get 0.0.0.0 as local address). */ pj_memset(local, 0, sizeof(*local)); - local->sin_family = PJ_AF_INET; - if (pj_sock_bind(sock, local, sizeof(*local)) != 0) { - PJ_PERROR((THIS_FILE, "bind() to %s 0.0.0.0:0", get_type_name(type))); + local->sin_family = PJ_AF_INET; + status = pj_sock_bind(sock, local, sizeof(*local)); + if (status != PJ_SUCCESS) { pj_sock_close(sock); - return PJ_INVALID_SOCKET; + return status; } /* Get the local address. */ - len = sizeof(pj_sockaddr_in); - if (pj_sock_getsockname(sock, local, &len)) { - PJ_PERROR((THIS_FILE, "getsockname()")); + len = sizeof(pj_sockaddr_in); + status = pj_sock_getsockname(sock, local, &len); + if (status != PJ_SUCCESS) { pj_sock_close(sock); - return -1; + return status; } } - - return sock; + + *p_sock = sock; + return PJ_SUCCESS; } /* @@ -547,21 +562,24 @@ static void destroy_socket( pjsip_transport_t * tr) /* * Create a new transport object. */ -static pjsip_transport_t* create_transport( pjsip_transport_mgr *mgr, - pjsip_transport_type_e type, - pj_sock_t sock_hnd, - const pj_sockaddr_in *local_addr, - const pj_sockaddr_in *addr_name) +static pj_status_t create_transport( pjsip_transport_mgr *mgr, + pjsip_transport_type_e type, + pj_sock_t sock_hnd, + const pj_sockaddr_in *local_addr, + const pj_sockaddr_in *addr_name, + pjsip_transport_t **p_transport ) { pj_pool_t *tr_pool=NULL, *rdata_pool=NULL; - pjsip_transport_t *tr = NULL; + pjsip_transport_t *tr = NULL; + pj_status_t status; /* Allocate pool for transport from endpoint. */ tr_pool = pjsip_endpt_create_pool( mgr->endpt, transport_get_name_format(type), PJSIP_POOL_LEN_TRANSPORT, PJSIP_POOL_INC_TRANSPORT ); - if (!tr_pool) { + if (!tr_pool) { + status = PJ_ENOMEM; goto on_error; } @@ -570,7 +588,8 @@ static pjsip_transport_t* create_transport( pjsip_transport_mgr *mgr, "prdt%p", PJSIP_POOL_LEN_RDATA, PJSIP_POOL_INC_RDATA ); - if (!rdata_pool) { + if (!rdata_pool) { + status = PJ_ENOMEM; goto on_error; } @@ -582,7 +601,7 @@ static pjsip_transport_t* create_transport( pjsip_transport_mgr *mgr, tr->sock = sock_hnd; pj_memcpy(&tr->local_addr, local_addr, sizeof(pj_sockaddr_in)); pj_list_init(&tr->cb_list); - sprintf(tr->obj_name, transport_get_name_format(type), tr); + pj_sprintf(tr->obj_name, transport_get_name_format(type), tr); if (type != PJSIP_TRANSPORT_UDP) { tr->flag |= PJSIP_TRANSPORT_RELIABLE; @@ -594,11 +613,10 @@ static pjsip_transport_t* create_transport( pjsip_transport_mgr *mgr, } pj_memcpy(&tr->addr_name, addr_name, sizeof(*addr_name)); - /* Create atomic */ - tr->ref_cnt = pj_atomic_create(tr_pool, 0); - if (!tr->ref_cnt) { + /* Create atomic */ + status = pj_atomic_create(tr_pool, 0, &tr->ref_cnt); + if (status != PJ_SUCCESS) goto on_error; - } /* Init rdata in the transport. */ tr->rdata = pj_pool_alloc(rdata_pool, sizeof(*tr->rdata)); @@ -607,22 +625,20 @@ static pjsip_transport_t* create_transport( pjsip_transport_mgr *mgr, tr->rdata->transport = tr; /* Init transport mutex. */ - tr->tr_mutex = pj_mutex_create(tr_pool, "mtr%p", 0); - if (!tr->tr_mutex) { - PJ_PERROR((tr->obj_name, "pj_mutex_create()")); + status = pj_mutex_create_recursive(tr_pool, "mtr%p", &tr->tr_mutex); + if (status != PJ_SUCCESS) goto on_error; - } /* Register to I/O Queue */ - tr->key = pj_ioqueue_register(tr_pool, mgr->ioqueue, - (pj_oshandle_t)tr->sock, tr, - &ioqueue_transport_callback); - if (tr->key == NULL) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_register()")); + status = pj_ioqueue_register_sock( tr_pool, mgr->ioqueue, + tr->sock, tr, + &ioqueue_transport_callback, + &tr->key); + if (status != PJ_SUCCESS) goto on_error; - } - - return tr; + + *p_transport = tr; + return PJ_SUCCESS; on_error: if (tr && tr->tr_mutex) { @@ -634,18 +650,18 @@ on_error: if (rdata_pool) { pjsip_endpt_destroy_pool(mgr->endpt, rdata_pool); } - return NULL; + return status; } /* * Destroy transport. */ -static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr ) +static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr) { transport_key hash_key; /* Remove from I/O queue. */ - pj_ioqueue_unregister( mgr->ioqueue, tr->key ); + pj_ioqueue_unregister( tr->key ); /* Remove from hash table */ init_key_from_transport(&hash_key, tr); @@ -668,12 +684,18 @@ static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr ) } -static int transport_send_msg( pjsip_transport_t *tr, pjsip_tx_data *tdata, - const pj_sockaddr_in *addr) +static pj_status_t transport_send_msg( pjsip_transport_t *tr, + pjsip_tx_data *tdata, + const pj_sockaddr_in *addr, + pj_ssize_t *p_sent) { const char *buf = tdata->buf.start; - int sent; - int len; + pj_ssize_t size; + pj_status_t status; + + /* Can only send if tdata is not being sent! */ + if (pj_ioqueue_is_pending(tr->key, &tdata->op_key)) + return PJSIP_EPENDINGTX; /* Allocate buffer if necessary. */ if (tdata->buf.start == NULL) { @@ -684,34 +706,31 @@ static int transport_send_msg( pjsip_transport_t *tr, pjsip_tx_data *tdata, /* Print the message if it's not printed */ if (tdata->buf.cur <= tdata->buf.start) { - len = pjsip_msg_print(tdata->msg, tdata->buf.start, - tdata->buf.end - tdata->buf.start); - if (len < 1) { - return len; - } - tdata->buf.cur += len; - tdata->buf.cur[len] = '\0'; + size = pjsip_msg_print( tdata->msg, tdata->buf.start, + tdata->buf.end - tdata->buf.start); + if (size < 0) { + return PJSIP_EMSGTOOLONG; + } + pj_assert(size != 0); + tdata->buf.cur += size; + tdata->buf.cur[size] = '\0'; } - /* BUG BUG BUG */ - /* MUST CHECK THAT THE SOCKET IS READY TO SEND (IOQueue)! */ - PJ_TODO(BUG_BUG_BUG___SENDING_DATAGRAM_WHILE_SOCKET_IS_PENDING__) - /* Send the message. */ buf = tdata->buf.start; - len = tdata->buf.cur - tdata->buf.start; + size = tdata->buf.cur - tdata->buf.start; if (tr->type == PJSIP_TRANSPORT_UDP) { PJ_LOG(4,(tr->obj_name, "sendto %s:%d, %d bytes, data:\n" "----------- begin msg ------------\n" "%s" "------------ end msg -------------", - pj_sockaddr_get_str_addr(addr), - pj_sockaddr_get_port(addr), - len, buf)); - - sent = pj_ioqueue_sendto( tr->mgr->ioqueue, tr->key, - buf, len, addr, sizeof(*addr)); + pj_inet_ntoa(addr->sin_addr), + pj_sockaddr_in_get_port(addr), + size, buf)); + + status = pj_ioqueue_sendto( tr->key, &tdata->op_key, + buf, &size, 0, addr, sizeof(*addr)); } #if PJ_HAS_TCP else { @@ -719,40 +738,33 @@ static int transport_send_msg( pjsip_transport_t *tr, pjsip_tx_data *tdata, "----------- begin msg ------------\n" "%s" "------------ end msg -------------", - len, buf)); + size, buf)); - sent = pj_ioqueue_write (tr->mgr->ioqueue, tr->key, buf, len); + status = pj_ioqueue_send(tr->key, &tdata->op_key, buf, &size, 0); } #else else { - pj_assert(0); - sent = -1; + pj_assert(!"Unsupported transport"); + status = PJSIP_EUNSUPTRANSPORT; } #endif - - if (sent == len || sent == PJ_IOQUEUE_PENDING) { - return len; - } - - /* On error, clear the flag. */ - PJ_PERROR((tr->obj_name, tr->type == PJSIP_TRANSPORT_UDP ? "pj_ioqueue_sendto()" : "pj_ioqueue_write()")); - return -1; + + *p_sent = size; + return status; } /* * Send a SIP message using the specified transport, to the address specified * in the outgoing data. */ -PJ_DEF(int) pjsip_transport_send_msg( pjsip_transport_t *tr, - pjsip_tx_data *tdata, - const pj_sockaddr_in *addr) +PJ_DEF(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr, + pjsip_tx_data *tdata, + const pj_sockaddr_in *addr, + pj_ssize_t *sent) { - int sent; - PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name)); - sent = transport_send_msg(tr, tdata, addr ); - return sent; + return transport_send_msg(tr, tdata, addr, sent ); } /////////////////////////////////////////////////////////////////////////////// @@ -760,44 +772,47 @@ PJ_DEF(int) pjsip_transport_send_msg( pjsip_transport_t *tr, /* * Create a new transport manager. */ -PJ_DEF(pjsip_transport_mgr*) -pjsip_transport_mgr_create( pj_pool_t *pool, - pjsip_endpoint * endpt, - void (*cb)(pjsip_endpoint*,pjsip_rx_data *) ) +PJ_DEF(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool, + pjsip_endpoint * endpt, + void (*cb)(pjsip_endpoint*, + pjsip_rx_data *), + pjsip_transport_mgr **p_mgr) { pjsip_transport_mgr *mgr; + pj_status_t status; PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_create()")); mgr = pj_pool_alloc(pool, sizeof(*mgr)); mgr->endpt = endpt; mgr->message_callback = cb; - + mgr->send_buf_size = DEFAULT_SO_SNDBUF; + mgr->recv_buf_size = DEFAULT_SO_RCVBUF; + mgr->transport_table = pj_hash_create(pool, MGR_HASH_TABLE_SIZE); if (!mgr->transport_table) { - PJ_LOG(3, (LOG_TRANSPORT_MGR, "error creating transport manager hash table")); - return NULL; + return PJ_ENOMEM; } - mgr->ioqueue = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS); - if (!mgr->ioqueue) { - PJ_LOG(3, (LOG_TRANSPORT_MGR, "error creating IO queue")); - return NULL; + status = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS, &mgr->ioqueue); + if (status != PJ_SUCCESS) { + return status; } - mgr->mutex = pj_mutex_create(pool, "tmgr%p", 0); - if (!mgr->mutex) { - PJ_LOG(3, (LOG_TRANSPORT_MGR, "error creating mutex")); + status = pj_mutex_create_recursive(pool, "tmgr%p", &mgr->mutex); + if (status != PJ_SUCCESS) { pj_ioqueue_destroy(mgr->ioqueue); - return NULL; + return status; } pj_gettimeofday(&mgr->next_idle_check); - mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL; - return mgr; + mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL; + + *p_mgr = mgr; + return status; } /* * Destroy transport manager. */ -PJ_DEF(void) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ) +PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ) { pj_hash_iterator_t itr_val; pj_hash_iterator_t *itr; @@ -822,7 +837,9 @@ PJ_DEF(void) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ) } pj_ioqueue_destroy(mgr->ioqueue); - pj_mutex_unlock(mgr->mutex); + pj_mutex_unlock(mgr->mutex); + + return PJ_SUCCESS; } /* @@ -835,62 +852,81 @@ static pj_status_t create_listener( pjsip_transport_mgr *mgr, const pj_sockaddr_in *addr_name) { pjsip_transport_t *tr; - struct transport_key *hash_key; - int opt_val; - - opt_val = DEFAULT_SO_SNDBUF; - if (pj_sock_setsockopt( sock_hnd, SOL_SOCKET, SO_SNDBUF, &opt_val, sizeof(opt_val)) != PJ_SUCCESS) { - PJ_LOG(3, (LOG_TRANSPORT_MGR, "create listener: error setting SNDBUF to %d", DEFAULT_SO_SNDBUF)); - // Just ignore the error. + struct transport_key *hash_key; + const pj_str_t loopback_addr = { "127.0.0.1", 9 }; + pj_status_t status; + + if (mgr->send_buf_size != 0) { + int opt_val = mgr->send_buf_size; + status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET, + PJ_SO_SNDBUF, + &opt_val, sizeof(opt_val)); + + if (status != PJ_SUCCESS) { + return status; + } } - - opt_val = DEFAULT_SO_RCVBUF; - if (pj_sock_setsockopt( sock_hnd, SOL_SOCKET, SO_RCVBUF, &opt_val, sizeof(opt_val)) != PJ_SUCCESS) { - PJ_LOG(3, (LOG_TRANSPORT_MGR, "create listener: error setting RCVBUF to %d", DEFAULT_SO_SNDBUF)); - // Just ignore the error + + if (mgr->recv_buf_size != 0) { + int opt_val = mgr->recv_buf_size; + status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET, + PJ_SO_RCVBUF, + &opt_val, sizeof(opt_val)); + if (status != PJ_SUCCESS) { + return status; + } } - tr = create_transport(mgr, type, sock_hnd, local_addr, addr_name); - if (!tr) { + status = create_transport(mgr, type, sock_hnd, local_addr, addr_name, &tr); + if (status != PJ_SUCCESS) { pj_sock_close(sock_hnd); - return -1; + return status; } #if PJ_HAS_TCP if (type == PJSIP_TRANSPORT_TCP) { - pj_status_t status; - - if (pj_sock_listen(tr->sock, BACKLOG) != 0) { - PJ_PERROR((tr->obj_name, "listen()")); - destroy_transport(mgr, tr); - return -1; - } - tr->accept_data.addrlen = sizeof(tr->accept_data.local); - status = pj_ioqueue_accept(mgr->ioqueue, tr->key, - &tr->accept_data.sock, - &tr->accept_data.local, - &tr->accept_data.remote, - &tr->accept_data.addrlen); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_accept()")); + + status = pj_sock_listen(tr->sock, BACKLOG); + if (status != 0) { destroy_transport(mgr, tr); - return -1; + return status; } + + /* Discard immediate connections. */ + do { + tr->accept_data.addrlen = sizeof(tr->accept_data.local); + status = pj_ioqueue_accept(tr->key, &tr->accept_op, + &tr->accept_data.sock, + &tr->accept_data.local, + &tr->accept_data.remote, + &tr->accept_data.addrlen); + if (status==PJ_SUCCESS) { + pj_sock_close(tr->accept_data.sock); + } else if (status != PJ_EPENDING) { + destroy_transport(mgr, tr); + return status; + } + } while (status==PJ_SUCCESS); } else #endif - if (type == PJSIP_TRANSPORT_UDP) { - pj_status_t status; - - tr->rdata->addr_len = sizeof(tr->rdata->addr); - status = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key, - tr->rdata->packet, PJSIP_MAX_PKT_LEN, - &tr->rdata->addr, - &tr->rdata->addr_len); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_recvfrom()")); - destroy_transport(mgr, tr); - return -1; - } + if (type == PJSIP_TRANSPORT_UDP) { + pj_ssize_t bytes; + + /* Discard immediate data. */ + do { + tr->rdata->addr_len = sizeof(tr->rdata->addr); + bytes = PJSIP_MAX_PKT_LEN; + status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key, + tr->rdata->packet, &bytes, 0, + &tr->rdata->addr, + &tr->rdata->addr_len); + if (status == PJ_SUCCESS) { + ; + } else if (status != PJ_EPENDING) { + destroy_transport(mgr, tr); + return status; + } + } while (status == PJ_SUCCESS); } pj_atomic_set(tr->ref_cnt, 1); @@ -900,26 +936,29 @@ static pj_status_t create_listener( pjsip_transport_mgr *mgr, /* Set remote address to 127.0.0.1 for UDP socket bound to 127.0.0.1. * See further comments on struct pjsip_transport_t definition. - */ - if (type == PJSIP_TRANSPORT_UDP && local_addr->sin_addr.s_addr == inet_addr("127.0.0.1")) { + */ + if (type == PJSIP_TRANSPORT_UDP && + local_addr->sin_addr.s_addr == pj_inet_addr(&loopback_addr).s_addr) + { pj_str_t localaddr = pj_str("127.0.0.1"); - pj_sockaddr_set_str_addr( &tr->remote_addr, &localaddr); + pj_sockaddr_in_set_str_addr( &tr->remote_addr, &localaddr); } hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); init_key_from_transport(hash_key, tr); pj_mutex_lock(mgr->mutex); - pj_hash_set(tr->pool, mgr->transport_table, hash_key, sizeof(transport_key), tr); + pj_hash_set(tr->pool, mgr->transport_table, + hash_key, sizeof(transport_key), tr); pj_mutex_unlock(mgr->mutex); PJ_LOG(4,(tr->obj_name, "Listening at %s %s:%d", get_type_name(tr->type), - pj_sockaddr_get_str_addr(&tr->local_addr), - pj_sockaddr_get_port(&tr->local_addr))); + pj_inet_ntoa(tr->local_addr.sin_addr), + pj_sockaddr_in_get_port(&tr->local_addr))); PJ_LOG(4,(tr->obj_name, "Listener public address is at %s %s:%d", get_type_name(tr->type), - pj_sockaddr_get_str_addr(&tr->addr_name), - pj_sockaddr_get_port(&tr->addr_name))); + pj_inet_ntoa(tr->addr_name.sin_addr), + pj_sockaddr_in_get_port(&tr->addr_name))); return PJ_SUCCESS; } @@ -932,12 +971,13 @@ PJ_DEF(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr, const pj_sockaddr_in *addr_name) { pj_sock_t sock_hnd; + pj_status_t status; PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type)); - sock_hnd = create_socket(type, local_addr); - if (sock_hnd == PJ_INVALID_SOCKET) { - return -1; + status = create_socket(type, local_addr, &sock_hnd); + if (status != PJ_SUCCESS) { + return status; } return create_listener(mgr, type, sock_hnd, local_addr, addr_name); @@ -950,13 +990,16 @@ PJ_DEF(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr, pj_sock_t sock, const pj_sockaddr_in *addr_name) { - pj_sockaddr_in local_addr; + pj_sockaddr_in local_addr; + pj_status_t status; int addrlen = sizeof(local_addr); + + status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen); + if (status != PJ_SUCCESS) + return status; - if (pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen) != 0) - return -1; - - return create_listener(mgr, PJSIP_TRANSPORT_UDP, sock, &local_addr, addr_name); + return create_listener(mgr, PJSIP_TRANSPORT_UDP, sock, + &local_addr, addr_name); } /* @@ -973,7 +1016,7 @@ PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr, transport_key search_key, *hash_key; pjsip_transport_t *tr; pj_sockaddr_in local; - int sock_hnd; + pj_sock_t sock_hnd; pj_status_t status; struct transport_callback *cb_rec; @@ -1029,49 +1072,50 @@ PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr, /* Transport not found. Create new one. */ pj_memset(&local, 0, sizeof(local)); local.sin_family = PJ_AF_INET; - sock_hnd = create_socket(type, &local); - if (sock_hnd == PJ_INVALID_SOCKET) { + status = create_socket(type, &local, &sock_hnd); + if (status != PJ_SUCCESS) { pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, -1); + (*cb_rec->cb)(NULL, cb_rec->token, status); return; } - tr = create_transport(mgr, type, sock_hnd, &local, NULL); - if (!tr) { + status = create_transport(mgr, type, sock_hnd, &local, NULL, &tr); + if (status != PJ_SUCCESS) { pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, -1); + (*cb_rec->cb)(NULL, cb_rec->token, status); return; } #if PJ_HAS_TCP if (type == PJSIP_TRANSPORT_TCP) { pj_memcpy(&tr->remote_addr, remote, sizeof(pj_sockaddr_in)); - status = pj_ioqueue_connect(mgr->ioqueue, tr->key, - &tr->remote_addr, sizeof(pj_sockaddr_in)); + status = pj_ioqueue_connect(tr->key, &tr->remote_addr, + sizeof(pj_sockaddr_in)); pj_assert(status != 0); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_connect()")); + if (status != PJ_EPENDING) { + PJ_TODO(HANDLE_IMMEDIATE_CONNECT); destroy_transport(mgr, tr); pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, -1); + (*cb_rec->cb)(NULL, cb_rec->token, status); return; } } else #endif if (type == PJSIP_TRANSPORT_UDP) { - int len; + pj_ssize_t size; do { - tr->rdata->addr_len = sizeof(tr->rdata->addr); - len = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key, - tr->rdata->packet, PJSIP_MAX_PKT_LEN, - &tr->rdata->addr, - &tr->rdata->addr_len); - pj_assert(len < 0); - if (len != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_recvfrom()")); + tr->rdata->addr_len = sizeof(tr->rdata->addr); + size = PJSIP_MAX_PKT_LEN; + status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key, + tr->rdata->packet, &size, 0, + &tr->rdata->addr, + &tr->rdata->addr_len); + if (status == PJ_SUCCESS) + ; + else if (status != PJ_EPENDING) { destroy_transport(mgr, tr); pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, -1); + (*cb_rec->cb)(NULL, cb_rec->token, status); return; } @@ -1082,7 +1126,7 @@ PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr, */ PJ_TODO(FIXED_BUG_ON_IMMEDIATE_TRANSPORT_DATA); - } while (len != PJ_IOQUEUE_PENDING); + } while (status == PJ_SUCCESS); //Bug: cb will never be called! // Must force status to PJ_SUCCESS; @@ -1092,15 +1136,16 @@ PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr, } else { pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, -1); + (*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT); return; } - pj_assert(status==PJ_IOQUEUE_PENDING || status==PJ_SUCCESS); + pj_assert(status==PJ_EPENDING || status==PJ_SUCCESS); pj_mutex_lock(tr->tr_mutex); hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); pj_memcpy(hash_key, &search_key, sizeof(transport_key)); - pj_hash_set(tr->pool, mgr->transport_table, hash_key, sizeof(transport_key), tr); + pj_hash_set(tr->pool, mgr->transport_table, + hash_key, sizeof(transport_key), tr); if (status == PJ_SUCCESS) { pj_mutex_unlock(tr->tr_mutex); pj_mutex_unlock(mgr->mutex); @@ -1123,24 +1168,28 @@ static void handle_new_connection( pjsip_transport_mgr *mgr, pj_status_t status ) { pjsip_transport_t *tr; - transport_key *hash_key; + transport_key *hash_key; + pj_ssize_t size; pj_assert (listener->type == PJSIP_TRANSPORT_TCP); if (status != PJ_SUCCESS) { - PJ_PERROR((listener->obj_name, "accept() returned error")); - return; + PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status, + "Error in accept() completion")); + goto on_return; } PJ_LOG(4,(listener->obj_name, "incoming tcp connection from %s:%d", - pj_sockaddr_get_str_addr(&listener->accept_data.remote), - pj_sockaddr_get_port(&listener->accept_data.remote))); - - tr = create_transport(mgr, listener->type, - listener->accept_data.sock, - &listener->accept_data.local, - NULL); - if (!tr) { + pj_inet_ntoa(listener->accept_data.remote.sin_addr), + pj_sockaddr_in_get_port(&listener->accept_data.remote))); + + status = create_transport(mgr, listener->type, + listener->accept_data.sock, + &listener->accept_data.local, + NULL, &tr); + if (status != PJ_SUCCESS) { + PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status, + "Error in creating new incoming TCP")); goto on_return; } @@ -1153,32 +1202,40 @@ static void handle_new_connection( pjsip_transport_mgr *mgr, */ tr->rdata->addr = listener->accept_data.remote; tr->rdata->addr_len = listener->accept_data.addrlen; - - status = pj_ioqueue_read (mgr->ioqueue, tr->key, tr->rdata->packet, PJSIP_MAX_PKT_LEN); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_read()")); + + size = PJSIP_MAX_PKT_LEN; + status = pj_ioqueue_recv(tr->key, &tr->rdata->op_key, + tr->rdata->packet, &size, 0); + if (status != PJ_EPENDING) { + PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status, + "Error in receiving data")); + PJ_TODO(IMMEDIATE_DATA); destroy_transport(mgr, tr); goto on_return; } - pj_memcpy(&tr->remote_addr, &listener->accept_data.remote, listener->accept_data.addrlen); + pj_memcpy(&tr->remote_addr, &listener->accept_data.remote, + listener->accept_data.addrlen); hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); init_key_from_transport(hash_key, tr); pj_mutex_lock(mgr->mutex); - pj_hash_set(tr->pool, mgr->transport_table, hash_key, sizeof(transport_key), tr); + pj_hash_set(tr->pool, mgr->transport_table, hash_key, + sizeof(transport_key), tr); pj_mutex_unlock(mgr->mutex); on_return: /* Re-initiate asynchronous accept() */ listener->accept_data.addrlen = sizeof(listener->accept_data.local); - status = pj_ioqueue_accept(mgr->ioqueue, listener->key, + status = pj_ioqueue_accept(listener->key, &listener->accept_op, &listener->accept_data.sock, &listener->accept_data.local, &listener->accept_data.remote, &listener->accept_data.addrlen); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((listener->obj_name, "pj_ioqueue_accept()")); + if (status != PJ_EPENDING) { + PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status, + "Error in receiving data")); + PJ_TODO(IMMEDIATE_ACCEPT); return; } } @@ -1193,8 +1250,9 @@ static void handle_connect_completion( pjsip_transport_mgr *mgr, { struct transport_callback new_list; struct transport_callback *cb_rec; + pj_ssize_t recv_size; - PJ_UNUSED_ARG(mgr) + PJ_UNUSED_ARG(mgr); /* On connect completion, we must call all registered callbacks in * the transport. @@ -1221,11 +1279,12 @@ static void handle_connect_completion( pjsip_transport_mgr *mgr, */ if (status == PJ_SUCCESS) { int addrlen = sizeof(tr->local_addr); - int rc; - if ((rc=pj_sock_getsockname(tr->sock, (pj_sockaddr_t*)&tr->local_addr, &addrlen)) == 0) { + + status = pj_sock_getsockname(tr->sock, + (pj_sockaddr_t*)&tr->local_addr, + &addrlen); + if (status == PJ_SUCCESS) { pj_memcpy(&tr->addr_name, &tr->local_addr, sizeof(tr->addr_name)); - } else { - PJ_LOG(4,(tr->obj_name, "Unable to get local address (getsockname=%d)", rc)); } } @@ -1243,15 +1302,18 @@ static void handle_connect_completion( pjsip_transport_mgr *mgr, /* Success? */ if (status != PJ_SUCCESS) { - destroy_transport(mgr, tr); + destroy_transport(mgr, tr); + PJ_TODO(WTF); return; } - /* Initiate read operation to socket. */ - status = pj_ioqueue_read (mgr->ioqueue, tr->key, tr->rdata->packet, PJSIP_MAX_PKT_LEN); - if (status != PJ_IOQUEUE_PENDING) { - PJ_PERROR((tr->obj_name, "pj_ioqueue_read()")); - destroy_transport(mgr, tr); + /* Initiate read operation to socket. */ + recv_size = PJSIP_MAX_PKT_LEN; + status = pj_ioqueue_recv( tr->key, &tr->rdata->op_key, tr->rdata->packet, + &recv_size, 0); + if (status != PJ_EPENDING) { + destroy_transport(mgr, tr); + PJ_TODO(IMMEDIATE_DATA); return; } } @@ -1269,7 +1331,6 @@ static void handle_received_data( pjsip_transport_mgr *mgr, pj_ssize_t size ) { pjsip_msg *msg; - pjsip_cid_hdr *call_id; pjsip_rx_data *rdata = tr->rdata; pj_pool_t *rdata_pool; pjsip_hdr *hdr; @@ -1315,8 +1376,8 @@ static void handle_received_data( pjsip_transport_mgr *mgr, rdata->packet[rdata->len] = '\0'; /* Get source address and port for logging purpose. */ - src_addr = pj_sockaddr_get_str_addr(&rdata->addr); - src_port = pj_sockaddr_get_port(&rdata->addr); + src_addr = pj_inet_ntoa(rdata->addr.sin_addr); + src_port = pj_sockaddr_in_get_port(&rdata->addr); /* Print the whole data to the log. */ PJ_LOG(4,(tr->obj_name, "%d bytes recvfrom %s:%d:\n" @@ -1333,15 +1394,15 @@ static void handle_received_data( pjsip_transport_mgr *mgr, #if PJ_HAS_TCP /* For TCP transport, check if the whole message has been received. */ if (tr->type != PJSIP_TRANSPORT_UDP) { - pj_bool_t is_complete; - is_complete = pjsip_find_msg(rdata->packet, rdata->len, PJ_FALSE, &msg_fragment_size); - if (!is_complete) { - if (rdata->len == PJSIP_MAX_PKT_LEN) { - PJ_LOG(1,(tr->obj_name, - "Transport buffer full (%d bytes) for TCP socket %s:%d " - "(probably too many invalid fragments received). " - "Buffer will be discarded.", - PJSIP_MAX_PKT_LEN, src_addr, src_port)); + pj_status_t msg_status; + msg_status = pjsip_find_msg(rdata->packet, rdata->len, PJ_FALSE, + &msg_fragment_size); + if (msg_status != PJ_SUCCESS) { + if (rdata->len == PJSIP_MAX_PKT_LEN) { + PJSIP_ENDPT_LOG_ERROR((mgr->endpt, tr->obj_name, + PJSIP_EOVERFLOW, + "Buffer discarded for %s:%d", + src_addr, src_port)); goto on_return; } else { goto tcp_read_packet; @@ -1357,36 +1418,21 @@ static void handle_received_data( pjsip_transport_mgr *mgr, PJ_LOG(5,(tr->obj_name, "Parsing %d bytes from %s:%d", msg_fragment_size, src_addr, src_port)); - msg = pjsip_parse_msg( rdata->pool, rdata->packet, msg_fragment_size, - &rdata->parse_err); + msg = pjsip_parse_rdata( rdata->packet, msg_fragment_size, rdata); if (msg == NULL) { PJ_LOG(3,(tr->obj_name, "Bad message (%d bytes from %s:%d)", msg_fragment_size, src_addr, src_port)); goto finish_process_fragment; } - - /* Attach newly created message to rdata. */ - rdata->msg = msg; - - /* Extract Call-ID, From and To header and tags, topmost Via, and CSeq - * header from the message. - */ - call_id = pjsip_msg_find_hdr( msg, PJSIP_H_CALL_ID, NULL); - rdata->from = pjsip_msg_find_hdr( msg, PJSIP_H_FROM, NULL); - rdata->to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL); - rdata->via = pjsip_msg_find_hdr( msg, PJSIP_H_VIA, NULL); - rdata->cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL); - - if (call_id == NULL || rdata->from == NULL || rdata->to == NULL || - rdata->via == NULL || rdata->cseq == NULL) + + /* Perform basic header checking. */ + if (rdata->call_id.ptr == NULL || rdata->from == NULL || + rdata->to == NULL || rdata->via == NULL || rdata->cseq == NULL) { PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header", src_addr, src_port)); goto finish_process_fragment; } - rdata->call_id = call_id->id; - rdata->from_tag = rdata->from->tag; - rdata->to_tag = rdata->to->tag; /* If message is received from address that's different from the sent-by, * MUST add received parameter to the via. @@ -1401,14 +1447,14 @@ static void handle_received_data( pjsip_transport_mgr *mgr, * If message contains "rport" param, put the received port there. */ if (rdata->via->rport_param == 0) { - rdata->via->rport_param = pj_sockaddr_get_port(&rdata->addr); + rdata->via->rport_param = pj_sockaddr_in_get_port(&rdata->addr); } /* Drop response message if it has more than one Via. */ if (msg->type == PJSIP_RESPONSE_MSG) { hdr = (pjsip_hdr*)rdata->via->next; - if (hdr) { + if (hdr != &rdata->msg->hdr) { hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr); if (hdr) { PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: " @@ -1444,10 +1490,12 @@ on_return: /* Read the next packet. */ rdata->addr_len = sizeof(rdata->addr); - if (tr->type == PJSIP_TRANSPORT_UDP) { - pj_ioqueue_recvfrom( tr->mgr->ioqueue, tr->key, - tr->rdata->packet, PJSIP_MAX_PKT_LEN, - &rdata->addr, &rdata->addr_len); + if (tr->type == PJSIP_TRANSPORT_UDP) { + pj_ssize_t size = PJSIP_MAX_PKT_LEN; + pj_ioqueue_recvfrom(tr->key, &tr->rdata->op_key, + tr->rdata->packet, &size, 0, + &rdata->addr, &rdata->addr_len); + PJ_TODO(HANDLE_IMMEDIATE_DATA); } #if PJ_HAS_TCP @@ -1455,10 +1503,12 @@ on_return: label inside the '#if PJ_HAS_TCP' block to avoid 'unreferenced label' warning. */ tcp_read_packet: - if (tr->type == PJSIP_TRANSPORT_TCP) { - pj_ioqueue_read( tr->mgr->ioqueue, tr->key, + if (tr->type == PJSIP_TRANSPORT_TCP) { + pj_ssize_t size = PJSIP_MAX_PKT_LEN - tr->rdata->len; + pj_ioqueue_recv( tr->key, &tr->rdata->op_key, tr->rdata->packet + tr->rdata->len, - PJSIP_MAX_PKT_LEN - tr->rdata->len); + &size, 0); + PJ_TODO(HANDLE_IMMEDIATE_DATA_1); } #endif } @@ -1507,7 +1557,9 @@ static void transport_mgr_on_idle( pjsip_transport_mgr *mgr ) pj_mutex_unlock(mgr->mutex); } -static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) +static void on_ioqueue_read(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_read) { pjsip_transport_t *t; t = pj_ioqueue_get_user_data(key); @@ -1515,17 +1567,22 @@ static void on_ioqueue_read(pj_ioqueue_key_t *key, pj_ssize_t bytes_read) handle_received_data( t->mgr, t, bytes_read ); } -static void on_ioqueue_write(pj_ioqueue_key_t *key, pj_ssize_t bytes_sent) +static void on_ioqueue_write(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_sent) { - PJ_UNUSED_ARG(key) - PJ_UNUSED_ARG(bytes_sent) + PJ_UNUSED_ARG(key); + PJ_UNUSED_ARG(bytes_sent); /* Completion of write operation. * Do nothing. */ } -static void on_ioqueue_accept(pj_ioqueue_key_t *key, int status) +static void on_ioqueue_accept(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_sock_t newsock, + int status) { #if PJ_HAS_TCP pjsip_transport_t *t; @@ -1533,8 +1590,8 @@ static void on_ioqueue_accept(pj_ioqueue_key_t *key, int status) handle_new_connection( t->mgr, t, status ); #else - PJ_UNUSED_ARG(key) - PJ_UNUSED_ARG(status) + PJ_UNUSED_ARG(key); + PJ_UNUSED_ARG(status); #endif } @@ -1546,8 +1603,8 @@ static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) handle_connect_completion( t->mgr, t, status); #else - PJ_UNUSED_ARG(key) - PJ_UNUSED_ARG(status) + PJ_UNUSED_ARG(key); + PJ_UNUSED_ARG(status); #endif } diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c index 516b78c9..8085f7fc 100644 --- a/pjsip/src/pjsip/sip_uri.c +++ b/pjsip/src/pjsip/sip_uri.c @@ -1,11 +1,11 @@ /* $Id$ - * */ #include #include -#include +#include #include #include +#include #define IS_SIPS(url) ((url)->vptr==&sips_url_vptr) @@ -68,13 +68,13 @@ static pjsip_uri_vptr name_addr_vptr = static const pj_str_t *pjsip_url_get_scheme(const pjsip_url *url) { - PJ_UNUSED_ARG(url) + PJ_UNUSED_ARG(url); return &sip_str; } static const pj_str_t *pjsips_url_get_scheme(const pjsip_url *url) { - PJ_UNUSED_ARG(url) + PJ_UNUSED_ARG(url); return &sips_str; } @@ -253,7 +253,7 @@ static int pjsip_url_compare( pjsip_uri_context_e context, return -1; } - if (strcmp(str_url1, str_url2)) { + if (pj_native_strcmp(str_url1, str_url2)) { /* Not equal */ return -1; } diff --git a/pjsip/src/pjsua/getopt.c b/pjsip/src/pjsua/getopt.c index caa8920f..5d4689cf 100644 --- a/pjsip/src/pjsua/getopt.c +++ b/pjsip/src/pjsua/getopt.c @@ -278,7 +278,7 @@ static char *posixly_correct; On some systems, it contains special magic macros that don't work in GCC. */ #include -#define my_index strchr +#define my_index pj_native_strchr #else static char * @@ -644,7 +644,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ - if (optind != argc && !strcmp (argv[optind], "--")) + if (optind != argc && !pj_native_strcmp(argv[optind], "--")) { optind++; diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c index c04d1a22..a8a0f49a 100644 --- a/pjsip/src/pjsua/main.c +++ b/pjsip/src/pjsua/main.c @@ -250,7 +250,7 @@ static void pres_on_received_request(pjsip_presentity *pres, pjsip_rx_data *rdat urllen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->from->uri, url, sizeof(url)-1); if (urllen < 1) { - strcpy(url, ""); + pj_native_strcpy(url, ""); } else { url[urllen] = '\0'; } @@ -1103,7 +1103,7 @@ static pj_status_t init_stack() } if (global.user_id[0]=='\0') { - strcpy(global.user_id, "user"); + pj_native_strcpy(global.user_id, "user"); } /* build contact */ @@ -1233,12 +1233,12 @@ static int on_incoming_im_msg(pjsip_rx_data *rdata) len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, rdata->from->uri, from, sizeof(from)); if (len > 0) from[len] = '\0'; - else strcpy(from, ""); + else pj_native_strcpy(from, ""); len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, rdata->to->uri, to, sizeof(to)); if (len > 0) to[len] = '\0'; - else strcpy(to, ""); + else pj_native_strcpy(to, ""); PJ_LOG(3,(THIS_FILE, "Incoming instant message:")); diff --git a/pjsip/src/pjsua/misc.c b/pjsip/src/pjsua/misc.c index 36439ccc..58cc795f 100644 --- a/pjsip/src/pjsua/misc.c +++ b/pjsip/src/pjsua/misc.c @@ -341,7 +341,7 @@ static int parse_args(pj_pool_t *pool, int argc, char *argv[]) global.cred_info[0].data = pj_str(optarg); break; case OPT_USE_STUN1: /* STUN server 1 */ - p = strchr(optarg, ':'); + p = pj_native_strchr(optarg, ':'); if (p) { *p = '\0'; global.stun_srv1 = pj_str(optarg); @@ -356,7 +356,7 @@ static int parse_args(pj_pool_t *pool, int argc, char *argv[]) } break; case OPT_USE_STUN2: /* STUN server 2 */ - p = strchr(optarg, ':'); + p = pj_native_strchr(optarg, ':'); if (p) { *p = '\0'; global.stun_srv2 = pj_str(optarg); -- cgit v1.2.3