From 9f4da35e676737f830a90a18de08440cf0f6cdf9 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sun, 20 Nov 2005 19:58:10 +0000 Subject: More compliant URI parser, comparison, etc. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@64 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/build/pjsip.dsw | 30 +- pjsip/build/pjsip_core.dsp | 14 +- pjsip/build/test_pjsip.dsp | 12 +- pjsip/docs/PJSIP-Testing.doc | Bin 330240 -> 332288 bytes pjsip/include/pjsip/print_util.h | 41 +- pjsip/include/pjsip/sip_errno.h | 157 ++++++-- pjsip/include/pjsip/sip_event.h | 2 +- pjsip/include/pjsip/sip_misc.h | 192 --------- pjsip/include/pjsip/sip_parser.h | 28 +- pjsip/include/pjsip/sip_transaction.h | 17 + pjsip/include/pjsip/sip_uri.h | 67 +++- pjsip/include/pjsip/sip_util.h | 192 +++++++++ pjsip/include/pjsip_core.h | 5 +- pjsip/src/pjsip-simple/event_notify.c | 2 +- pjsip/src/pjsip-simple/messaging.c | 2 +- pjsip/src/pjsip-ua/sip_dialog.c | 2 +- pjsip/src/pjsip-ua/sip_reg.c | 2 +- pjsip/src/pjsip-ua/sip_ua.c | 2 +- pjsip/src/pjsip/sip_endpoint.c | 59 ++- pjsip/src/pjsip/sip_errno.c | 125 ++++++ pjsip/src/pjsip/sip_misc.c | 724 ---------------------------------- pjsip/src/pjsip/sip_parser.c | 82 +++- pjsip/src/pjsip/sip_transaction.c | 8 +- pjsip/src/pjsip/sip_transport.c | 2 +- pjsip/src/pjsip/sip_uri.c | 289 ++++++++++---- pjsip/src/pjsip/sip_util.c | 724 ++++++++++++++++++++++++++++++++++ pjsip/src/test-pjsip/main.c | 6 + pjsip/src/test-pjsip/msg.c | 369 +++++++++++++++++ pjsip/src/test-pjsip/parse_msg.c | 440 --------------------- pjsip/src/test-pjsip/parse_uri.c | 660 ------------------------------- pjsip/src/test-pjsip/test.c | 47 ++- pjsip/src/test-pjsip/test.h | 9 +- pjsip/src/test-pjsip/uri.c | 560 ++++++++++++++++++++++++++ 33 files changed, 2647 insertions(+), 2224 deletions(-) delete mode 100644 pjsip/include/pjsip/sip_misc.h create mode 100644 pjsip/include/pjsip/sip_util.h create mode 100644 pjsip/src/pjsip/sip_errno.c delete mode 100644 pjsip/src/pjsip/sip_misc.c create mode 100644 pjsip/src/pjsip/sip_util.c create mode 100644 pjsip/src/test-pjsip/msg.c delete mode 100644 pjsip/src/test-pjsip/parse_msg.c delete mode 100644 pjsip/src/test-pjsip/parse_uri.c create mode 100644 pjsip/src/test-pjsip/uri.c (limited to 'pjsip') diff --git a/pjsip/build/pjsip.dsw b/pjsip/build/pjsip.dsw index 562d33eb..5e6dfe03 100644 --- a/pjsip/build/pjsip.dsw +++ b/pjsip/build/pjsip.dsw @@ -57,18 +57,6 @@ Package=<4> ############################################################################### -Project: "test_pjsip"=.\test_pjsip.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - Project: "pjsip_ua"=.\pjsip_ua.dsp - Package Owner=<4> Package=<5> @@ -108,6 +96,24 @@ Package=<4> ############################################################################### +Project: "test_pjsip"=.\test_pjsip.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name pjlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name pjsip_core + End Project Dependency +}}} + +############################################################################### + Global: Package=<5> diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp index cacb9b5d..11de7fd3 100644 --- a/pjsip/build/pjsip_core.dsp +++ b/pjsip/build/pjsip_core.dsp @@ -103,7 +103,7 @@ SOURCE=..\src\pjsip\sip_endpoint.c # End Source File # Begin Source File -SOURCE=..\src\pjsip\sip_misc.c +SOURCE=..\src\pjsip\sip_errno.c # End Source File # Begin Source File @@ -133,6 +133,10 @@ SOURCE=..\src\pjsip\sip_transport_udp.c SOURCE=..\src\pjsip\sip_uri.c # End Source File +# Begin Source File + +SOURCE=..\src\pjsip\sip_util.c +# End Source File # End Group # Begin Group "Header Files" @@ -175,10 +179,6 @@ SOURCE=..\include\pjsip\sip_event.h # End Source File # Begin Source File -SOURCE=..\include\pjsip\sip_misc.h -# End Source File -# Begin Source File - SOURCE=..\include\pjsip\sip_module.h # End Source File # Begin Source File @@ -217,6 +217,10 @@ SOURCE=..\include\pjsip\sip_types.h SOURCE=..\include\pjsip\sip_uri.h # End Source File +# Begin Source File + +SOURCE=..\include\pjsip\sip_util.h +# End Source File # End Group # Begin Group "Inline Files" diff --git a/pjsip/build/test_pjsip.dsp b/pjsip/build/test_pjsip.dsp index c01f737b..2d58318d 100644 --- a/pjsip/build/test_pjsip.dsp +++ b/pjsip/build/test_pjsip.dsp @@ -51,7 +51,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 wsock32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-release.exe" +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-release.exe" !ELSEIF "$(CFG)" == "test_pjsip - Win32 Debug" @@ -76,7 +76,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 wsock32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-debug.exe" /pdbtype:sept +# ADD LINK32 dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib kernel32.lib netapi32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\test-pjsip-i386-win32-vc6-debug.exe" /pdbtype:sept !ENDIF @@ -93,11 +93,15 @@ SOURCE="..\src\test-pjsip\main.c" # End Source File # Begin Source File -SOURCE="..\src\test-pjsip\test_msg.c" +SOURCE="..\src\test-pjsip\msg.c" # End Source File # Begin Source File -SOURCE="..\src\test-pjsip\test_uri.c" +SOURCE="..\src\test-pjsip\test.c" +# End Source File +# Begin Source File + +SOURCE="..\src\test-pjsip\uri.c" # End Source File # End Group # Begin Group "Header Files" diff --git a/pjsip/docs/PJSIP-Testing.doc b/pjsip/docs/PJSIP-Testing.doc index 59822a9f..26d98a35 100644 Binary files a/pjsip/docs/PJSIP-Testing.doc and b/pjsip/docs/PJSIP-Testing.doc differ diff --git a/pjsip/include/pjsip/print_util.h b/pjsip/include/pjsip/print_util.h index 340984ce..56f05851 100644 --- a/pjsip/include/pjsip/print_util.h +++ b/pjsip/include/pjsip/print_util.h @@ -19,9 +19,12 @@ #ifndef __PJSIP_PRINT_H__ #define __PJSIP_PRINT_H__ +/* Minimum space left in the buffer */ +#define MIN_SPACE 10 + #define copy_advance_check(buf,str) \ do { \ - if ((str).slen+10 >= (endbuf-buf)) return -1; \ + if ((str).slen+MIN_SPACE >= (endbuf-buf)) return -1; \ pj_memcpy(buf, (str).ptr, (str).slen); \ buf += (str).slen; \ } while (0) @@ -31,7 +34,7 @@ static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, in { if (str2->slen) { int printed = len1+str2->slen; - if (printed+10 >= (endbuf-buf)) return NULL; + if (printed+MIN_SPACE >= (endbuf-buf)) return NULL; pj_memcpy(buf,str1,len1); pj_memcpy(buf+len1, str2->ptr, str2->slen); return buf + printed; @@ -44,7 +47,7 @@ static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, in do { \ if (str2.slen) { \ printed = len1+str2.slen; \ - if (printed+10 >= (endbuf-buf)) return -1; \ + if (printed+MIN_SPACE >= (endbuf-buf)) return -1; \ pj_memcpy(buf,str1,len1); \ pj_memcpy(buf+len1, str2.ptr, str2.slen); \ buf += printed; \ @@ -62,7 +65,7 @@ static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, in do { \ if (str2.slen) { \ printed = len1+str2.slen+2; \ - if (printed+10 >= (endbuf-buf)) return -1; \ + if (printed+MIN_SPACE >= (endbuf-buf)) return -1; \ pj_memcpy(buf,str1,len1); \ *(buf+len1)=quotebegin; \ pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \ @@ -71,9 +74,35 @@ static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, in } \ } while (0) +#define copy_advance_pair_escape(buf,str1,len1,str2,unres) \ + do { \ + if (str2.slen) { \ + pj_ssize_t esc_len; \ + if (len1+str2.slen+MIN_SPACE >= (endbuf-buf)) return -1; \ + pj_memcpy(buf,str1,len1); \ + buf += len1; \ + esc_len=pj_strncpy2_escape(buf, &str2, (endbuf-buf), &unres); \ + if (esc_len < 0) return -1; \ + buf += esc_len; \ + if (endbuf-buf < MIN_SPACE) return -1; \ + } \ + } while (0) + + #define copy_advance_no_check(buf,str) \ - pj_memcpy(buf, (str).ptr, (str).slen); \ - buf += (str).slen; + do { \ + pj_memcpy(buf, (str).ptr, (str).slen); \ + buf += (str).slen; \ + } while (0) + +#define copy_advance_escape(buf,str,unres) \ + do { \ + pj_ssize_t len = \ + pj_strncpy2_escape(buf, &(str), (endbuf-buf), &(unres)); \ + if (len < 0) return -1; \ + buf += len; \ + if (endbuf-buf < MIN_SPACE) return -1; \ + } while (0) #define copy_advance_pair_no_check(buf,str1,len1,str2) \ if (str2.slen) { \ diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h index 5473f362..2c8e6764 100644 --- a/pjsip/include/pjsip/sip_errno.h +++ b/pjsip/include/pjsip/sip_errno.h @@ -21,10 +21,31 @@ #include +PJ_BEGIN_DECL + +/* + * PJSIP error codes occupies 170000 - 219000, and mapped as follows: + * - 170100 - 170799: mapped to SIP status code in response msg. + * - 171000 - 171999: mapped to errors generated from PJSIP core. + */ + +/** + * Get error message for the specified error code. + * + * @param status The error code. + * @param buffer The buffer where to put the error message. + * @param bufsize Size of the buffer. + * + * @return The error message as NULL terminated string, + * wrapped with pj_str_t. + */ +PJ_DECL(pj_str_t) pjsip_strerror( pj_status_t status, char *buffer, + pj_size_t bufsize); + /** * Start of error code relative to PJ_ERRNO_START_USER. */ -#define PJSIP_ERRNO_START (PJ_ERRNO_START_USER+10000) +#define PJSIP_ERRNO_START (PJ_ERRNO_START_USER) /** * Create error value from SIP status code. @@ -43,81 +64,165 @@ */ #define PJSIP_ERRNO_TO_SIP_STATUS(status) \ ((status>=PJSIP_ERRNO_FROM_SIP_STATUS(100) && \ - status - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __PJSIP_SIP_MISC_H__ -#define __PJSIP_SIP_MISC_H__ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJSIP_ENDPT SIP Endpoint - * @ingroup PJSIP - * @{ - */ - -/** - * Create an independent request message. This can be used to build any - * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request - * inside a dialog, application should use #pjsip_dlg_create_request. - * - * Once a transmit data is created, the reference counter is initialized to 1. - * - * @param endpt Endpoint instance. - * @param method SIP Method. - * @param target Target URI. - * @param from URL to put in From header. - * @param to URL to put in To header. - * @param contact URL to put in Contact header. - * @param call_id Optional Call-ID (put NULL to generate unique Call-ID). - * @param cseq Optional CSeq (put -1 to generate random CSeq). - * @param text Optional text body (put NULL to omit body). - * @param p_tdata Pointer to receive the transmit data. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, - const pjsip_method *method, - const pj_str_t *target, - const pj_str_t *from, - const pj_str_t *to, - const pj_str_t *contact, - const pj_str_t *call_id, - int cseq, - const pj_str_t *text, - pjsip_tx_data **p_tdata); - -/** - * Create an independent request message from the specified headers. This - * function will shallow clone the headers and put them in the request. - * - * Once a transmit data is created, the reference counter is initialized to 1. - * - * @param endpt Endpoint instance. - * @param method SIP Method. - * @param target Target URI. - * @param from URL to put in From header. - * @param to URL to put in To header. - * @param contact URL to put in Contact header. - * @param call_id Optional Call-ID (put NULL to generate unique Call-ID). - * @param cseq Optional CSeq (put -1 to generate random CSeq). - * @param text Optional text body (put NULL to omit body). - * @param p_tdata Pointer to receive the transmit data. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) -pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, - const pjsip_method *method, - const pjsip_uri *target, - const pjsip_from_hdr *from, - const pjsip_to_hdr *to, - const pjsip_contact_hdr *contact, - const pjsip_cid_hdr *call_id, - int cseq, - const pj_str_t *text, - pjsip_tx_data **p_tdata); - -/** - * Send outgoing request and initiate UAC transaction for the request. - * This is an auxiliary function to be used by application to send arbitrary - * requests outside a dialog. To send a request within a dialog, application - * should use #pjsip_dlg_send_msg instead. - * - * @param endpt The endpoint instance. - * @param tdata The transmit data to be sent. - * @param timeout Optional timeout for final response to be received, or -1 - * if the transaction should not have a timeout restriction. - * @param token Optional token to be associated with the transaction, and - * to be passed to the callback. - * @param cb Optional callback to be called when the transaction has - * received a final response. The callback will be called with - * the previously registered token and the event that triggers - * the completion of the transaction. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - int timeout, - void *token, - void (*cb)(void*,pjsip_event*)); - -/** - * Construct a minimal response message for the received request. This function - * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and - * Call-ID headers from the request. - * - * Note: the txdata reference counter is set to ZERO!. - * - * @param endpt The endpoint. - * @param rdata The request receive data. - * @param code Status code to be put in the response. - * @param p_tdata Pointer to receive the transmit data. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt, - const pjsip_rx_data *rdata, - int code, - pjsip_tx_data **p_tdata); - -/** - * Construct a full ACK request for the received non-2xx final response. - * This utility function is normally called by the transaction to construct - * an ACK request to 3xx-6xx final response. - * The generation of ACK message for 2xx final response is different than - * this one. - * - * @param endpt The endpoint. - * @param tdata On input, this contains the original INVITE request, and on - * output, it contains the ACK message. - * @param rdata The final response message. - */ -PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - const pjsip_rx_data *rdata ); - - -/** - * Construct CANCEL request for the previously sent request. - * - * @param endpt The endpoint. - * @param tdata The transmit buffer for the request being cancelled. - * @param p_tdata Pointer to receive the transmit data. - * - * @return PJ_SUCCESS, or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - pjsip_tx_data **p_tdata); - - -/** - * Get the address parameters (host, port, flag, TTL, etc) to send the - * response. - * - * @param pool The pool. - * @param tr The transport where the request was received. - * @param via The top-most Via header of the request. - * @param addr The send address concluded from the calculation. - * - * @return zero (PJ_OK) if successfull. - */ -PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool, - const pjsip_transport *tr, - const pjsip_via_hdr *via, - pjsip_host_port *addr); - -/** - * @} - */ - -PJ_END_DECL - -#endif /* __PJSIP_SIP_MISC_H__ */ - diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h index 3cc690a6..6c30e837 100644 --- a/pjsip/include/pjsip/sip_parser.h +++ b/pjsip/include/pjsip/sip_parser.h @@ -294,19 +294,21 @@ PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, * Various specification used in parsing, exported here as extern for other * parsers. */ -extern -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_NEWLINE_OR_EOF_SPEC, /* For eating up header.*/ - pjsip_DISPLAY_SCAN_SPEC; /* Used when searching for display name in URL. */ +extern 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_HDR_CHAR_SPEC, /**< Chars in hname/havalue in URL. */ + pjsip_PROBE_USER_HOST_SPEC, /**< Hostname characters. */ + pjsip_PASSWD_SPEC, /**< Password. */ + pjsip_USER_SPEC, /**< User */ + pjsip_NEWLINE_OR_EOF_SPEC, /**< For eating up header.*/ + pjsip_DISPLAY_SCAN_SPEC; /**< Used when searching for display name. */ /* * Various string constants. diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h index 4090ca4c..e7edceef 100644 --- a/pjsip/include/pjsip/sip_transaction.h +++ b/pjsip/include/pjsip/sip_transaction.h @@ -129,6 +129,23 @@ struct pjsip_transaction }; +/** + * Create new transaction. Application would normally use + * #pjsip_endpt_create_tsx rather than this function. + * + * @param pool Pool to use by the transaction. + * @param endpt Endpoint. + * @param p_tsx Pointer to return the transaction. + * + * @return PJ_SUCCESS or the appropriate error code. + * + * @see pjsip_endpt_create_tsx + * + */ +PJ_DEF(pj_status_t) pjsip_tsx_create( pj_pool_t *pool, + pjsip_endpoint *endpt, + pjsip_transaction **p_tsx); + /** * 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. diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h index f73207da..b72721f2 100644 --- a/pjsip/include/pjsip/sip_uri.h +++ b/pjsip/include/pjsip/sip_uri.h @@ -26,6 +26,7 @@ #include #include +#include PJ_BEGIN_DECL @@ -37,6 +38,53 @@ PJ_BEGIN_DECL * @{ */ +/** + * Generic parameter, normally used in other_param or header_param. + */ +typedef struct pjsip_param +{ + PJ_DECL_LIST_MEMBER(struct pjsip_param); /**< Generic list member. */ + pj_str_t name; /**< Param/header name. */ + pj_str_t value; /**< Param/header value. */ +} pjsip_param; + + +/** + * Find the specified parameter name in the list. The name will be compared + * in case-insensitive comparison. + * + * @param param_list List of parameters to find. + * @param name Parameter/header name to find. + * + * @return The parameter if found, or NULL. + */ +PJ_DECL(pjsip_param*) pjsip_param_find( pjsip_param *param_list, + const pj_str_t *name ); + + +/** + * Find the specified parameter name in the list. The name will be compared + * in case-insensitive comparison. + * + * @param param_list List of parameters to find. + * @param name Parameter/header name to find. + * + * @return The parameter if found, or NULL. + */ +PJ_DECL(const pjsip_param*) pjsip_param_cfind(const pjsip_param *param_list, + const pj_str_t *name ); + + +/** + * Duplicate the parameters. + * + * @param pool Pool to allocate memory from. + * @param dst_list Destination list. + * @param src_list Source list. + */ +PJ_DECL(void) pjsip_param_clone(pj_pool_t *pool, pjsip_param *dst_list, + const pjsip_param *src_list); + /** * URI context. */ @@ -89,10 +137,11 @@ typedef struct pjsip_uri_vptr * @param context the context. * @param uri1 the first URI (self). * @param uri2 the second URI. - * @return zero if equal. + * @return PJ_SUCCESS if equal, or otherwise the error status which + * should point to the mismatch part. */ - int (*p_compare)(pjsip_uri_context_e context, - const void *uri1, const void *uri2); + pj_status_t (*p_compare)(pjsip_uri_context_e context, + const void *uri1, const void *uri2); /** * Clone URI. @@ -139,7 +188,6 @@ struct pjsip_uri (pj_strnicmp2(pjsip_uri_get_scheme(url), "tel", 3)==0) - /** * SIP and SIPS URL scheme. */ @@ -156,8 +204,8 @@ typedef struct pjsip_url int ttl_param; /**< Optional TTL param, or -1. */ int lr_param; /**< Optional loose routing param, or zero */ pj_str_t maddr_param; /**< Optional maddr param */ - pj_str_t other_param; /**< Other parameters grouped together. */ - pj_str_t header_param; /**< Optional header parameter. */ + pjsip_param other_param; /**< Other parameters grouped together. */ + pjsip_param header_param; /**< Optional header parameter. */ } pjsip_url; @@ -207,10 +255,11 @@ PJ_INLINE(void*) pjsip_uri_get_uri(void *uri) * @param context Comparison context. * @param uri1 The first URI. * @param uri2 The second URI. - * @return Zero if equal. + * @return PJ_SUCCESS if equal, or otherwise the error status which + * should point to the mismatch part. */ -PJ_INLINE(int) pjsip_uri_cmp(pjsip_uri_context_e context, - const void *uri1, const void *uri2) +PJ_INLINE(pj_status_t) pjsip_uri_cmp(pjsip_uri_context_e context, + const void *uri1, const void *uri2) { return (*((const pjsip_uri*)uri1)->vptr->p_compare)(context, uri1, uri2); } diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h new file mode 100644 index 00000000..f8685e54 --- /dev/null +++ b/pjsip/include/pjsip/sip_util.h @@ -0,0 +1,192 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJSIP_SIP_MISC_H__ +#define __PJSIP_SIP_MISC_H__ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJSIP_ENDPT SIP Endpoint + * @ingroup PJSIP + * @{ + */ + +/** + * Create an independent request message. This can be used to build any + * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request + * inside a dialog, application should use #pjsip_dlg_create_request. + * + * Once a transmit data is created, the reference counter is initialized to 1. + * + * @param endpt Endpoint instance. + * @param method SIP Method. + * @param target Target URI. + * @param from URL to put in From header. + * @param to URL to put in To header. + * @param contact URL to put in Contact header. + * @param call_id Optional Call-ID (put NULL to generate unique Call-ID). + * @param cseq Optional CSeq (put -1 to generate random CSeq). + * @param text Optional text body (put NULL to omit body). + * @param p_tdata Pointer to receive the transmit data. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, + const pjsip_method *method, + const pj_str_t *target, + const pj_str_t *from, + const pj_str_t *to, + const pj_str_t *contact, + const pj_str_t *call_id, + int cseq, + const pj_str_t *text, + pjsip_tx_data **p_tdata); + +/** + * Create an independent request message from the specified headers. This + * function will shallow clone the headers and put them in the request. + * + * Once a transmit data is created, the reference counter is initialized to 1. + * + * @param endpt Endpoint instance. + * @param method SIP Method. + * @param target Target URI. + * @param from URL to put in From header. + * @param to URL to put in To header. + * @param contact URL to put in Contact header. + * @param call_id Optional Call-ID (put NULL to generate unique Call-ID). + * @param cseq Optional CSeq (put -1 to generate random CSeq). + * @param text Optional text body (put NULL to omit body). + * @param p_tdata Pointer to receive the transmit data. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) +pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, + const pjsip_method *method, + const pjsip_uri *target, + const pjsip_from_hdr *from, + const pjsip_to_hdr *to, + const pjsip_contact_hdr *contact, + const pjsip_cid_hdr *call_id, + int cseq, + const pj_str_t *text, + pjsip_tx_data **p_tdata); + +/** + * Send outgoing request and initiate UAC transaction for the request. + * This is an auxiliary function to be used by application to send arbitrary + * requests outside a dialog. To send a request within a dialog, application + * should use #pjsip_dlg_send_msg instead. + * + * @param endpt The endpoint instance. + * @param tdata The transmit data to be sent. + * @param timeout Optional timeout for final response to be received, or -1 + * if the transaction should not have a timeout restriction. + * @param token Optional token to be associated with the transaction, and + * to be passed to the callback. + * @param cb Optional callback to be called when the transaction has + * received a final response. The callback will be called with + * the previously registered token and the event that triggers + * the completion of the transaction. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + int timeout, + void *token, + void (*cb)(void*,pjsip_event*)); + +/** + * Construct a minimal response message for the received request. This function + * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and + * Call-ID headers from the request. + * + * Note: the txdata reference counter is set to ZERO!. + * + * @param endpt The endpoint. + * @param rdata The request receive data. + * @param code Status code to be put in the response. + * @param p_tdata Pointer to receive the transmit data. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt, + const pjsip_rx_data *rdata, + int code, + pjsip_tx_data **p_tdata); + +/** + * Construct a full ACK request for the received non-2xx final response. + * This utility function is normally called by the transaction to construct + * an ACK request to 3xx-6xx final response. + * The generation of ACK message for 2xx final response is different than + * this one. + * + * @param endpt The endpoint. + * @param tdata On input, this contains the original INVITE request, and on + * output, it contains the ACK message. + * @param rdata The final response message. + */ +PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + const pjsip_rx_data *rdata ); + + +/** + * Construct CANCEL request for the previously sent request. + * + * @param endpt The endpoint. + * @param tdata The transmit buffer for the request being cancelled. + * @param p_tdata Pointer to receive the transmit data. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + pjsip_tx_data **p_tdata); + + +/** + * Get the address parameters (host, port, flag, TTL, etc) to send the + * response. + * + * @param pool The pool. + * @param tr The transport where the request was received. + * @param via The top-most Via header of the request. + * @param addr The send address concluded from the calculation. + * + * @return zero (PJ_OK) if successfull. + */ +PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool, + const pjsip_transport *tr, + const pjsip_via_hdr *via, + pjsip_host_port *addr); + +/** + * @} + */ + +PJ_END_DECL + +#endif /* __PJSIP_SIP_MISC_H__ */ + diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip_core.h index f2af3964..6edfda89 100644 --- a/pjsip/include/pjsip_core.h +++ b/pjsip/include/pjsip_core.h @@ -20,9 +20,10 @@ #define __PJSIP_CORE_H__ #include +#include #include +#include #include -#include #include #include #include @@ -30,7 +31,7 @@ #include #include #include -#include +#include #endif /* __PJSIP_CORE_H__ */ diff --git a/pjsip/src/pjsip-simple/event_notify.c b/pjsip/src/pjsip-simple/event_notify.c index 004a37df..4879f884 100644 --- a/pjsip/src/pjsip-simple/event_notify.c +++ b/pjsip/src/pjsip-simple/event_notify.c @@ -18,7 +18,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/pjsip/src/pjsip-simple/messaging.c b/pjsip/src/pjsip-simple/messaging.c index 9668f42f..d43acc0c 100644 --- a/pjsip/src/pjsip-simple/messaging.c +++ b/pjsip/src/pjsip-simple/messaging.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/pjsip/src/pjsip-ua/sip_dialog.c b/pjsip/src/pjsip-ua/sip_dialog.c index 1b23bc42..ac110412 100644 --- a/pjsip/src/pjsip-ua/sip_dialog.c +++ b/pjsip/src/pjsip-ua/sip_dialog.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c index 12a670c5..e7bf9bd6 100644 --- a/pjsip/src/pjsip-ua/sip_reg.c +++ b/pjsip/src/pjsip-ua/sip_reg.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/pjsip/src/pjsip-ua/sip_ua.c b/pjsip/src/pjsip-ua/sip_ua.c index bbe362a6..11f7670c 100644 --- a/pjsip/src/pjsip-ua/sip_ua.c +++ b/pjsip/src/pjsip-ua/sip_ua.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c index 0d80b994..d68d35d0 100644 --- a/pjsip/src/pjsip/sip_endpoint.c +++ b/pjsip/src/pjsip/sip_endpoint.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -105,13 +105,6 @@ static void endpt_transport_callback(pjsip_endpoint*, pj_status_t, pjsip_rx_data*); -/* - * Create transaction. - * Defined in sip_transaction.c - */ -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 * are created by the endpoint (by default, all pools ARE allocated by @@ -294,7 +287,7 @@ void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt ) /* * Get "Allow" header. */ -PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt ) +PJ_DEF(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt ) { return endpt->allow_hdr; } @@ -671,7 +664,7 @@ PJ_DEF(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt, /* * Find transaction by the key. */ -PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt, +PJ_DEF(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt, const pj_str_t *key ) { pjsip_transaction *tsx; @@ -980,7 +973,7 @@ PJ_DEF(pj_ioqueue_t*) pjsip_endpt_get_ioqueue(pjsip_endpoint *endpt) /* * Find/create transport. */ -PJ_DECL(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt, +PJ_DEF(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt, pjsip_transport_type_e type, const pj_sockaddr_in *remote, pjsip_transport **p_transport) @@ -991,6 +984,50 @@ PJ_DECL(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt, } +/* + * Report error. + */ +PJ_DEF(void) pjsip_endpt_log_error( pjsip_endpoint *endpt, + const char *sender, + pj_status_t error_code, + const char *format, + ... ) +{ + char newformat[256]; + int len; + va_list marker; + + va_start(marker, format); + + PJ_UNUSED_ARG(endpt); + + len = pj_native_strlen(format); + if (len < sizeof(newformat)-30) { + pj_str_t errstr; + + pj_native_strcpy(newformat, format); + pj_snprintf(newformat+len, sizeof(newformat)-len-1, + ": [err %d] ", error_code); + len += pj_native_strlen(newformat+len); + + errstr = pjsip_strerror(error_code, newformat+len, + sizeof(newformat)-len-1); + + len += errstr.slen; + newformat[len] = '\0'; + + pj_log(sender, 1, newformat, marker); + } else { + pj_log(sender, 1, format, marker); + } + + va_end(marker); +} + + +/* + * Dump endpoint. + */ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) { #if PJ_LOG_MAX_LEVEL >= 3 diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c new file mode 100644 index 00000000..7e24f3ee --- /dev/null +++ b/pjsip/src/pjsip/sip_errno.c @@ -0,0 +1,125 @@ +/* $Id: $ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include + +/* PJSIP's own error codes/messages + * MUST KEEP THIS ARRAY SORTED!! + */ +static const struct +{ + int code; + const char *msg; +} err_str[] = +{ + /* Generic SIP errors */ + { PJSIP_EBUSY, "Object is busy" }, + { PJSIP_ETYPEEXISTS , "Object with the same type exists" }, + + /* Messaging errors */ + { PJSIP_EINVALIDMSG, "Invalid message/syntax error" }, + { PJSIP_EINVALIDSCHEME, "Invalid URI scheme" }, + { PJSIP_EMSGTOOLONG, "Message too long" }, + { PJSIP_EPARTIALMSG, "Partial message" }, + { PJSIP_EMISSINGHDR, "Missing required header(s)" }, + { PJSIP_EINVALIDVIA, "Invalid Via header" }, + { PJSIP_EMULTIPLEVIA, "Multiple Via headers in response" }, + + /* Transport errors */ + { PJSIP_EUNSUPTRANSPORT, "Unsupported transport"}, + { PJSIP_EPENDINGTX, "Transmit buffer already pending"}, + { PJSIP_ERXOVERFLOW, "Rx buffer overflow"}, + + /* Transaction errors */ + { PJSIP_ETSXDESTROYED, "Transaction has been destroyed"}, +}; + + +/* + * pjsip_strerror() + */ +PJ_DEF(pj_str_t) pjsip_strerror( pj_status_t statcode, + char *buf, pj_size_t bufsize ) +{ + pj_str_t errstr; + + if (statcode >= PJSIP_ERRNO_START && statcode < PJSIP_ERRNO_START+800) + { + /* Status code. */ + const pj_str_t *status_text = + pjsip_get_status_text(PJSIP_ERRNO_TO_SIP_STATUS(statcode)); + + errstr.ptr = buf; + pj_strncpy_with_null(&errstr, status_text, bufsize); + return errstr; + } + else if (statcode >= PJSIP_ERRNO_START_PJSIP && + statcode < PJSIP_ERRNO_START_PJSIP + 1000) + { + /* Find the error in the table. + * Use binary search! + */ + int first = 0; + int n = PJ_ARRAY_SIZE(err_str); + + while (n > 0) { + int half = n/2; + int mid = first + half; + + if (err_str[mid].code < statcode) { + first = mid+1; + n -= (half+1); + } else if (err_str[mid].code > statcode) { + n = half; + } else { + first = mid; + break; + } + } + + + if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) { + pj_str_t msg; + + msg.ptr = (char*)err_str[first].msg; + msg.slen = pj_native_strlen(err_str[first].msg); + + errstr.ptr = buf; + pj_strncpy_with_null(&errstr, &msg, bufsize); + return errstr; + + } else { + /* Error not found. */ + errstr.ptr = buf; + errstr.slen = pj_snprintf(buf, bufsize, + "Unknown error %d", + statcode); + + return errstr; + } + } + else { + /* Not our code. Give it to PJLIB. */ + return pj_strerror(statcode, buf, bufsize); + } + +} + diff --git a/pjsip/src/pjsip/sip_misc.c b/pjsip/src/pjsip/sip_misc.c deleted file mode 100644 index c134da88..00000000 --- a/pjsip/src/pjsip/sip_misc.c +++ /dev/null @@ -1,724 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 Benny Prijono - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define THIS_FILE "endpoint" - -static const char *event_str[] = -{ - "UNIDENTIFIED", - "TIMER", - "TX_MSG", - "RX_MSG", - "TRANSPORT_ERROR", - "TSX_STATE", - "RX_2XX_RESPONSE", - "RX_ACK", - "DISCARD_MSG", - "USER", - "BEFORE_TX", -}; - -static pj_str_t str_TEXT = { "text", 4}, - str_PLAIN = { "plain", 5 }; -static int aux_mod_id; - -struct aux_tsx_data -{ - void *token; - void (*cb)(void*,pjsip_event*); -}; - -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); - - aux_mod_id = id; - return 0; -} - -static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event ) -{ - pjsip_transaction *tsx; - struct aux_tsx_data *tsx_data; - - PJ_UNUSED_ARG(mod); - - 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) - return; - if (tsx->status_code < 200) - return; - - /* Call the callback, if any, and prevent the callback to be called again - * by clearing the transaction's module_data. - */ - tsx_data = tsx->module_data[aux_mod_id]; - tsx->module_data[aux_mod_id] = NULL; - - if (tsx_data->cb) { - (*tsx_data->cb)(tsx_data->token, event); - } -} - -pjsip_module aux_tsx_module = -{ - { "Aux-Tsx", 7}, /* Name. */ - 0, /* Flag */ - 128, /* Priority */ - NULL, /* Arbitrary data. */ - 0, /* Number of methods supported (none). */ - { 0 }, /* Array of methods (none) */ - &aux_tsx_init, /* init_module() */ - NULL, /* start_module() */ - NULL, /* deinit_module() */ - &aux_tsx_handler, /* tsx_handler() */ -}; - -PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - int timeout, - void *token, - void (*cb)(void*,pjsip_event*)) -{ - pjsip_transaction *tsx; - struct aux_tsx_data *tsx_data; - pj_status_t status; - - status = pjsip_endpt_create_tsx(endpt, &tsx); - if (!tsx) { - pjsip_tx_data_dec_ref(tdata); - return -1; - } - - tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data)); - tsx_data->token = token; - tsx_data->cb = cb; - tsx->module_data[aux_mod_id] = tsx_data; - - if (pjsip_tsx_init_uac(tsx, tdata) != 0) { - pjsip_endpt_destroy_tsx(endpt, tsx); - pjsip_tx_data_dec_ref(tdata); - return -1; - } - - pjsip_endpt_register_tsx(endpt, tsx); - pjsip_tx_data_invalidate_msg(tdata); - pjsip_tsx_on_tx_msg(tsx, tdata); - pjsip_tx_data_dec_ref(tdata); - return 0; -} - -/* - * Initialize transmit data (msg) with the headers and optional body. - * This will just put the headers in the message as it is. Be carefull - * when calling this function because once a header is put in a message, - * it CAN NOT be put in other message until the first message is deleted, - * because the way the header is put in the list. - * That's why the session will shallow_clone it's headers before calling - * this function. - */ -static void init_request_throw( pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - pjsip_method *method, - pjsip_uri *param_target, - pjsip_from_hdr *param_from, - pjsip_to_hdr *param_to, - pjsip_contact_hdr *param_contact, - pjsip_cid_hdr *param_call_id, - pjsip_cseq_hdr *param_cseq, - const pj_str_t *param_text) -{ - 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); - - /* 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); - pjsip_msg_add_hdr(msg, (void*)param_from); - - /* Add To header. */ - pjsip_msg_add_hdr(msg, (void*)param_to); - - /* Add Contact header. */ - if (param_contact) { - pjsip_msg_add_hdr(msg, (void*)param_contact); - } - - /* Add Call-ID header. */ - pjsip_msg_add_hdr(msg, (void*)param_call_id); - - /* Add CSeq header. */ - pjsip_msg_add_hdr(msg, (void*)param_cseq); - - /* Create message body. */ - if (param_text) { - body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body)); - body->content_type.type = str_TEXT; - body->content_type.subtype = str_PLAIN; - body->data = pj_pool_alloc(tdata->pool, param_text->slen ); - pj_memcpy(body->data, param_text->ptr, param_text->slen); - body->len = param_text->slen; - body->print_body = &pjsip_print_text_body; - msg->body = body; - } -} - -/* - * Create arbitrary request. - */ -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; - pjsip_from_hdr *from; - pjsip_to_hdr *to; - pjsip_contact_hdr *contact; - pjsip_cseq_hdr *cseq = NULL; /* = NULL, warning in VC6 */ - pjsip_cid_hdr *call_id; - pj_str_t tmp; - pj_status_t status; - PJ_USE_EXCEPTION; - - PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()")); - - status = pjsip_endpt_create_tdata(endpt, &tdata); - if (status != PJ_SUCCESS) - return status; - - /* Init reference counter to 1. */ - pjsip_tx_data_add_ref(tdata); - - PJ_TRY { - /* Request target. */ - 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,(THIS_FILE, "Error creating request: invalid target %s", - tmp.ptr)); - goto on_error; - } - - /* From */ - from = pjsip_from_hdr_create(tdata->pool); - pj_strdup_with_null(tdata->pool, &tmp, param_from); - from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, - PJSIP_PARSE_URI_AS_NAMEADDR); - if (from->uri == NULL) { - PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'", - tmp.ptr)); - goto on_error; - } - pj_create_unique_string(tdata->pool, &from->tag); - - /* To */ - to = pjsip_to_hdr_create(tdata->pool); - pj_strdup_with_null(tdata->pool, &tmp, param_to); - to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, - PJSIP_PARSE_URI_AS_NAMEADDR); - if (to->uri == NULL) { - PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'", - tmp.ptr)); - goto on_error; - } - - /* Contact. */ - if (param_contact) { - contact = pjsip_contact_hdr_create(tdata->pool); - pj_strdup_with_null(tdata->pool, &tmp, param_contact); - contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, - PJSIP_PARSE_URI_AS_NAMEADDR); - if (contact->uri == NULL) { - PJ_LOG(4,(THIS_FILE, - "Error creating request: invalid 'Contact' URI '%s'", - tmp.ptr)); - goto on_error; - } - } else { - contact = NULL; - } - - /* Call-ID */ - call_id = pjsip_cid_hdr_create(tdata->pool); - if (param_call_id != NULL && param_call_id->slen) - pj_strdup(tdata->pool, &call_id->id, param_call_id); - else - pj_create_unique_string(tdata->pool, &call_id->id); - - /* CSeq */ - cseq = pjsip_cseq_hdr_create(tdata->pool); - if (param_cseq >= 0) - cseq->cseq = param_cseq; - else - cseq->cseq = pj_rand() & 0xFFFF; - - /* Method */ - pjsip_method_copy(tdata->pool, &cseq->method, method); - - /* Create the request. */ - init_request_throw( endpt, tdata, &cseq->method, target, from, to, - contact, call_id, cseq, param_text); - } - PJ_DEFAULT { - status = PJ_ENOMEM; - goto on_error; - } - PJ_END - - PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", - tdata->obj_name, - cseq->cseq, - cseq->method.name.slen, - cseq->method.name.ptr)); - - *p_tdata = tdata; - return PJ_SUCCESS; - -on_error: - pjsip_tx_data_dec_ref(tdata); - return status; -} - -PJ_DEF(pj_status_t) -pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, - const pjsip_method *method, - const pjsip_uri *param_target, - const pjsip_from_hdr *param_from, - const pjsip_to_hdr *param_to, - const pjsip_contact_hdr *param_contact, - const pjsip_cid_hdr *param_call_id, - int param_cseq, - const pj_str_t *param_text, - pjsip_tx_data **p_tdata) -{ - pjsip_uri *target; - pjsip_tx_data *tdata; - pjsip_from_hdr *from; - pjsip_to_hdr *to; - pjsip_contact_hdr *contact; - pjsip_cid_hdr *call_id; - pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */ - pj_status_t status; - PJ_USE_EXCEPTION; - - PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()")); - - status = pjsip_endpt_create_tdata(endpt, &tdata); - if (status != PJ_SUCCESS) - return status; - - pjsip_tx_data_add_ref(tdata); - - PJ_TRY { - target = pjsip_uri_clone(tdata->pool, param_target); - from = pjsip_hdr_shallow_clone(tdata->pool, param_from); - pjsip_fromto_set_from(from); - to = pjsip_hdr_shallow_clone(tdata->pool, param_to); - pjsip_fromto_set_to(to); - if (param_contact) - contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact); - else - contact = NULL; - call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id); - cseq = pjsip_cseq_hdr_create(tdata->pool); - if (param_cseq >= 0) - cseq->cseq = param_cseq; - else - cseq->cseq = pj_rand() % 0xFFFF; - pjsip_method_copy(tdata->pool, &cseq->method, method); - - init_request_throw(endpt, tdata, &cseq->method, target, from, to, - contact, call_id, cseq, param_text); - } - PJ_DEFAULT { - status = PJ_ENOMEM; - goto on_error; - } - PJ_END; - - PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", - tdata->obj_name, - cseq->cseq, - cseq->method.name.slen, - cseq->method.name.ptr)); - - *p_tdata = tdata; - return PJ_SUCCESS; - -on_error: - pjsip_tx_data_dec_ref(tdata); - return status; -} - -/* - * Construct a minimal response message for the received request. - */ -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; - pj_status_t status; - - /* rdata must be a request message. */ - req_msg = rdata->msg_info.msg; - pj_assert(req_msg->type == PJSIP_REQUEST_MSG); - - /* Log this action. */ - PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", - rdata, code)); - - /* Create a new transmit buffer. */ - 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); - - /* Set status code and reason text. */ - msg->line.status.code = code; - msg->line.status.reason = *pjsip_get_status_text(code); - - /* Set TX data attributes. */ - tdata->rx_timestamp = rdata->pkt_info.timestamp; - - /* Copy all the via headers, in order. */ - via = rdata->msg_info.via; - while (via) { - pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via)); - via = via->next; - if (via != (void*)&req_msg->hdr) - via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via); - else - break; - } - - /* Copy all Record-Route headers, in order. */ - rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL); - while (rr) { - pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr)); - rr = rr->next; - if (rr != (void*)&req_msg->hdr) - rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr); - else - break; - } - - /* Copy Call-ID header. */ - hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL); - pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr)); - - /* Copy From header. */ - hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from); - pjsip_msg_add_hdr( msg, hdr); - - /* Copy To header. */ - hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to); - pjsip_msg_add_hdr( msg, hdr); - - /* Copy CSeq header. */ - hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq); - pjsip_msg_add_hdr( msg, hdr); - - /* All done. */ - *p_tdata = tdata; - return PJ_SUCCESS; -} - - -/* - * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of - * RFC3261). Note that the generation of ACK for 2xx response is different, - * and one must not use this function to generate such ACK. - */ -PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt, - pjsip_tx_data *tdata, - const pjsip_rx_data *rdata ) -{ - pjsip_msg *ack_msg, *invite_msg; - pjsip_to_hdr *to; - pjsip_from_hdr *from; - pjsip_cseq_hdr *cseq; - pjsip_hdr *hdr; - - /* Make compiler happy. */ - PJ_UNUSED_ARG(endpt); - - /* rdata must be a final response. */ - pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG && - rdata->msg_info.msg->line.status.code >= 300); - - /* Log this action. */ - 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); - pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD ); - - /* The original INVITE message. */ - invite_msg = tdata->msg; - - /* Copy Request-Uri from the original INVITE. */ - ack_msg->line.req.uri = invite_msg->line.req.uri; - - /* Copy Call-ID from the original INVITE */ - hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL); - pjsip_msg_add_hdr( ack_msg, hdr ); - - /* Copy From header from the original INVITE. */ - from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, - PJSIP_H_FROM, NULL); - pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from ); - - /* 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->msg_info.to->tag); - pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to ); - - /* Must contain single Via, just as the original INVITE. */ - hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL); - pjsip_msg_insert_first_hdr( ack_msg, hdr ); - - /* Must have the same CSeq value as the original INVITE, but method - * changed to ACK - */ - cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, - PJSIP_H_CSEQ, NULL); - pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD ); - pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq ); - - /* If the original INVITE has Route headers, those header fields MUST - * appear in the ACK. - */ - hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL); - while (hdr != NULL) { - pjsip_msg_add_hdr( ack_msg, hdr ); - hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL); - } - - /* Set the message in the "tdata" to point to the ACK message. */ - tdata->msg = ack_msg; - - /* Reset transmit packet buffer, to force 're-printing' of message. */ - tdata->buf.cur = tdata->buf.start; - - /* We're done. - * "tdata" parameter now contains the ACK message. - */ -} - - -/* - * Construct CANCEL request for the previously sent request, according to - * chapter 9.1 of RFC3261. - */ -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; - pj_status_t status; - - /* Log this action. */ - 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_RETURN(req_msg->type == PJSIP_REQUEST_MSG && - req_msg->line.req.method.id == PJSIP_INVITE_METHOD, - PJ_EINVAL); - - /* Create new transmit buffer. */ - status = pjsip_endpt_create_tdata( endpt, &cancel_tdata); - if (status != PJ_SUCCESS) { - return status; - } - - /* Create CANCEL request message. */ - cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG); - cancel_tdata->msg = cancel_msg; - - /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are - * copied from the original request. - */ - /* Set request line. */ - pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD); - req_uri = req_msg->line.req.uri; - cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri); - - /* Copy Call-ID */ - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL); - pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); - - /* Copy From header. */ - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL); - pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); - - /* Copy To header. */ - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL); - pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); - - /* Create new CSeq with equal number, but method set to CANCEL. */ - req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL); - cseq = pjsip_cseq_hdr_create(cancel_tdata->pool); - cseq->cseq = req_cseq->cseq; - pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD); - pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq); - - /* Must only have single Via which matches the top-most Via in the - * request being cancelled. - */ - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL); - pjsip_msg_insert_first_hdr(cancel_msg, - pjsip_hdr_clone(cancel_tdata->pool, hdr)); - - /* If the original request has Route header, the CANCEL request must also - * has exactly the same. - * Copy "Route" header from the request. - */ - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL); - while (hdr != NULL) { - pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); - hdr = hdr->next; - if (hdr != &cancel_msg->hdr) - hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr); - else - break; - } - - /* Done. - * Return the transmit buffer containing the CANCEL request. - */ - *p_tdata = cancel_tdata; - return PJ_SUCCESS; -} - -/* Get the address parameters (host, port, flag, TTL, etc) to send the - * response. - */ -PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool, - const pjsip_transport *req_transport, - const pjsip_via_hdr *via, - pjsip_host_port *send_addr) -{ - /* Determine the destination address (section 18.2.2): - * - for TCP, SCTP, or TLS, send the response using the transport where - * the request was received. - * - if maddr parameter is present, send to this address using the port - * in sent-by or 5060. If multicast is used, the TTL in the Via must - * be used, or 1 if ttl parameter is not present. - * - otherwise if received parameter is present, set to this address. - * - otherwise send to the address in sent-by. - */ - send_addr->flag = req_transport->flag; - send_addr->type = req_transport->type; - - if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) { - const pj_sockaddr_in *remote_addr; - remote_addr = &req_transport->rem_addr; - pj_strdup2(pool, &send_addr->host, - pj_inet_ntoa(remote_addr->sin_addr)); - send_addr->port = pj_sockaddr_in_get_port(remote_addr); - - } else { - /* Set the host part */ - if (via->maddr_param.slen) { - pj_strdup(pool, &send_addr->host, &via->maddr_param); - } else if (via->recvd_param.slen) { - pj_strdup(pool, &send_addr->host, &via->recvd_param); - } else { - pj_strdup(pool, &send_addr->host, &via->sent_by.host); - } - - /* Set the port */ - send_addr->port = via->sent_by.port; - } - - return PJ_SUCCESS; -} - -/* - * Get the event string from the event ID. - */ -PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e) -{ - return event_str[e]; -} - diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c index 01013363..7b869492 100644 --- a/pjsip/src/pjsip/sip_parser.c +++ b/pjsip/src/pjsip/sip_parser.c @@ -23,6 +23,7 @@ #include #include /* rdata structure */ #include +#include #include #include #include @@ -32,16 +33,20 @@ #include #include -#define RESERVED ";/?:@&=+$," -#define MARK "-_.!~*'()" -#define ESCAPED "%" -#define USER "&=+$,;?/" -#define PASS "&=+$," -#define TOKEN "-.!%*_=`'~+" /* '+' is because of application/pidf+xml - * in Content-Type! */ -#define HOST "_-." -#define HEX_DIGIT "abcdefABCDEF" -#define PARAM_CHAR "[]/:&+$" MARK "%" +#define ALNUM +#define RESERVED ";/?:@&=+$," +#define MARK "-_.!~*'()" +#define UNRESERVED ALNUM MARK +#define ESCAPED "%" +#define USER_UNRESERVED "&=+$,;?/" +#define PASS "&=+$," +#define TOKEN "-.!%*_=`'~+" /* '+' is because of app/pidf+xml + * in Content-Type! */ +#define HOST "_-." +#define HEX_DIGIT "abcdefABCDEF" +#define PARAM_CHAR "[]/:&+$" UNRESERVED ESCAPED +#define HNV_UNRESERVED "[]/?:+$" +#define HDR_CHAR HNV_UNRESERVED UNRESERVED ESCAPED #define PJSIP_VERSION "SIP/2.0" #define PJSIP_SYN_ERR_EXCEPTION 1 @@ -92,6 +97,7 @@ pj_cis_t pjsip_HOST_SPEC, /* For scanning host part. */ pjsip_HEX_SPEC, /* Hexadecimal digits. */ pjsip_PARAM_CHAR_SPEC, /* For scanning pname (or pvalue when * it's not quoted.) */ + pjsip_HDR_CHAR_SPEC, /* Chars in hname or hvalue */ pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */ pjsip_PASSWD_SPEC, /* Password. */ pjsip_USER_SPEC, /* User */ @@ -109,6 +115,9 @@ static pjsip_msg * int_parse_msg( pjsip_parse_ctx *ctx, static void int_parse_param( pj_scanner *scanner, pj_str_t *pname, pj_str_t *pvalue); +static void int_parse_hparam( pj_scanner *scanner, + pj_str_t *hname, + pj_str_t *hvalue ); static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool, pjsip_request_line *req_line); @@ -271,9 +280,13 @@ static pj_status_t init_parser() PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR); + status = pj_cis_dup(&pjsip_HDR_CHAR_SPEC, &pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str(&pjsip_HDR_CHAR_SPEC, HDR_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 ); + pj_cis_add_str( &pjsip_USER_SPEC, ESCAPED USER_UNRESERVED ); status = pj_cis_dup(&pjsip_PASSWD_SPEC, &pjsip_ALNUM_SPEC); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); @@ -858,6 +871,7 @@ void pjsip_parse_param_imp( pj_scanner *scanner, { /* pname */ pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pname); + pj_str_unescape(pname); /* pvalue, if any */ if (*scanner->curptr == '=') { @@ -871,6 +885,7 @@ void pjsip_parse_param_imp( pj_scanner *scanner, } } else { pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pvalue); + pj_str_unescape(pvalue); } } else { pvalue->ptr = NULL; @@ -889,15 +904,39 @@ static void int_parse_param( pj_scanner *scanner, pjsip_parse_param_imp(scanner, pname, pvalue, 0); } +/* Parse header parameter. */ +static void int_parse_hparam( pj_scanner *scanner, + pj_str_t *hname, pj_str_t *hvalue ) +{ + /* Get '?' or '&' character. */ + pj_scan_get_char(scanner); + + /* hname */ + pj_scan_get(scanner, &pjsip_HDR_CHAR_SPEC, hname); + pj_str_unescape(hname); + + /* pvalue, if any */ + if (*scanner->curptr == '=') { + pj_scan_get_char(scanner); + pj_scan_get(scanner, &pjsip_HDR_CHAR_SPEC, hvalue); + pj_str_unescape(hvalue); + } else { + hvalue->ptr = NULL; + hvalue->slen = 0; + } +} + /* Parse host:port in URI. */ 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); + /* RFC3261 section 19.1.2: host don't need to be unescaped */ if (*scanner->curptr == ':') { pj_str_t port; pj_scan_get_char(scanner); pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port); + pj_str_unescape(&port); *p_port = pj_strtoul(&port); } else { *p_port = 0; @@ -926,9 +965,12 @@ 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); + pj_str_unescape(user); + if ( *scanner->curptr == ':') { pj_scan_get_char( scanner ); pj_scan_get( scanner, &pjsip_PASSWD_SPEC, pass); + pj_str_unescape(pass); } else { pass->ptr = NULL; pass->slen = 0; @@ -945,6 +987,9 @@ static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *po pjsip_uri *uri; int is_name_addr = 0; + /* Exhaust any whitespaces. */ + pj_scan_skip_whitespace(scanner); + if (*scanner->curptr=='"' || *scanner->curptr=='<') { uri = (pjsip_uri*)int_parse_name_addr( scanner, pool ); is_name_addr = 1; @@ -1034,6 +1079,7 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, pjsip_url *url; int colon; int skip_ws = scanner->skip_ws; + int hsep = '?'; scanner->skip_ws = 0; pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme); @@ -1089,14 +1135,20 @@ static pjsip_url *int_parse_sip_url( pj_scanner *scanner, url->lr_param = 1; } else { - concat_param(&url->other_param, pool, &pname, &pvalue); + pjsip_param *p = pj_pool_alloc(pool, sizeof(pjsip_param)); + p->name = pname; + p->value = pvalue; + pj_list_insert_before(&url->other_param, p); } } /* Get header params. */ - if (parse_params && *scanner->curptr == '?') { - pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, - &url->header_param); + while (parse_params && *scanner->curptr == hsep) { + pjsip_param *param; + param = pj_pool_alloc(pool, sizeof(pjsip_param)); + int_parse_hparam(scanner, ¶m->name, ¶m->value); + pj_list_insert_before(&url->header_param, param); + hsep = '&'; } scanner->skip_ws = skip_ws; diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index f4818817..bc4f21ff 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -345,9 +345,9 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, /* * Create new transaction. */ -pj_status_t pjsip_tsx_create( pj_pool_t *pool, - pjsip_endpoint *endpt, - pjsip_transaction **p_tsx) +PJ_DEF(pj_status_t) pjsip_tsx_create( pj_pool_t *pool, + pjsip_endpoint *endpt, + pjsip_transaction **p_tsx) { pjsip_transaction *tsx; pj_status_t status; diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 307f9e5e..a32fb683 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -647,7 +647,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, &msg_fragment_size); if (msg_status != PJ_SUCCESS) { if (remaining_len == PJSIP_MAX_PKT_LEN) { - mgr->msg_cb(mgr->endpt, PJSIP_EOVERFLOW, rdata); + mgr->msg_cb(mgr->endpt, PJSIP_ERXOVERFLOW, rdata); /* Exhaust all data. */ return rdata->pkt_info.len; } else { diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c index bd49db97..b292fea0 100644 --- a/pjsip/src/pjsip/sip_uri.c +++ b/pjsip/src/pjsip/sip_uri.c @@ -18,11 +18,59 @@ */ #include #include +#include #include +#include +#include #include #include #include +/* + * Generic parameter manipulation. + */ +PJ_DEF(pjsip_param*) pjsip_param_find( pjsip_param *param_list, + const pj_str_t *name ) +{ + pjsip_param *p = param_list->next; + while (p != param_list) { + if (pj_stricmp(&p->name, name)==0) + return p; + p = p->next; + } + return NULL; +} + +PJ_DEF(const pjsip_param*) pjsip_param_cfind( const pjsip_param *param_list, + const pj_str_t *name ) +{ + const pjsip_param *p = param_list->next; + while (p != param_list) { + if (pj_stricmp(&p->name, name)==0) + return p; + p = p->next; + } + return NULL; +} + +PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list, + const pjsip_param *src_list) +{ + const pjsip_param *p = src_list->next; + + pj_list_init(dst_list); + while (p != src_list) { + pjsip_param *new_param = pj_pool_alloc(pool, sizeof(pjsip_param)); + pj_strdup(pool, &new_param->name, &p->name); + pj_strdup(pool, &new_param->value, &p->value); + pj_list_insert_before(dst_list, new_param); + p = p->next; + } +} + +/* + * URI stuffs + */ #define IS_SIPS(url) ((url)->vptr==&sips_url_vptr) static const pj_str_t *pjsip_url_get_scheme( const pjsip_url* ); @@ -109,6 +157,8 @@ PJ_DEF(void) pjsip_url_init(pjsip_url *url, int secure) pj_memset(url, 0, sizeof(*url)); url->ttl_param = -1; url->vptr = secure ? &sips_url_vptr : &sip_url_vptr; + pj_list_init(&url->other_param); + pj_list_init(&url->header_param); } PJ_DEF(pjsip_url*) pjsip_url_create( pj_pool_t *pool, int secure ) @@ -123,37 +173,25 @@ static int pjsip_url_print( pjsip_uri_context_e context, char *buf, pj_size_t size) { int printed; - pj_size_t size_required; char *startbuf = buf; + char *endbuf = buf+size; const pj_str_t *scheme; - *buf = '\0'; + pjsip_param *param; + char hparam_char = '?'; - /* Check the buffer length. */ - size_required = 6 + url->host.slen + 10 + - url->user.slen + url->passwd.slen + 2 + - url->user_param.slen + 6 + - url->method_param.slen + 8 + - url->transport_param.slen + 11 + - 9 + 5 + - url->maddr_param.slen + 7 + - 3 + - url->other_param.slen + - url->header_param.slen; - if (size < size_required) { - return -1; - } + *buf = '\0'; /* Print scheme ("sip:" or "sips:") */ scheme = pjsip_uri_get_scheme(url); - copy_advance_no_check(buf, *scheme); + copy_advance_check(buf, *scheme); *buf++ = ':'; /* Print "user:password@", if any. */ if (url->user.slen) { - copy_advance_no_check(buf, url->user); + copy_advance_escape(buf, url->user, pjsip_USER_SPEC); if (url->passwd.slen) { *buf++ = ':'; - copy_advance_no_check(buf, url->passwd); + copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC); } *buf++ = '@'; @@ -161,7 +199,7 @@ static int pjsip_url_print( pjsip_uri_context_e context, /* Print host. */ pj_assert(url->host.slen != 0); - copy_advance_no_check(buf, url->host); + copy_advance_check(buf, url->host); /* Only print port if it is explicitly specified. * Port is not allowed in To and From header. @@ -170,29 +208,31 @@ static int pjsip_url_print( pjsip_uri_context_e context, * number exactly as it was sent. We don't remember whether an * UA has sent us port, so we'll just send the port indiscrimately */ - PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER) - if (url->port /*&& context != PJSIP_URI_IN_FROMTO_HDR*/) { + //PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER) + if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) { *buf++ = ':'; printed = pj_utoa(url->port, buf); buf += printed; } /* User param is allowed in all contexes */ - copy_advance_pair_no_check(buf, ";user=", 6, url->user_param); + copy_advance_pair_check(buf, ";user=", 6, url->user_param); /* Method param is only allowed in external/other context. */ if (context == PJSIP_URI_IN_OTHER) { - copy_advance_pair_no_check(buf, ";method=", 8, url->method_param); + copy_advance_pair_escape(buf, ";method=", 8, url->method_param, + pjsip_PARAM_CHAR_SPEC); } /* Transport is not allowed in From/To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { - copy_advance_pair_no_check(buf, ";transport=", 11, url->transport_param); + copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param, + pjsip_PARAM_CHAR_SPEC); } /* TTL param is not allowed in From, To, Route, and Record-Route header. */ if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR && - context != PJSIP_URI_IN_ROUTING_HDR) + context != PJSIP_URI_IN_ROUTING_HDR && (endbuf-buf) > 15) { pj_memcpy(buf, ";ttl=", 5); printed = pj_utoa(url->ttl_param, buf+5); @@ -201,7 +241,8 @@ static int pjsip_url_print( pjsip_uri_context_e context, /* maddr param is not allowed in From and To header. */ if (context != PJSIP_URI_IN_FROMTO_HDR) { - copy_advance_pair_no_check(buf, ";maddr=", 7, url->maddr_param); + copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param, + pjsip_PARAM_CHAR_SPEC); } /* lr param is not allowed in From, To, and Contact header. */ @@ -209,86 +250,166 @@ static int pjsip_url_print( pjsip_uri_context_e context, context != PJSIP_URI_IN_CONTACT_HDR) { pj_str_t lr = { ";lr", 3 }; - copy_advance_no_check(buf, lr); + copy_advance_check(buf, lr); } /* Other param. */ - if (url->other_param.slen) { - copy_advance_no_check(buf, url->other_param); + param = url->other_param.next; + while (param != &url->other_param) { + *buf++ = ';'; + copy_advance_escape(buf, param->name, pjsip_PARAM_CHAR_SPEC); + if (param->value.slen) { + *buf++ = '='; + copy_advance_escape(buf, param->value, pjsip_PARAM_CHAR_SPEC); + } + param = param->next; } /* Header param. */ - if (url->header_param.slen) { - copy_advance_no_check(buf, url->header_param); + param = url->header_param.next; + while (param != &url->header_param) { + *buf++ = hparam_char; + copy_advance_escape(buf, param->name, pjsip_HDR_CHAR_SPEC); + if (param->value.slen) { + *buf++ = '='; + copy_advance_escape(buf, param->value, pjsip_HDR_CHAR_SPEC); + } + param = param->next; + hparam_char = '&'; } *buf = '\0'; return buf-startbuf; } -static int pjsip_url_compare( pjsip_uri_context_e context, - const pjsip_url *url1, const pjsip_url *url2) +static pj_status_t pjsip_url_compare( pjsip_uri_context_e context, + const pjsip_url *url1, + const pjsip_url *url2) { - /* The easiest (and probably the most efficient) way to compare two URLs - are to print them, and compare them bytes per bytes. This technique - works quite well with RFC3261, as the RFC (unlike RFC2543) defines that - components specified in one URL does NOT match its default value if - it is not specified in the second URL. For example, parameter "user=ip" - does NOT match if it is omited in second URL. - - HOWEVER, THE SAME CAN NOT BE APPLIED FOR other-param NOR header-param. - For these, each of the parameters must be compared one by one. Parameter - that exists in one URL will match the comparison. But parameter that - exists in both URLs and doesn't match wont match the URL comparison. - - The solution for this is to compare 'standard' URL components with - bytes-to-bytes comparison, and compare other-param and header-param with - more intelligent comparison. + const pjsip_param *p1; + + /* + * Compare two SIP URL's according to Section 19.1.4 of RFC 3261. */ - char str_url1[PJSIP_MAX_URL_SIZE]; - char str_url2[PJSIP_MAX_URL_SIZE]; - int len1, len2; - /* Must compare scheme first, as the second URI may not be SIP URL. */ - if (pj_stricmp(pjsip_uri_get_scheme(url1), pjsip_uri_get_scheme(url2))) - return -1; + /* SIP and SIPS URI are never equivalent. + * Note: just compare the vptr to avoid string comparison. + * Pretty neat huh!! + */ + if (url1->vptr != url2->vptr) + return PJSIP_ECMPSCHEME; - len1 = pjsip_url_print(context, url1, str_url1, sizeof(str_url1)); - if (len1 < 1) { - pj_assert(0); - return -1; + /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. + * This includes userinfo containing passwords or formatted as + * telephone-subscribers. + */ + if (pj_strcmp(&url1->user, &url2->user) != 0) + return PJSIP_ECMPUSER; + if (pj_strcmp(&url1->passwd, &url2->passwd) != 0) + return PJSIP_ECMPPASSWD; + + /* Comparison of all other components of the URI is + * case-insensitive unless explicitly defined otherwise. + */ + + /* The ordering of parameters and header fields is not significant + * in comparing SIP and SIPS URIs. + */ + + /* Characters other than those in the “reserved” set (see RFC 2396 [5]) + * are equivalent to their “encoding. + */ + + /* An IP address that is the result of a DNS lookup of a host name + * does not match that host name. + */ + if (pj_stricmp(&url1->host, &url2->host) != 0) + return PJSIP_ECMPHOST; + + /* A URI omitting any component with a default value will not match a URI + * explicitly containing that component with its default value. + * For instance, a URI omitting the optional port component will not match + * a URI explicitly declaring port 5060. + * The same is true for the transport-parameter, ttl-parameter, + * user-parameter, and method components. + */ + + /* Port is not allowed in To and From header. + */ + if (context != PJSIP_URI_IN_FROMTO_HDR) { + if (url1->port != url2->port) + return PJSIP_ECMPPORT; } - len2 = pjsip_url_print(context, url2, str_url2, sizeof(str_url2)); - if (len2 < 1) { - pj_assert(0); - return -1; + /* Transport is not allowed in From/To header. */ + if (context != PJSIP_URI_IN_FROMTO_HDR) { + if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0) + return PJSIP_ECMPTRANSPORTPRM; } - - if (len1 != len2) { - /* Not equal. */ - return -1; + /* TTL param is not allowed in From, To, Route, and Record-Route header. */ + if (context != PJSIP_URI_IN_FROMTO_HDR && + context != PJSIP_URI_IN_ROUTING_HDR) + { + if (url1->ttl_param != url2->ttl_param) + return PJSIP_ECMPTTLPARAM; } - - if (pj_native_strcmp(str_url1, str_url2)) { - /* Not equal */ - return -1; + /* User param is allowed in all contexes */ + if (pj_stricmp(&url1->user_param, &url2->user_param) != 0) + return PJSIP_ECMPUSERPARAM; + /* Method param is only allowed in external/other context. */ + if (context == PJSIP_URI_IN_OTHER) { + if (pj_stricmp(&url1->method_param, &url2->method_param) != 0) + return PJSIP_ECMPMETHODPARAM; + } + /* maddr param is not allowed in From and To header. */ + if (context != PJSIP_URI_IN_FROMTO_HDR) { + if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0) + return PJSIP_ECMPMADDRPARAM; } - /* TODO: compare other-param and header-param in more intelligent manner. */ - PJ_TODO(HPARAM_AND_OTHER_PARAM_COMPARISON_IN_URL_COMPARISON) + /* lr parameter is ignored (?) */ + /* lr param is not allowed in From, To, and Contact header. */ - if (pj_strcmp(&url1->other_param, &url2->other_param)) { - /* Not equal. */ - return -1; + + /* All other uri-parameters appearing in only one URI are ignored when + * comparing the URIs. + */ + p1 = url1->other_param.next; + while (p1 != &url1->other_param) { + const pjsip_param *p2; + p2 = pjsip_param_cfind(&url2->other_param, &p1->name); + if (p2 ) { + if (pj_stricmp(&p1->value, &p2->value) != 0) + return PJSIP_ECMPOTHERPARAM; + } + + p1 = p1->next; } - if (pj_strcmp(&url1->header_param, &url2->header_param)) { - /* Not equal. */ - return -1; + + /* URI header components are never ignored. Any present header component + * MUST be present in both URIs and match for the URIs to match. + * The matching rules are defined for each header field in Section 20. + */ + p1 = url1->header_param.next; + while (p1 != &url1->header_param) { + const pjsip_param *p2; + p2 = pjsip_param_cfind(&url2->header_param, &p1->name); + if (p2) { + /* It seems too much to compare two header params according to + * the rule of each header. We'll just compare them string to + * string.. + */ + PJ_TODO(MORE_COMPLIANT_HEADER_PARAM_COMPARISON_IN_URL); + + if (pj_stricmp(&p1->value, &p2->value) != 0) + return PJSIP_ECMPHEADERPARAM; + } else { + return PJSIP_ECMPHEADERPARAM; + } + p1 = p1->next; } - /* Seems to be equal, isn't it. */ - return 0; - + /* Equal!! Pheuww.. */ + return PJ_SUCCESS; } @@ -304,8 +425,8 @@ PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_url *url, pj_strdup( pool, &url->transport_param, &rhs->transport_param); url->ttl_param = rhs->ttl_param; pj_strdup( pool, &url->maddr_param, &rhs->maddr_param); - pj_strdup( pool, &url->other_param, &rhs->other_param); - pj_strdup( pool, &url->header_param, &rhs->header_param); + pjsip_param_clone(pool, &url->other_param, &rhs->other_param); + pjsip_param_clone(pool, &url->header_param, &rhs->header_param); url->lr_param = rhs->lr_param; } diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c new file mode 100644 index 00000000..5f59a12e --- /dev/null +++ b/pjsip/src/pjsip/sip_util.c @@ -0,0 +1,724 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define THIS_FILE "endpoint" + +static const char *event_str[] = +{ + "UNIDENTIFIED", + "TIMER", + "TX_MSG", + "RX_MSG", + "TRANSPORT_ERROR", + "TSX_STATE", + "RX_2XX_RESPONSE", + "RX_ACK", + "DISCARD_MSG", + "USER", + "BEFORE_TX", +}; + +static pj_str_t str_TEXT = { "text", 4}, + str_PLAIN = { "plain", 5 }; +static int aux_mod_id; + +struct aux_tsx_data +{ + void *token; + void (*cb)(void*,pjsip_event*); +}; + +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); + + aux_mod_id = id; + return 0; +} + +static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event ) +{ + pjsip_transaction *tsx; + struct aux_tsx_data *tsx_data; + + PJ_UNUSED_ARG(mod); + + 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) + return; + if (tsx->status_code < 200) + return; + + /* Call the callback, if any, and prevent the callback to be called again + * by clearing the transaction's module_data. + */ + tsx_data = tsx->module_data[aux_mod_id]; + tsx->module_data[aux_mod_id] = NULL; + + if (tsx_data->cb) { + (*tsx_data->cb)(tsx_data->token, event); + } +} + +pjsip_module aux_tsx_module = +{ + { "Aux-Tsx", 7}, /* Name. */ + 0, /* Flag */ + 128, /* Priority */ + NULL, /* Arbitrary data. */ + 0, /* Number of methods supported (none). */ + { 0 }, /* Array of methods (none) */ + &aux_tsx_init, /* init_module() */ + NULL, /* start_module() */ + NULL, /* deinit_module() */ + &aux_tsx_handler, /* tsx_handler() */ +}; + +PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + int timeout, + void *token, + void (*cb)(void*,pjsip_event*)) +{ + pjsip_transaction *tsx; + struct aux_tsx_data *tsx_data; + pj_status_t status; + + status = pjsip_endpt_create_tsx(endpt, &tsx); + if (!tsx) { + pjsip_tx_data_dec_ref(tdata); + return -1; + } + + tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data)); + tsx_data->token = token; + tsx_data->cb = cb; + tsx->module_data[aux_mod_id] = tsx_data; + + if (pjsip_tsx_init_uac(tsx, tdata) != 0) { + pjsip_endpt_destroy_tsx(endpt, tsx); + pjsip_tx_data_dec_ref(tdata); + return -1; + } + + pjsip_endpt_register_tsx(endpt, tsx); + pjsip_tx_data_invalidate_msg(tdata); + pjsip_tsx_on_tx_msg(tsx, tdata); + pjsip_tx_data_dec_ref(tdata); + return 0; +} + +/* + * Initialize transmit data (msg) with the headers and optional body. + * This will just put the headers in the message as it is. Be carefull + * when calling this function because once a header is put in a message, + * it CAN NOT be put in other message until the first message is deleted, + * because the way the header is put in the list. + * That's why the session will shallow_clone it's headers before calling + * this function. + */ +static void init_request_throw( pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + pjsip_method *method, + pjsip_uri *param_target, + pjsip_from_hdr *param_from, + pjsip_to_hdr *param_to, + pjsip_contact_hdr *param_contact, + pjsip_cid_hdr *param_call_id, + pjsip_cseq_hdr *param_cseq, + const pj_str_t *param_text) +{ + 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); + + /* 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); + pjsip_msg_add_hdr(msg, (void*)param_from); + + /* Add To header. */ + pjsip_msg_add_hdr(msg, (void*)param_to); + + /* Add Contact header. */ + if (param_contact) { + pjsip_msg_add_hdr(msg, (void*)param_contact); + } + + /* Add Call-ID header. */ + pjsip_msg_add_hdr(msg, (void*)param_call_id); + + /* Add CSeq header. */ + pjsip_msg_add_hdr(msg, (void*)param_cseq); + + /* Create message body. */ + if (param_text) { + body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body)); + body->content_type.type = str_TEXT; + body->content_type.subtype = str_PLAIN; + body->data = pj_pool_alloc(tdata->pool, param_text->slen ); + pj_memcpy(body->data, param_text->ptr, param_text->slen); + body->len = param_text->slen; + body->print_body = &pjsip_print_text_body; + msg->body = body; + } +} + +/* + * Create arbitrary request. + */ +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; + pjsip_from_hdr *from; + pjsip_to_hdr *to; + pjsip_contact_hdr *contact; + pjsip_cseq_hdr *cseq = NULL; /* = NULL, warning in VC6 */ + pjsip_cid_hdr *call_id; + pj_str_t tmp; + pj_status_t status; + PJ_USE_EXCEPTION; + + PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()")); + + status = pjsip_endpt_create_tdata(endpt, &tdata); + if (status != PJ_SUCCESS) + return status; + + /* Init reference counter to 1. */ + pjsip_tx_data_add_ref(tdata); + + PJ_TRY { + /* Request target. */ + 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,(THIS_FILE, "Error creating request: invalid target %s", + tmp.ptr)); + goto on_error; + } + + /* From */ + from = pjsip_from_hdr_create(tdata->pool); + pj_strdup_with_null(tdata->pool, &tmp, param_from); + from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, + PJSIP_PARSE_URI_AS_NAMEADDR); + if (from->uri == NULL) { + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'", + tmp.ptr)); + goto on_error; + } + pj_create_unique_string(tdata->pool, &from->tag); + + /* To */ + to = pjsip_to_hdr_create(tdata->pool); + pj_strdup_with_null(tdata->pool, &tmp, param_to); + to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, + PJSIP_PARSE_URI_AS_NAMEADDR); + if (to->uri == NULL) { + PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'", + tmp.ptr)); + goto on_error; + } + + /* Contact. */ + if (param_contact) { + contact = pjsip_contact_hdr_create(tdata->pool); + pj_strdup_with_null(tdata->pool, &tmp, param_contact); + contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, + PJSIP_PARSE_URI_AS_NAMEADDR); + if (contact->uri == NULL) { + PJ_LOG(4,(THIS_FILE, + "Error creating request: invalid 'Contact' URI '%s'", + tmp.ptr)); + goto on_error; + } + } else { + contact = NULL; + } + + /* Call-ID */ + call_id = pjsip_cid_hdr_create(tdata->pool); + if (param_call_id != NULL && param_call_id->slen) + pj_strdup(tdata->pool, &call_id->id, param_call_id); + else + pj_create_unique_string(tdata->pool, &call_id->id); + + /* CSeq */ + cseq = pjsip_cseq_hdr_create(tdata->pool); + if (param_cseq >= 0) + cseq->cseq = param_cseq; + else + cseq->cseq = pj_rand() & 0xFFFF; + + /* Method */ + pjsip_method_copy(tdata->pool, &cseq->method, method); + + /* Create the request. */ + init_request_throw( endpt, tdata, &cseq->method, target, from, to, + contact, call_id, cseq, param_text); + } + PJ_DEFAULT { + status = PJ_ENOMEM; + goto on_error; + } + PJ_END + + PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", + tdata->obj_name, + cseq->cseq, + cseq->method.name.slen, + cseq->method.name.ptr)); + + *p_tdata = tdata; + return PJ_SUCCESS; + +on_error: + pjsip_tx_data_dec_ref(tdata); + return status; +} + +PJ_DEF(pj_status_t) +pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, + const pjsip_method *method, + const pjsip_uri *param_target, + const pjsip_from_hdr *param_from, + const pjsip_to_hdr *param_to, + const pjsip_contact_hdr *param_contact, + const pjsip_cid_hdr *param_call_id, + int param_cseq, + const pj_str_t *param_text, + pjsip_tx_data **p_tdata) +{ + pjsip_uri *target; + pjsip_tx_data *tdata; + pjsip_from_hdr *from; + pjsip_to_hdr *to; + pjsip_contact_hdr *contact; + pjsip_cid_hdr *call_id; + pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */ + pj_status_t status; + PJ_USE_EXCEPTION; + + PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()")); + + status = pjsip_endpt_create_tdata(endpt, &tdata); + if (status != PJ_SUCCESS) + return status; + + pjsip_tx_data_add_ref(tdata); + + PJ_TRY { + target = pjsip_uri_clone(tdata->pool, param_target); + from = pjsip_hdr_shallow_clone(tdata->pool, param_from); + pjsip_fromto_set_from(from); + to = pjsip_hdr_shallow_clone(tdata->pool, param_to); + pjsip_fromto_set_to(to); + if (param_contact) + contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact); + else + contact = NULL; + call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id); + cseq = pjsip_cseq_hdr_create(tdata->pool); + if (param_cseq >= 0) + cseq->cseq = param_cseq; + else + cseq->cseq = pj_rand() % 0xFFFF; + pjsip_method_copy(tdata->pool, &cseq->method, method); + + init_request_throw(endpt, tdata, &cseq->method, target, from, to, + contact, call_id, cseq, param_text); + } + PJ_DEFAULT { + status = PJ_ENOMEM; + goto on_error; + } + PJ_END; + + PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", + tdata->obj_name, + cseq->cseq, + cseq->method.name.slen, + cseq->method.name.ptr)); + + *p_tdata = tdata; + return PJ_SUCCESS; + +on_error: + pjsip_tx_data_dec_ref(tdata); + return status; +} + +/* + * Construct a minimal response message for the received request. + */ +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; + pj_status_t status; + + /* rdata must be a request message. */ + req_msg = rdata->msg_info.msg; + pj_assert(req_msg->type == PJSIP_REQUEST_MSG); + + /* Log this action. */ + PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", + rdata, code)); + + /* Create a new transmit buffer. */ + 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); + + /* Set status code and reason text. */ + msg->line.status.code = code; + msg->line.status.reason = *pjsip_get_status_text(code); + + /* Set TX data attributes. */ + tdata->rx_timestamp = rdata->pkt_info.timestamp; + + /* Copy all the via headers, in order. */ + via = rdata->msg_info.via; + while (via) { + pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via)); + via = via->next; + if (via != (void*)&req_msg->hdr) + via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via); + else + break; + } + + /* Copy all Record-Route headers, in order. */ + rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL); + while (rr) { + pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr)); + rr = rr->next; + if (rr != (void*)&req_msg->hdr) + rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr); + else + break; + } + + /* Copy Call-ID header. */ + hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL); + pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr)); + + /* Copy From header. */ + hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from); + pjsip_msg_add_hdr( msg, hdr); + + /* Copy To header. */ + hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to); + pjsip_msg_add_hdr( msg, hdr); + + /* Copy CSeq header. */ + hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq); + pjsip_msg_add_hdr( msg, hdr); + + /* All done. */ + *p_tdata = tdata; + return PJ_SUCCESS; +} + + +/* + * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of + * RFC3261). Note that the generation of ACK for 2xx response is different, + * and one must not use this function to generate such ACK. + */ +PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt, + pjsip_tx_data *tdata, + const pjsip_rx_data *rdata ) +{ + pjsip_msg *ack_msg, *invite_msg; + pjsip_to_hdr *to; + pjsip_from_hdr *from; + pjsip_cseq_hdr *cseq; + pjsip_hdr *hdr; + + /* Make compiler happy. */ + PJ_UNUSED_ARG(endpt); + + /* rdata must be a final response. */ + pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG && + rdata->msg_info.msg->line.status.code >= 300); + + /* Log this action. */ + 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); + pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD ); + + /* The original INVITE message. */ + invite_msg = tdata->msg; + + /* Copy Request-Uri from the original INVITE. */ + ack_msg->line.req.uri = invite_msg->line.req.uri; + + /* Copy Call-ID from the original INVITE */ + hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL); + pjsip_msg_add_hdr( ack_msg, hdr ); + + /* Copy From header from the original INVITE. */ + from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, + PJSIP_H_FROM, NULL); + pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from ); + + /* 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->msg_info.to->tag); + pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to ); + + /* Must contain single Via, just as the original INVITE. */ + hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL); + pjsip_msg_insert_first_hdr( ack_msg, hdr ); + + /* Must have the same CSeq value as the original INVITE, but method + * changed to ACK + */ + cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, + PJSIP_H_CSEQ, NULL); + pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD ); + pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq ); + + /* If the original INVITE has Route headers, those header fields MUST + * appear in the ACK. + */ + hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL); + while (hdr != NULL) { + pjsip_msg_add_hdr( ack_msg, hdr ); + hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL); + } + + /* Set the message in the "tdata" to point to the ACK message. */ + tdata->msg = ack_msg; + + /* Reset transmit packet buffer, to force 're-printing' of message. */ + tdata->buf.cur = tdata->buf.start; + + /* We're done. + * "tdata" parameter now contains the ACK message. + */ +} + + +/* + * Construct CANCEL request for the previously sent request, according to + * chapter 9.1 of RFC3261. + */ +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; + pj_status_t status; + + /* Log this action. */ + 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_RETURN(req_msg->type == PJSIP_REQUEST_MSG && + req_msg->line.req.method.id == PJSIP_INVITE_METHOD, + PJ_EINVAL); + + /* Create new transmit buffer. */ + status = pjsip_endpt_create_tdata( endpt, &cancel_tdata); + if (status != PJ_SUCCESS) { + return status; + } + + /* Create CANCEL request message. */ + cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG); + cancel_tdata->msg = cancel_msg; + + /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are + * copied from the original request. + */ + /* Set request line. */ + pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD); + req_uri = req_msg->line.req.uri; + cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri); + + /* Copy Call-ID */ + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL); + pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); + + /* Copy From header. */ + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL); + pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); + + /* Copy To header. */ + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL); + pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); + + /* Create new CSeq with equal number, but method set to CANCEL. */ + req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL); + cseq = pjsip_cseq_hdr_create(cancel_tdata->pool); + cseq->cseq = req_cseq->cseq; + pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD); + pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq); + + /* Must only have single Via which matches the top-most Via in the + * request being cancelled. + */ + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL); + pjsip_msg_insert_first_hdr(cancel_msg, + pjsip_hdr_clone(cancel_tdata->pool, hdr)); + + /* If the original request has Route header, the CANCEL request must also + * has exactly the same. + * Copy "Route" header from the request. + */ + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL); + while (hdr != NULL) { + pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr)); + hdr = hdr->next; + if (hdr != &cancel_msg->hdr) + hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr); + else + break; + } + + /* Done. + * Return the transmit buffer containing the CANCEL request. + */ + *p_tdata = cancel_tdata; + return PJ_SUCCESS; +} + +/* Get the address parameters (host, port, flag, TTL, etc) to send the + * response. + */ +PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool, + const pjsip_transport *req_transport, + const pjsip_via_hdr *via, + pjsip_host_port *send_addr) +{ + /* Determine the destination address (section 18.2.2): + * - for TCP, SCTP, or TLS, send the response using the transport where + * the request was received. + * - if maddr parameter is present, send to this address using the port + * in sent-by or 5060. If multicast is used, the TTL in the Via must + * be used, or 1 if ttl parameter is not present. + * - otherwise if received parameter is present, set to this address. + * - otherwise send to the address in sent-by. + */ + send_addr->flag = req_transport->flag; + send_addr->type = req_transport->type; + + if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) { + const pj_sockaddr_in *remote_addr; + remote_addr = &req_transport->rem_addr; + pj_strdup2(pool, &send_addr->host, + pj_inet_ntoa(remote_addr->sin_addr)); + send_addr->port = pj_sockaddr_in_get_port(remote_addr); + + } else { + /* Set the host part */ + if (via->maddr_param.slen) { + pj_strdup(pool, &send_addr->host, &via->maddr_param); + } else if (via->recvd_param.slen) { + pj_strdup(pool, &send_addr->host, &via->recvd_param); + } else { + pj_strdup(pool, &send_addr->host, &via->sent_by.host); + } + + /* Set the port */ + send_addr->port = via->sent_by.port; + } + + return PJ_SUCCESS; +} + +/* + * Get the event string from the event ID. + */ +PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e) +{ + return event_str[e]; +} + diff --git a/pjsip/src/test-pjsip/main.c b/pjsip/src/test-pjsip/main.c index 75b3792e..3c819be8 100644 --- a/pjsip/src/test-pjsip/main.c +++ b/pjsip/src/test-pjsip/main.c @@ -16,3 +16,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "test.h" + +int main(void) +{ + return test_main(); +} diff --git a/pjsip/src/test-pjsip/msg.c b/pjsip/src/test-pjsip/msg.c new file mode 100644 index 00000000..b546a756 --- /dev/null +++ b/pjsip/src/test-pjsip/msg.c @@ -0,0 +1,369 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include +#include + +static pjsip_msg *create_msg0(pj_pool_t *pool); + +struct test_msg +{ + char msg[1024]; + pjsip_msg *(*creator)(pj_pool_t *pool); + pj_size_t len; +} test_array[] = +{ + { + /* 'Normal' message with all headers. */ + "INVITE sip:user@foo SIP/2.0\n" + "From: Hi I'm Joe ;tag=1234578901234567890\r" + "To: Fellow User \r\n" + "Call-ID: 12345678901234567890@bar\r\n" + "Content-Length: 0\r\n" + "CSeq: 123456 INVITE\n" + "Contact: ; q=0.5;expires=3600,sip:user@host;q=0.500\r" + " ,sip:user2@host2\n" + "Content-Type: text/html ; charset=ISO-8859-4\r" + "Route: ,\r\n" + " \r" + "Record-Route: ,\r\n" + " \n" + "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" + "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" + " ;received=192.0.2.1\r\n" + "Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n" + "Organization: \r" + "Max-Forwards: 70\n" + "X-Header: \r\n" + "\r", + &create_msg0 + } +}; + +static pj_uint32_t parse_len, parse_time, print_time; + +static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) +{ + pjsip_msg *parsed_msg, *ref_msg; + pj_status_t status = PJ_SUCCESS; + int len; + pj_str_t str1, str2; + pjsip_hdr *hdr1, *hdr2; + pj_timestamp t1, t2; + char *msgbuf; + + enum { BUFLEN = 512 }; + + /* Parse message. */ + parse_len += entry->len; + pj_get_timestamp(&t1); + parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL); + if (parsed_msg == NULL) { + status = -10; + goto on_return; + } + pj_get_timestamp(&t2); + parse_time += t2.u32.lo - t1.u32.lo; + + /* Create reference message. */ + ref_msg = entry->creator(pool); + + /* Create buffer for comparison. */ + str1.ptr = pj_pool_alloc(pool, BUFLEN); + str2.ptr = pj_pool_alloc(pool, BUFLEN); + + /* Compare message type. */ + if (parsed_msg->type != ref_msg->type) { + status = -20; + goto on_return; + } + + /* Compare request or status line. */ + if (parsed_msg->type == PJSIP_REQUEST_MSG) { + pjsip_method *m1 = &parsed_msg->line.req.method; + pjsip_method *m2 = &ref_msg->line.req.method; + + if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) { + status = -30; + goto on_return; + } + } else { + + } + + /* Compare headers. */ + hdr1 = parsed_msg->hdr.next; + hdr2 = ref_msg->hdr.next; + + while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) { + len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN); + if (len < 1) { + status = -40; + goto on_return; + } + str1.slen = len; + + len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN); + if (len < 1) { + status = -50; + goto on_return; + } + str2.slen = len; + + if (pj_strcmp(&str1, &str2) != 0) { + status = -60; + goto on_return; + } + + hdr1 = hdr1->next; + hdr2 = hdr2->next; + } + + if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) { + status = -70; + goto on_return; + } + + /* Print message. */ + msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN); + if (msgbuf == NULL) { + status = -80; + goto on_return; + } + pj_get_timestamp(&t1); + len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN); + if (len < 1) { + status = -90; + goto on_return; + } + pj_get_timestamp(&t2); + print_time += t2.u32.lo - t1.u32.lo; + status = PJ_SUCCESS; + +on_return: + return status; +} + + +pj_status_t msg_test(void) +{ + pj_status_t status; + pj_pool_t *pool; + + pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); + + status = test_entry( pool, &test_array[0] ); + + pjsip_endpt_destroy(endpt); + return status; +} + +/*****************************************************************************/ + +static pjsip_msg *create_msg0(pj_pool_t *pool) +{ + + pjsip_msg *msg; + pjsip_name_addr *name_addr; + pjsip_url *url; + pjsip_fromto_hdr *fromto; + pjsip_cid_hdr *cid; + pjsip_clen_hdr *clen; + pjsip_cseq_hdr *cseq; + pjsip_contact_hdr *contact; + pjsip_ctype_hdr *ctype; + pjsip_routing_hdr *routing; + pjsip_via_hdr *via; + pjsip_generic_string_hdr *generic; + pj_str_t str; + + msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG); + + /* "INVITE sip:user@foo SIP/2.0\n" */ + pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD); + url = pjsip_url_create(pool, 0); + msg->line.req.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "foo"); + + /* "From: Hi I'm Joe ;tag=1234578901234567890\r" */ + fromto = pjsip_from_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); + pj_strdup2(pool, &fromto->tag, "1234578901234567890"); + name_addr = pjsip_name_addr_create(pool); + fromto->uri = (pjsip_uri*)name_addr; + pj_strdup2(pool, &name_addr->display, "Hi I'm Joe"); + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "joe.user"); + pj_strdup2(pool, &url->host, "bar.otherdomain.com"); + + /* "To: Fellow User \r\n" */ + fromto = pjsip_to_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); + name_addr = pjsip_name_addr_create(pool); + fromto->uri = (pjsip_uri*)name_addr; + pj_strdup2(pool, &name_addr->display, "Fellow User"); + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "foo.bar.domain.com"); + + /* "Call-ID: 12345678901234567890@bar\r\n" */ + cid = pjsip_cid_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); + pj_strdup2(pool, &cid->id, "12345678901234567890@bar"); + + /* "Content-Length: 0\r\n" */ + clen = pjsip_clen_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); + clen->len = 0; + + /* "CSeq: 123456 INVITE\n" */ + cseq = pjsip_cseq_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); + cseq->cseq = 123456; + pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); + + /* "Contact: ;q=0.5;expires=3600*/ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + contact->q1000 = 500; + contact->expires = 3600; + name_addr = pjsip_name_addr_create(pool); + contact->uri = (pjsip_uri*)name_addr; + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "joe"); + pj_strdup2(pool, &url->host, "bar"); + + /*, sip:user@host;q=0.500\r" */ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + contact->q1000 = 500; + url = pjsip_url_create(pool, 0); + contact->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "host"); + + /* " ,sip:user2@host2\n" */ + contact = pjsip_contact_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); + url = pjsip_url_create(pool, 0); + contact->uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->user, "user2"); + pj_strdup2(pool, &url->host, "host2"); + + /* "Content-Type: text/html; charset=ISO-8859-4\r" */ + ctype = pjsip_ctype_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); + pj_strdup2(pool, &ctype->media.type, "text"); + pj_strdup2(pool, &ctype->media.subtype, "html"); + pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4"); + + /* "Route: ,\r\n" */ + routing = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_url_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); + url->lr_param = 1; + + /* " \r" */ + routing = pjsip_route_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_url_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "server10.biloxi.com"); + url->lr_param = 1; + + /* "Record-Route: ,\r\n" */ + routing = pjsip_rr_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_url_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "server10.biloxi.com"); + url->lr_param = 0; + + /* " \n" */ + routing = pjsip_rr_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); + url = pjsip_url_create(pool, 0); + routing->name_addr.uri = (pjsip_uri*)url; + pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); + url->lr_param = 1; + + /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "SCTP"); + pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com"); + pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1"); + + /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" + " ;received=192.0.2.1\r\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "UDP"); + pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com"); + pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8"); + pj_strdup2(pool, &via->recvd_param, "192.0.2.1"); + + + /* "Via: SIP/2.0/UDP 10.2.1.1, */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "UDP"); + pj_strdup2(pool, &via->sent_by.host, "10.2.1.1"); + + + /*SIP/2.0/TCP 192.168.1.1\n" */ + via = pjsip_via_hdr_create(pool); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); + pj_strdup2(pool, &via->transport, "TCP"); + pj_strdup2(pool, &via->sent_by.host, "192.168.1.1"); + + /* "Organization: \r" */ + str.ptr = "Organization"; + str.slen = 12; + generic = pjsip_generic_string_hdr_create(pool, &str); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + generic->hvalue.ptr = NULL; + generic->hvalue.slen = 0; + + /* "Max-Forwards: 70\n" */ + str.ptr = "Max-Forwards"; + str.slen = 12; + generic = pjsip_generic_string_hdr_create(pool, &str); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + str.ptr = "70"; + str.slen = 2; + generic->hvalue = str; + + /* "X-Header: \r\n" */ + str.ptr = "X-Header"; + str.slen = 8; + generic = pjsip_generic_string_hdr_create(pool, &str); + pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); + str.ptr = NULL; + str.slen = 0; + generic->hvalue = str; + + return msg; +} diff --git a/pjsip/src/test-pjsip/parse_msg.c b/pjsip/src/test-pjsip/parse_msg.c deleted file mode 100644 index 94ac25ce..00000000 --- a/pjsip/src/test-pjsip/parse_msg.c +++ /dev/null @@ -1,440 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 Benny Prijono - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include "test.h" - -#define ERR_SYNTAX_ERR (-2) -#define ERR_NOT_EQUAL (-3) -#define ERR_SYSTEM (-4) - - -static pjsip_msg *create_msg0(pj_pool_t *pool); - -struct test_msg -{ - char msg[1024]; - pjsip_msg *(*creator)(pj_pool_t *pool); - pj_size_t len; -} test_array[] = -{ - { - /* 'Normal' message with all headers. */ - "INVITE sip:user@foo SIP/2.0\n" - "From: Hi I'm Joe ;tag=1234578901234567890\r" - "To: Fellow User \r\n" - "Call-ID: 12345678901234567890@bar\r\n" - "Content-Length: 0\r\n" - "CSeq: 123456 INVITE\n" - "Contact: ; q=0.5;expires=3600,sip:user@host;q=0.500\r" - " ,sip:user2@host2\n" - "Content-Type: text/html ; charset=ISO-8859-4\r" - "Route: ,\r\n" - " \r" - "Record-Route: ,\r\n" - " \n" - "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" - "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" - " ;received=192.0.2.1\r\n" - "Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n" - "Organization: \r" - "Max-Forwards: 70\n" - "X-Header: \r\n" - "\r", - &create_msg0 - } -}; - -static pj_caching_pool cp; -static pj_pool_factory *pf = &cp.factory; -static pj_uint32_t parse_len, parse_time, print_time; - -static void pool_error(pj_pool_t *pool, pj_size_t sz) -{ - PJ_UNUSED_ARG(pool) - PJ_UNUSED_ARG(sz) - - pj_assert(0); - exit(1); -} - -static const char *STATUS_STR(pj_status_t status) -{ - switch (status) { - case 0: return "OK"; - case ERR_SYNTAX_ERR: return "Syntax Error"; - case ERR_NOT_EQUAL: return "Not Equal"; - case ERR_SYSTEM: return "System Error"; - } - return "???"; -} - -static pj_status_t test_entry( struct test_msg *entry ) -{ - pjsip_msg *parsed_msg, *ref_msg; - pj_pool_t *pool; - pj_status_t status = PJ_SUCCESS; - int len; - pj_str_t str1, str2; - pjsip_hdr *hdr1, *hdr2; - pj_hr_timestamp t1, t2; - char *msgbuf; - - enum { BUFLEN = 512 }; - - pool = pj_pool_create( pf, "", - PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, - &pool_error); - - if (entry->len == 0) { - entry->len = strlen(entry->msg); - } - - /* Parse message. */ - parse_len += entry->len; - pj_hr_gettimestamp(&t1); - parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL); - if (parsed_msg == NULL) { - status = ERR_SYNTAX_ERR; - goto on_return; - } - pj_hr_gettimestamp(&t2); - parse_time += t2.u32.lo - t1.u32.lo; - -#if IS_PROFILING - goto print_msg; -#endif - - /* Create reference message. */ - ref_msg = entry->creator(pool); - - /* Create buffer for comparison. */ - str1.ptr = pj_pool_alloc(pool, BUFLEN); - str2.ptr = pj_pool_alloc(pool, BUFLEN); - - /* Compare message type. */ - if (parsed_msg->type != ref_msg->type) { - status = ERR_NOT_EQUAL; - goto on_return; - } - - /* Compare request or status line. */ - if (parsed_msg->type == PJSIP_REQUEST_MSG) { - pjsip_method *m1 = &parsed_msg->line.req.method; - pjsip_method *m2 = &ref_msg->line.req.method; - - if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) { - status = ERR_NOT_EQUAL; - goto on_return; - } - } else { - - } - - /* Compare headers. */ - hdr1 = parsed_msg->hdr.next; - hdr2 = ref_msg->hdr.next; - - while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) { - len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN); - if (len < 1) { - status = ERR_SYSTEM; - goto on_return; - } - str1.slen = len; - - len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN); - if (len < 1) { - status = ERR_SYSTEM; - goto on_return; - } - str2.slen = len; - - if (!SILENT) { - printf("hdr1='%.*s'\n" - "hdr2='%.*s'\n\n", - str1.slen, str1.ptr, - str2.slen, str2.ptr); - } - if (pj_strcmp(&str1, &str2) != 0) { - status = ERR_NOT_EQUAL; - goto on_return; - } - - hdr1 = hdr1->next; - hdr2 = hdr2->next; - } - - if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) { - status = ERR_NOT_EQUAL; - goto on_return; - } - - /* Print message. */ -#if IS_PROFILING -print_msg: -#endif - msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN); - if (msgbuf == NULL) { - status = ERR_SYSTEM; - goto on_return; - } - pj_hr_gettimestamp(&t1); - len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN); - if (len < 1) { - status = ERR_SYSTEM; - goto on_return; - } - pj_hr_gettimestamp(&t2); - print_time += t2.u32.lo - t1.u32.lo; - status = PJ_SUCCESS; - -on_return: - pj_pool_release(pool); - return status; -} - -static void warm_up() -{ - pj_pool_t *pool; - pool = pj_pool_create( pf, "", - PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, - &pool_error); - pj_pool_release(pool); -} - - -pj_status_t test_msg(void) -{ - pj_status_t status; - unsigned i; - - pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); - warm_up(); - - for (i=0; iline.req.method, PJSIP_INVITE_METHOD); - url = pjsip_url_create(pool, 0); - msg->line.req.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "foo"); - - /* "From: Hi I'm Joe ;tag=1234578901234567890\r" */ - fromto = pjsip_from_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); - pj_strdup2(pool, &fromto->tag, "1234578901234567890"); - name_addr = pjsip_name_addr_create(pool); - fromto->uri = (pjsip_uri*)name_addr; - pj_strdup2(pool, &name_addr->display, "Hi I'm Joe"); - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "joe.user"); - pj_strdup2(pool, &url->host, "bar.otherdomain.com"); - - /* "To: Fellow User \r\n" */ - fromto = pjsip_to_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto); - name_addr = pjsip_name_addr_create(pool); - fromto->uri = (pjsip_uri*)name_addr; - pj_strdup2(pool, &name_addr->display, "Fellow User"); - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "foo.bar.domain.com"); - - /* "Call-ID: 12345678901234567890@bar\r\n" */ - cid = pjsip_cid_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid); - pj_strdup2(pool, &cid->id, "12345678901234567890@bar"); - - /* "Content-Length: 0\r\n" */ - clen = pjsip_clen_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen); - clen->len = 0; - - /* "CSeq: 123456 INVITE\n" */ - cseq = pjsip_cseq_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq); - cseq->cseq = 123456; - pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD); - - /* "Contact: ;q=0.5;expires=3600*/ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - contact->q1000 = 500; - contact->expires = 3600; - name_addr = pjsip_name_addr_create(pool); - contact->uri = (pjsip_uri*)name_addr; - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "joe"); - pj_strdup2(pool, &url->host, "bar"); - - /*, sip:user@host;q=0.500\r" */ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - contact->q1000 = 500; - url = pjsip_url_create(pool, 0); - contact->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "host"); - - /* " ,sip:user2@host2\n" */ - contact = pjsip_contact_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact); - url = pjsip_url_create(pool, 0); - contact->uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->user, "user2"); - pj_strdup2(pool, &url->host, "host2"); - - /* "Content-Type: text/html; charset=ISO-8859-4\r" */ - ctype = pjsip_ctype_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype); - pj_strdup2(pool, &ctype->media.type, "text"); - pj_strdup2(pool, &ctype->media.subtype, "html"); - pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4"); - - /* "Route: ,\r\n" */ - routing = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_url_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); - url->lr_param = 1; - - /* " \r" */ - routing = pjsip_route_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_url_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "server10.biloxi.com"); - url->lr_param = 1; - - /* "Record-Route: ,\r\n" */ - routing = pjsip_rr_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_url_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "server10.biloxi.com"); - url->lr_param = 0; - - /* " \n" */ - routing = pjsip_rr_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing); - url = pjsip_url_create(pool, 0); - routing->name_addr.uri = (pjsip_uri*)url; - pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com"); - url->lr_param = 1; - - /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "SCTP"); - pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com"); - pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1"); - - /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n" - " ;received=192.0.2.1\r\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "UDP"); - pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com"); - pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8"); - pj_strdup2(pool, &via->recvd_param, "192.0.2.1"); - - - /* "Via: SIP/2.0/UDP 10.2.1.1, */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "UDP"); - pj_strdup2(pool, &via->sent_by.host, "10.2.1.1"); - - - /*SIP/2.0/TCP 192.168.1.1\n" */ - via = pjsip_via_hdr_create(pool); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)via); - pj_strdup2(pool, &via->transport, "TCP"); - pj_strdup2(pool, &via->sent_by.host, "192.168.1.1"); - - /* "Organization: \r" */ - str.ptr = "Organization"; - str.slen = 12; - generic = pjsip_generic_string_hdr_create(pool, &str); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - generic->hvalue.ptr = NULL; - generic->hvalue.slen = 0; - - /* "Max-Forwards: 70\n" */ - str.ptr = "Max-Forwards"; - str.slen = 12; - generic = pjsip_generic_string_hdr_create(pool, &str); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - str.ptr = "70"; - str.slen = 2; - generic->hvalue = str; - - /* "X-Header: \r\n" */ - str.ptr = "X-Header"; - str.slen = 8; - generic = pjsip_generic_string_hdr_create(pool, &str); - pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic); - str.ptr = NULL; - str.slen = 0; - generic->hvalue = str; - - return msg; -} diff --git a/pjsip/src/test-pjsip/parse_uri.c b/pjsip/src/test-pjsip/parse_uri.c deleted file mode 100644 index cfb3afd7..00000000 --- a/pjsip/src/test-pjsip/parse_uri.c +++ /dev/null @@ -1,660 +0,0 @@ -/* $Id$ */ -/* - * Copyright (C) 2003-2006 Benny Prijono - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include "test.h" - -#define ERR_SYNTAX_ERR (-2) -#define ERR_NOT_EQUAL (-3) - -#define ALPHANUM "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - "0123456789" -#define MARK "-_.!~*'()" -#define USER "&=+$,;?/%" -#define PASS "&=+$,%" -#define PARAM_CHAR "[]/:&+$" MARK "%" - -#define POOL_SIZE 4096 - -static const char *STATUS_STR(pj_status_t status) -{ - switch (status) { - case 0: return "OK"; - case ERR_SYNTAX_ERR: return "Syntax Error"; - case ERR_NOT_EQUAL: return "Not Equal"; - } - return "???"; -} - -static pj_uint32_t parse_len, parse_time, print_time; -static pj_caching_pool cp; - - -/* URI creator functions. */ -static pjsip_uri *create_uri1( pj_pool_t *pool ); -static pjsip_uri *create_uri2( pj_pool_t *pool ); -static pjsip_uri *create_uri3( pj_pool_t *pool ); -static pjsip_uri *create_uri4( pj_pool_t *pool ); -static pjsip_uri *create_uri5( pj_pool_t *pool ); -static pjsip_uri *create_uri6( pj_pool_t *pool ); -static pjsip_uri *create_uri7( pj_pool_t *pool ); -static pjsip_uri *create_uri8( pj_pool_t *pool ); -static pjsip_uri *create_uri9( pj_pool_t *pool ); -static pjsip_uri *create_uri10( pj_pool_t *pool ); -static pjsip_uri *create_uri11( pj_pool_t *pool ); -static pjsip_uri *create_uri12( pj_pool_t *pool ); -static pjsip_uri *create_uri13( pj_pool_t *pool ); -static pjsip_uri *create_uri14( pj_pool_t *pool ); -static pjsip_uri *create_uri15( pj_pool_t *pool ); -static pjsip_uri *create_uri16( pj_pool_t *pool ); -static pjsip_uri *create_uri17( pj_pool_t *pool ); -static pjsip_uri *create_uri18( pj_pool_t *pool ); -static pjsip_uri *create_uri19( pj_pool_t *pool ); -static pjsip_uri *create_dummy( pj_pool_t *pool ); - -struct uri_test -{ - pj_status_t status; - char str[PJSIP_MAX_URL_SIZE]; - pjsip_uri *(*creator)(pj_pool_t *pool); - pj_size_t len; -} uri_test_array[] = -{ - { - PJ_SUCCESS, - "sip:localhost", - &create_uri1 - }, - { - PJ_SUCCESS, - "sip:user@localhost", - &create_uri2 - }, - { - PJ_SUCCESS, - "sip:user:password@localhost:5060", - &create_uri3, - }, - { - /* Port is specified should not match unspecified port. */ - ERR_NOT_EQUAL, - "sip:localhost:5060", - &create_uri4 - }, - { - /* All recognized parameters. */ - PJ_SUCCESS, - "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK", - &create_uri5 - }, - { - /* Params mixed with other params and header params. */ - PJ_SUCCESS, - "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" - "?Subject=Hello%20There&Server=SIP%20Server", - &create_uri6 - }, - { - /* SIPS. */ - PJ_SUCCESS, - "sips:localhost", - &create_uri7, - }, - { - /* Name address */ - PJ_SUCCESS, - "", - &create_uri8 - }, - { - /* Name address with display name and SIPS scheme with some redundant - * whitespaced. - */ - PJ_SUCCESS, - " Power Administrator ", - &create_uri9 - }, - { - /* Name address. */ - PJ_SUCCESS, - " \"User\" ", - &create_uri10 - }, - { - /* Escaped sequence in display name (display=Strange User\"\\\"). */ - PJ_SUCCESS, - " \"Strange User\\\"\\\\\\\"\" ", - &create_uri11, - }, - { - /* Errorneous escaping in display name. */ - ERR_SYNTAX_ERR, - " \"Rogue User\\\" ", - &create_uri12, - }, - { - /* Dangling quote in display name, but that should be OK. */ - PJ_SUCCESS, - "Strange User\" ", - &create_uri13, - }, - { - /* Special characters in parameter value must be quoted. */ - PJ_SUCCESS, - "sip:localhost;pvalue=\"hello world\"", - &create_uri14, - }, - { - /* Excercise strange character sets allowed in display, user, password, - * host, and port. - */ - PJ_SUCCESS, - "This is -. !% *_+`'~ me ", - &create_uri15, - }, - { - /* Another excercise to the allowed character sets to the hostname. */ - PJ_SUCCESS, - "sip:" ALPHANUM "-_.com", - &create_uri16, - }, - { - /* Another excercise to the allowed character sets to the username - * and password. - */ - PJ_SUCCESS, - "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host", - &create_uri17, - }, - { - /* Excercise to the pname and pvalue, and mixup of other-param - * between 'recognized' params. - */ - PJ_SUCCESS, - "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR - ";lr;other=1;transport=sctp;other2", - &create_uri18, - }, - { - /* This should trigger syntax error. */ - ERR_SYNTAX_ERR, - "sip:", - &create_dummy, - }, - { - /* Syntax error: whitespace after scheme. */ - ERR_SYNTAX_ERR, - "sip :host", - &create_dummy, - }, - { - /* Syntax error: whitespace before hostname. */ - ERR_SYNTAX_ERR, - "sip: host", - &create_dummy, - }, - { - /* Syntax error: invalid port. */ - ERR_SYNTAX_ERR, - "sip:user:password", - &create_dummy, - }, - { - /* Syntax error: no host. */ - ERR_SYNTAX_ERR, - "sip:user@", - &create_dummy, - }, - { - /* Syntax error: no user/host. */ - ERR_SYNTAX_ERR, - "sip:@", - &create_dummy, - }, - { - /* Syntax error: empty string. */ - ERR_SYNTAX_ERR, - "", - &create_dummy, - }, - { - PJ_SUCCESS, - "", - NULL, - }, -}; - -static pjsip_uri *create_uri1(pj_pool_t *pool) -{ - /* "sip:localhost" */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri2(pj_pool_t *pool) -{ - /* "sip:user@localhost" */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2( pool, &url->user, "user"); - pj_strdup2( pool, &url->host, "localhost"); - - return (pjsip_uri*) url; -} - -static pjsip_uri *create_uri3(pj_pool_t *pool) -{ - /* "sip:user:password@localhost:5060" */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2( pool, &url->user, "user"); - pj_strdup2( pool, &url->passwd, "password"); - pj_strdup2( pool, &url->host, "localhost"); - url->port = 5060; - - return (pjsip_uri*) url; -} - -static pjsip_uri *create_uri4(pj_pool_t *pool) -{ - /* Like: "sip:localhost:5060", but without the port. */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri5(pj_pool_t *pool) -{ - /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - pj_strdup2(pool, &url->transport_param, "tcp"); - pj_strdup2(pool, &url->user_param, "ip"); - url->ttl_param = 255; - url->lr_param = 1; - pj_strdup2(pool, &url->maddr_param, "127.0.0.1"); - pj_strdup2(pool, &url->method_param, "ACK"); - - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri6(pj_pool_t *pool) -{ - /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" - "?Subject=Hello%20There&Server=SIP%20Server" - */ - pjsip_url *url = pjsip_url_create(pool, 0); - - pj_strdup2(pool, &url->host, "localhost"); - pj_strdup2(pool, &url->user_param, "phone"); - pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry"); - pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server"); - return (pjsip_uri*)url; - -} - -static pjsip_uri *create_uri7(pj_pool_t *pool) -{ - /* "sips:localhost" */ - pjsip_url *url = pjsip_url_create(pool, 1); - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri8(pj_pool_t *pool) -{ - /* "" */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri9(pj_pool_t *pool) -{ - /* " Power Administrator " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 1); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Power Administrator"); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri10(pj_pool_t *pool) -{ - /* " \"User\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "\"User\""); - pj_strdup2(pool, &url->user, "user"); - pj_strdup2(pool, &url->host, "localhost"); - url->port = 5071; - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri11(pj_pool_t *pool) -{ - /* " \"Strange User\\\"\\\\\\\"\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\""); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri12(pj_pool_t *pool) -{ - /* " \"Rogue User\\\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\""); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri13(pj_pool_t *pool) -{ - /* "Strange User\" " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "Strange User\""); - pj_strdup2(pool, &url->host, "localhost"); - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri14(pj_pool_t *pool) -{ - /* "sip:localhost;pvalue=\"hello world\"" */ - pjsip_url *url; - url = pjsip_url_create(pool, 0); - pj_strdup2(pool, &url->host, "localhost"); - pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\""); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri15(pj_pool_t *pool) -{ - /* "This is -. !% *_+`'~ me " */ - pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); - pjsip_url *url; - - url = pjsip_url_create(pool, 0); - name_addr->uri = (pjsip_uri*) url; - - pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me"); - pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c"); - pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,"); - pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com"); - url->port = 9801; - return (pjsip_uri*)name_addr; -} - -static pjsip_uri *create_uri16(pj_pool_t *pool) -{ - /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */ - pjsip_url *url; - url = pjsip_url_create(pool, 0); - pj_strdup2(pool, &url->host, ALPHANUM "-_.com"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri17(pj_pool_t *pool) -{ - /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */ - pjsip_url *url; - url = pjsip_url_create(pool, 0); - pj_strdup2(pool, &url->user, ALPHANUM USER); - pj_strdup2(pool, &url->passwd, ALPHANUM PASS); - pj_strdup2(pool, &url->host, "host"); - return (pjsip_uri*)url; -} - -static pjsip_uri *create_uri18(pj_pool_t *pool) -{ - /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */ - pjsip_url *url; - url = pjsip_url_create(pool, 0); - pj_strdup2(pool, &url->host, "host"); - pj_strdup2(pool, &url->user_param, "ip"); - pj_strdup2(pool, &url->transport_param, "sctp"); - pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2"); - url->lr_param = 1; - return (pjsip_uri*)url; -} - -static pjsip_uri *create_dummy(pj_pool_t *pool) -{ - PJ_UNUSED_ARG(pool) - return NULL; -} - -/*****************************************************************************/ - -static void pool_error(pj_pool_t *pool, pj_size_t sz) -{ - PJ_UNUSED_ARG(pool) - PJ_UNUSED_ARG(sz) - - pj_assert(0); - exit(1); -} - -/* - * Test one test entry. - */ -static pj_status_t test_entry(struct uri_test *entry) -{ - pj_status_t status; - pj_pool_t *pool; - int len; - pjsip_uri *parsed_uri, *ref_uri; - pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0}; - pj_hr_timestamp t1, t2; - - pool = (*cp.factory.create_pool)( &cp.factory, "", POOL_SIZE, 0, &pool_error); - - /* Parse URI text. */ - pj_hr_gettimestamp(&t1); - parse_len += entry->len; - parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0); - if (!parsed_uri) { - /* Parsing failed. If the entry says that this is expected, then - * return OK. - */ - status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : ERR_SYNTAX_ERR; - goto on_return; - } - pj_hr_gettimestamp(&t2); - parse_time += t2.u32.lo - t1.u32.lo; - - /* Create the reference URI. */ - ref_uri = entry->creator(pool); - - /* Print both URI. */ - s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); - s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); - - pj_hr_gettimestamp(&t1); - len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE); - if (len < 1) { - status = -1; - goto on_return; - } - s1.slen = len; - - len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); - if (len < 1) { - status = -1; - goto on_return; - } - s2.slen = len; - pj_hr_gettimestamp(&t2); - print_time += t2.u32.lo - t1.u32.lo; - - /* Full comparison of parsed URI with reference URI. */ - if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) { - /* Not equal. See if this is the expected status. */ - status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : ERR_NOT_EQUAL; - goto on_return; - - } else { - /* Equal. See if this is the expected status. */ - status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -1; - if (status != PJ_SUCCESS) { - goto on_return; - } - } - - /* Compare text. */ - if (pj_strcmp(&s1, &s2) != 0) { - /* Not equal. */ - status = ERR_NOT_EQUAL; - } - -on_return: - if (!SILENT) { - printf("%.2d %s (expected status=%s)\n" - " str=%s\n" - " uri=%.*s\n" - " ref=%.*s\n\n", - entry-uri_test_array, - STATUS_STR(status), - STATUS_STR(entry->status), - entry->str, - (int)s1.slen, s1.ptr, (int)s2.slen, s2.ptr); - } - - pj_pool_release(pool); - return status; -} - -static void warm_up(pj_pool_factory *pf) -{ - pj_pool_t *pool; - struct uri_test *entry; - - pool = pj_pool_create(pf, "", POOL_SIZE, 0, &pool_error); - pjsip_parse_uri(pool, "sip:host", 8, 0); - entry = &uri_test_array[0]; - while (entry->creator) { - entry->len = strlen(entry->str); - ++entry; - } - pj_pool_release(pool); -} - -//#if !IS_PROFILING -#if 1 -pj_status_t test_uri() -{ - struct uri_test *entry; - int i=0, err=0; - pj_status_t status; - pj_hr_timestamp t1, t2; - pj_uint32_t total_time; - - pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); - warm_up(&cp.factory); - - pj_hr_gettimestamp(&t1); - for (i=0; icreator) { - status = test_entry(entry); - if (status != PJ_SUCCESS) { - ++err; - } - ++entry; - } - } - pj_hr_gettimestamp(&t2); - total_time = t2.u32.lo - t1.u32.lo; - - printf("Error=%d\n", err); - printf("Total parse len: %u bytes\n", parse_len); - printf("Total parse time: %u (%f/char), print time: %u (%f/char)\n", - parse_time, parse_time*1.0/parse_len, - print_time, print_time*1.0/parse_len); - printf("Total time: %u (%f/char)\n", total_time, total_time*1.0/parse_len); - return err; -} - -#else - -pj_status_t test_uri() -{ - struct uri_test *entry; - unsigned i; - - warm_up(); - pj_caching_pool_init(&cp, 1024*1024); - - for (i=0; icreator) { - pj_pool_t *pool; - pjsip_uri *uri1, *uri2; - - pool = pj_pool_create( &cp.factory, "", POOL_SIZE, 0, &pool_error); - uri1 = pjsip_parse_uri(pool, entry->str, strlen(entry->str)); - pj_pool_release(pool); - ++entry; - } - } - - return 0; -} - -#endif diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c index 4a69b582..80d08881 100644 --- a/pjsip/src/test-pjsip/test.c +++ b/pjsip/src/test-pjsip/test.c @@ -46,20 +46,59 @@ void app_perror(const char *msg, pj_status_t rc) } +pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) +{ + *count = 0; + return PJ_SUCCESS; +} - -int main() +int test_main(void) { pj_status_t rc; + pj_caching_pool caching_pool; + const char *filename; + int line; + + pj_log_set_level(3); + pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | + PJ_LOG_HAS_MICRO_SEC); if ((rc=pj_init()) != PJ_SUCCESS) { app_perror("pj_init", rc); + return rc; + } + + pj_dump_config(); + + pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); + + rc = pjsip_endpt_create(&caching_pool.factory, "endpt", &endpt); + if (rc != PJ_SUCCESS) { + app_perror("pjsip_endpt_create", rc); + pj_caching_pool_destroy(&caching_pool); + return rc; } - DO_TEST(parse_uri()); - DO_TEST(parse_msg()); + PJ_LOG(3,("","")); + + DO_TEST(uri_test()); on_return: + + pjsip_endpt_destroy(endpt); + pj_caching_pool_destroy(&caching_pool); + + PJ_LOG(3,("test", "")); + + pj_thread_get_stack_info(pj_thread_this(), &filename, &line); + PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", + pj_thread_get_stack_max_usage(pj_thread_this()), + filename, line)); + if (rc == 0) + PJ_LOG(3,("test", "Looks like everything is okay!..")); + else + PJ_LOG(3,("test", "Test completed with error(s)")); + return 0; } diff --git a/pjsip/src/test-pjsip/test.h b/pjsip/src/test-pjsip/test.h index 225c8be7..60b67c5e 100644 --- a/pjsip/src/test-pjsip/test.h +++ b/pjsip/src/test-pjsip/test.h @@ -21,15 +21,12 @@ #include -#define SILENT 1 -#define IS_PROFILING 1 -#define LOOP 2000 - extern pjsip_endpoint *endpt; -pj_status_t parse_uri(void); -pj_status_t parse_msg(void); +pj_status_t uri_test(void); +pj_status_t msg_test(void); +int test_main(void); void app_perror(const char *msg, pj_status_t status); diff --git a/pjsip/src/test-pjsip/uri.c b/pjsip/src/test-pjsip/uri.c new file mode 100644 index 00000000..a61382f0 --- /dev/null +++ b/pjsip/src/test-pjsip/uri.c @@ -0,0 +1,560 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include +#include + + +#define ALPHANUM "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "0123456789" +#define MARK "-_.!~*'()" +#define USER "&=+$,;?/%" +#define PASS "&=+$,%" +#define PARAM_CHAR "[]/:&+$" MARK "%" + +#define POOL_SIZE 4096 + +static pj_uint32_t parse_len, parse_time, print_time; + + +/* URI creator functions. */ +static pjsip_uri *create_uri1( pj_pool_t *pool ); +static pjsip_uri *create_uri2( pj_pool_t *pool ); +static pjsip_uri *create_uri3( pj_pool_t *pool ); +static pjsip_uri *create_uri4( pj_pool_t *pool ); +static pjsip_uri *create_uri5( pj_pool_t *pool ); +static pjsip_uri *create_uri6( pj_pool_t *pool ); +static pjsip_uri *create_uri7( pj_pool_t *pool ); +static pjsip_uri *create_uri8( pj_pool_t *pool ); +static pjsip_uri *create_uri9( pj_pool_t *pool ); +static pjsip_uri *create_uri10( pj_pool_t *pool ); +static pjsip_uri *create_uri11( pj_pool_t *pool ); +static pjsip_uri *create_uri12( pj_pool_t *pool ); +static pjsip_uri *create_uri13( pj_pool_t *pool ); +static pjsip_uri *create_uri14( pj_pool_t *pool ); +static pjsip_uri *create_uri15( pj_pool_t *pool ); +static pjsip_uri *create_uri16( pj_pool_t *pool ); +static pjsip_uri *create_uri17( pj_pool_t *pool ); +static pjsip_uri *create_uri18( pj_pool_t *pool ); +static pjsip_uri *create_uri19( pj_pool_t *pool ); +static pjsip_uri *create_dummy( pj_pool_t *pool ); + +#define ERR_NOT_EQUAL -1001 +#define ERR_SYNTAX_ERR -1002 + +struct uri_test +{ + pj_status_t status; + char str[PJSIP_MAX_URL_SIZE]; + pjsip_uri *(*creator)(pj_pool_t *pool); + pj_size_t len; +} uri_test_array[] = +{ + { + PJ_SUCCESS, + "sip:localhost", + &create_uri1 + }, + { + PJ_SUCCESS, + "sip:user@localhost", + &create_uri2 + }, + { + PJ_SUCCESS, + "sip:user:password@localhost:5060", + &create_uri3, + }, + { + /* Port is specified should not match unspecified port. */ + ERR_NOT_EQUAL, + "sip:localhost:5060", + &create_uri4 + }, + { + /* All recognized parameters. */ + PJ_SUCCESS, + "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK", + &create_uri5 + }, + { + /* Params mixed with other params and header params. */ + PJ_SUCCESS, + "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" + "?Subject=Hello%20There&Server=SIP%20Server", + &create_uri6 + }, + { + /* SIPS. */ + PJ_SUCCESS, + "sips:localhost", + &create_uri7, + }, + { + /* Name address */ + PJ_SUCCESS, + "", + &create_uri8 + }, + { + /* Name address with display name and SIPS scheme with some redundant + * whitespaced. + */ + PJ_SUCCESS, + " Power Administrator ", + &create_uri9 + }, + { + /* Name address. */ + PJ_SUCCESS, + " \"User\" ", + &create_uri10 + }, + { + /* Escaped sequence in display name (display=Strange User\"\\\"). */ + PJ_SUCCESS, + " \"Strange User\\\"\\\\\\\"\" ", + &create_uri11, + }, + { + /* Errorneous escaping in display name. */ + ERR_SYNTAX_ERR, + " \"Rogue User\\\" ", + &create_uri12, + }, + { + /* Dangling quote in display name, but that should be OK. */ + PJ_SUCCESS, + "Strange User\" ", + &create_uri13, + }, + { + /* Special characters in parameter value must be quoted. */ + PJ_SUCCESS, + "sip:localhost;pvalue=\"hello world\"", + &create_uri14, + }, + { + /* Excercise strange character sets allowed in display, user, password, + * host, and port. + */ + PJ_SUCCESS, + "This is -. !% *_+`'~ me ", + &create_uri15, + }, + { + /* Another excercise to the allowed character sets to the hostname. */ + PJ_SUCCESS, + "sip:" ALPHANUM "-_.com", + &create_uri16, + }, + { + /* Another excercise to the allowed character sets to the username + * and password. + */ + PJ_SUCCESS, + "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host", + &create_uri17, + }, + { + /* Excercise to the pname and pvalue, and mixup of other-param + * between 'recognized' params. + */ + PJ_SUCCESS, + "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR + ";lr;other=1;transport=sctp;other2", + &create_uri18, + }, + { + /* This should trigger syntax error. */ + ERR_SYNTAX_ERR, + "sip:", + &create_dummy, + }, + { + /* Syntax error: whitespace after scheme. */ + ERR_SYNTAX_ERR, + "sip :host", + &create_dummy, + }, + { + /* Syntax error: whitespace before hostname. */ + ERR_SYNTAX_ERR, + "sip: host", + &create_dummy, + }, + { + /* Syntax error: invalid port. */ + ERR_SYNTAX_ERR, + "sip:user:password", + &create_dummy, + }, + { + /* Syntax error: no host. */ + ERR_SYNTAX_ERR, + "sip:user@", + &create_dummy, + }, + { + /* Syntax error: no user/host. */ + ERR_SYNTAX_ERR, + "sip:@", + &create_dummy, + }, + { + /* Syntax error: empty string. */ + ERR_SYNTAX_ERR, + "", + &create_dummy, + } +}; + +static pjsip_uri *create_uri1(pj_pool_t *pool) +{ + /* "sip:localhost" */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri2(pj_pool_t *pool) +{ + /* "sip:user@localhost" */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2( pool, &url->user, "user"); + pj_strdup2( pool, &url->host, "localhost"); + + return (pjsip_uri*) url; +} + +static pjsip_uri *create_uri3(pj_pool_t *pool) +{ + /* "sip:user:password@localhost:5060" */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2( pool, &url->user, "user"); + pj_strdup2( pool, &url->passwd, "password"); + pj_strdup2( pool, &url->host, "localhost"); + url->port = 5060; + + return (pjsip_uri*) url; +} + +static pjsip_uri *create_uri4(pj_pool_t *pool) +{ + /* Like: "sip:localhost:5060", but without the port. */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri5(pj_pool_t *pool) +{ + /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + pj_strdup2(pool, &url->transport_param, "tcp"); + pj_strdup2(pool, &url->user_param, "ip"); + url->ttl_param = 255; + url->lr_param = 1; + pj_strdup2(pool, &url->maddr_param, "127.0.0.1"); + pj_strdup2(pool, &url->method_param, "ACK"); + + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri6(pj_pool_t *pool) +{ + /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry" + "?Subject=Hello%20There&Server=SIP%20Server" + */ + pjsip_url *url = pjsip_url_create(pool, 0); + + pj_strdup2(pool, &url->host, "localhost"); + pj_strdup2(pool, &url->user_param, "phone"); + pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry"); + pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server"); + return (pjsip_uri*)url; + +} + +static pjsip_uri *create_uri7(pj_pool_t *pool) +{ + /* "sips:localhost" */ + pjsip_url *url = pjsip_url_create(pool, 1); + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri8(pj_pool_t *pool) +{ + /* "" */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri9(pj_pool_t *pool) +{ + /* " Power Administrator " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 1); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Power Administrator"); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri10(pj_pool_t *pool) +{ + /* " \"User\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "\"User\""); + pj_strdup2(pool, &url->user, "user"); + pj_strdup2(pool, &url->host, "localhost"); + url->port = 5071; + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri11(pj_pool_t *pool) +{ + /* " \"Strange User\\\"\\\\\\\"\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\""); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri12(pj_pool_t *pool) +{ + /* " \"Rogue User\\\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\""); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri13(pj_pool_t *pool) +{ + /* "Strange User\" " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "Strange User\""); + pj_strdup2(pool, &url->host, "localhost"); + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri14(pj_pool_t *pool) +{ + /* "sip:localhost;pvalue=\"hello world\"" */ + pjsip_url *url; + url = pjsip_url_create(pool, 0); + pj_strdup2(pool, &url->host, "localhost"); + pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\""); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri15(pj_pool_t *pool) +{ + /* "This is -. !% *_+`'~ me " */ + pjsip_name_addr *name_addr = pjsip_name_addr_create(pool); + pjsip_url *url; + + url = pjsip_url_create(pool, 0); + name_addr->uri = (pjsip_uri*) url; + + pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me"); + pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c"); + pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,"); + pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com"); + url->port = 9801; + return (pjsip_uri*)name_addr; +} + +static pjsip_uri *create_uri16(pj_pool_t *pool) +{ + /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */ + pjsip_url *url; + url = pjsip_url_create(pool, 0); + pj_strdup2(pool, &url->host, ALPHANUM "-_.com"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri17(pj_pool_t *pool) +{ + /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */ + pjsip_url *url; + url = pjsip_url_create(pool, 0); + pj_strdup2(pool, &url->user, ALPHANUM USER); + pj_strdup2(pool, &url->passwd, ALPHANUM PASS); + pj_strdup2(pool, &url->host, "host"); + return (pjsip_uri*)url; +} + +static pjsip_uri *create_uri18(pj_pool_t *pool) +{ + /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */ + pjsip_url *url; + url = pjsip_url_create(pool, 0); + pj_strdup2(pool, &url->host, "host"); + pj_strdup2(pool, &url->user_param, "ip"); + pj_strdup2(pool, &url->transport_param, "sctp"); + pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2"); + url->lr_param = 1; + return (pjsip_uri*)url; +} + +static pjsip_uri *create_dummy(pj_pool_t *pool) +{ + PJ_UNUSED_ARG(pool); + return NULL; +} + +/*****************************************************************************/ + +/* + * Test one test entry. + */ +static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) +{ + pj_status_t status; + int len; + pjsip_uri *parsed_uri, *ref_uri; + pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0}; + pj_timestamp t1, t2; + + entry->len = pj_native_strlen(entry->str); + + /* Parse URI text. */ + pj_get_timestamp(&t1); + parse_len += entry->len; + parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0); + if (!parsed_uri) { + /* Parsing failed. If the entry says that this is expected, then + * return OK. + */ + status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : -10; + goto on_return; + } + pj_get_timestamp(&t2); + parse_time += t2.u32.lo - t1.u32.lo; + + /* Create the reference URI. */ + ref_uri = entry->creator(pool); + + /* Print both URI. */ + s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); + s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); + + pj_get_timestamp(&t1); + len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE); + if (len < 1) { + status = -20; + goto on_return; + } + s1.slen = len; + + len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); + if (len < 1) { + status = -30; + goto on_return; + } + s2.slen = len; + pj_get_timestamp(&t2); + print_time += t2.u32.lo - t1.u32.lo; + + /* Full comparison of parsed URI with reference URI. */ + if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) { + /* Not equal. See if this is the expected status. */ + status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : -40; + goto on_return; + + } else { + /* Equal. See if this is the expected status. */ + status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -50; + if (status != PJ_SUCCESS) { + goto on_return; + } + } + + /* Compare text. */ + if (pj_strcmp(&s1, &s2) != 0) { + /* Not equal. */ + status = -60; + } + +on_return: + return status; +} + +pj_status_t uri_test() +{ + unsigned i; + pj_pool_t *pool; + pj_status_t status; + + pool = pjsip_endpt_create_pool(endpt, "", 4000, 4000); + + for (i=0; i