Changeset 3243


Ignore:
Timestamp:
Aug 1, 2010 9:48:51 AM (10 years ago)
Author:
bennylp
Message:

Implemented core multipart support and support in the invite session (re #1070)

  • incoming multipart message will be handled automatically
  • for testing, enable HAVE_MULTIPART_TEST in pjsua_app.c
Location:
pjproject/trunk
Files:
6 added
15 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/build.symbian/pjsip.mmp

    r3046 r3243  
    4444SOURCE  sip_errno.c 
    4545SOURCE  sip_msg.c 
     46SOURCE  sip_multipart.c 
    4647SOURCE  sip_parser_wrap.cpp 
    4748SOURCE  sip_resolve.c 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r3216 r3243  
    2727//#define STEREO_DEMO 
    2828//#define TRANSPORT_ADAPTER_SAMPLE 
     29//#define HAVE_MULTIPART_TEST 
    2930 
    3031/* Ringtones                US         UK  */ 
     
    22192220} 
    22202221 
     2222#ifdef HAVE_MULTIPART_TEST 
     2223  /* 
     2224   * Enable multipart in msg_data and add a dummy body into the 
     2225   * multipart bodies. 
     2226   */ 
     2227  static void add_multipart(pjsua_msg_data *msg_data) 
     2228  { 
     2229      static pjsip_multipart_part *alt_part; 
     2230 
     2231      if (!alt_part) { 
     2232          pj_str_t type, subtype, content; 
     2233 
     2234          alt_part = pjsip_multipart_create_part(app_config.pool); 
     2235 
     2236          type = pj_str("text"); 
     2237          subtype = pj_str("plain"); 
     2238          content = pj_str("Sample text body of a multipart bodies"); 
     2239          alt_part->body = pjsip_msg_body_create(app_config.pool, &type, 
     2240                                                 &subtype, &content); 
     2241      } 
     2242 
     2243      msg_data->multipart_ctype.type = pj_str("multipart"); 
     2244      msg_data->multipart_ctype.subtype = pj_str("mixed"); 
     2245      pj_list_push_back(&msg_data->multipart_parts, alt_part); 
     2246  } 
     2247#  define TEST_MULTIPART(msg_data)      add_multipart(msg_data) 
     2248#else 
     2249#  define TEST_MULTIPART(msg_data) 
     2250#endif 
     2251 
    22212252/* 
    22222253 * Find next call when current call is disconnected or when user 
     
    34333464    pj_str_t tmp; 
    34343465    struct input_result result; 
     3466    pjsua_msg_data msg_data; 
    34353467    pjsua_call_info call_info; 
    34363468    pjsua_acc_info acc_info; 
     
    35013533            } 
    35023534             
    3503             pjsua_call_make_call( current_acc, &tmp, 0, NULL, NULL, NULL); 
     3535            pjsua_msg_data_init(&msg_data); 
     3536            TEST_MULTIPART(&msg_data); 
     3537            pjsua_call_make_call( current_acc, &tmp, 0, NULL, &msg_data, NULL); 
    35043538            break; 
    35053539 
     
    36393673                pj_str_t hvalue; 
    36403674                pjsip_generic_string_hdr hcontact; 
    3641                 pjsua_msg_data msg_data; 
    36423675 
    36433676                if (!simple_input("Answer with code (100-699)", buf, sizeof(buf))) 
     
    38873920            } else { 
    38883921                int call = current_call; 
    3889                 pjsua_msg_data msg_data; 
    38903922                pjsip_generic_string_hdr refer_sub; 
    38913923                pj_str_t STR_REFER_SUB = { "Refer-Sub", 9 }; 
     
    39423974                int call = current_call; 
    39433975                int dst_call; 
    3944                 pjsua_msg_data msg_data; 
    39453976                pjsip_generic_string_hdr refer_sub; 
    39463977                pj_str_t STR_REFER_SUB = { "Refer-Sub", 9 }; 
     
    40844115                digits = pj_str(buf); 
    40854116                for (i=0; i<digits.slen; ++i) { 
    4086                     pjsua_msg_data msg_data; 
    40874117                    char body[80]; 
    40884118 
  • pjproject/trunk/pjsip/build/Makefile

    r2970 r3243  
    3737export PJSIP_SRCDIR = ../src/pjsip 
    3838export PJSIP_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ 
    39                 sip_config.o \ 
     39                sip_config.o sip_multipart.o \ 
    4040                sip_errno.o sip_msg.o sip_parser.o sip_tel_uri.o sip_uri.o \ 
    4141                sip_endpoint.o sip_util.o sip_util_proxy.o \ 
     
    8787export TEST_SRCDIR = ../src/test 
    8888export TEST_OBJS += dlg_core_test.o dns_test.o msg_err_test.o \ 
    89                     msg_logger.o msg_test.o regc_test.o \ 
     89                    msg_logger.o msg_test.o multipart_test.o regc_test.o \ 
    9090                    test.o transport_loop_test.o transport_tcp_test.o \ 
    9191                    transport_test.o transport_udp_test.o \ 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h

    r3222 r3243  
    383383 
    384384/** 
     385 * This structure represents SDP information in a pjsip_rx_data. Application 
     386 * retrieve this information by calling #pjsip_rdata_get_sdp_info(). This 
     387 * mechanism supports multipart message body. 
     388 */ 
     389typedef struct pjsip_rdata_sdp_info 
     390{ 
     391    /** 
     392     * Pointer and length of the text body in the incoming message. If 
     393     * the pointer is NULL, it means the message does not contain SDP 
     394     * body. 
     395     */ 
     396    pj_str_t             body; 
     397 
     398    /** 
     399     * This will contain non-zero if an invalid SDP body is found in the 
     400     * message. 
     401     */ 
     402    pj_status_t          sdp_err; 
     403 
     404    /** 
     405     * A parsed and validated SDP body. 
     406     */ 
     407    pjmedia_sdp_session *sdp; 
     408 
     409} pjsip_rdata_sdp_info; 
     410 
     411 
     412/** 
    385413 * Initialize the invite usage module and register it to the endpoint.  
    386414 * The callback argument contains pointer to functions to be called on  
     
    875903                                           pjsip_msg_body **p_body); 
    876904 
     905/** 
     906 * Retrieve SDP information from an incoming message. Application should 
     907 * prefer to use this function rather than parsing the SDP manually since 
     908 * this function supports multipart message body. 
     909 * 
     910 * This function will only parse the SDP once, the first time it is called 
     911 * on the same message. Subsequent call on the same message will just pick 
     912 * up the already parsed SDP from the message. 
     913 * 
     914 * @param rdata         The incoming message. 
     915 * 
     916 * @return              The SDP info. 
     917 */ 
     918PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata); 
     919 
    877920 
    878921PJ_END_DECL 
  • pjproject/trunk/pjsip/include/pjsip.h

    r2394 r3243  
    2929#include <pjsip/sip_tel_uri.h> 
    3030#include <pjsip/sip_msg.h> 
     31#include <pjsip/sip_multipart.h> 
    3132#include <pjsip/sip_parser.h> 
    3233 
  • pjproject/trunk/pjsip/include/pjsip/sip_parser.h

    r2660 r3243  
    277277 *                      pinpoint the location of the error in the buffer. 
    278278 * 
    279  * @return              The instance of the header if parsing was successfull, 
     279 * @return              The instance of the header if parsing was successful, 
    280280 *                      or otherwise a NULL pointer will be returned. 
    281281 */ 
     
    288288 * When there are multiple headers, the headers MUST be separated by either 
    289289 * a newline (as in SIP message) or ampersand mark (as in URI). This separator 
    290  * however is optional for the last header. 
    291  * 
    292  * @param pool          the pool. 
    293  * @param input         the input text to parse, which must be NULL terminated. 
    294  * @param size          the text length. 
    295  * @param hlist         the header list to store the parsed headers.  
     290 * is optional for the last header. 
     291 * 
     292 * @param pool          The pool. 
     293 * @param input         The input text to parse, which must be NULL terminated. 
     294 * @param size          The text length. 
     295 * @param hlist         The header list to store the parsed headers. 
    296296 *                      This list must have been initialized before calling  
    297297 *                      this function. 
     298 * @param options       Specify 1 here to make parsing stop when error is 
     299 *                      encountered when parsing the header. Otherwise the 
     300 *                      error is silently ignored and parsing resumes to the 
     301 *                      next line. 
    298302 * @return              zero if successfull, or -1 if error is encountered.  
    299303 *                      Upon error, the \a hlist argument MAY contain  
    300304 *                      successfully parsed headers. 
    301305 */ 
    302 PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, 
    303                                           char *input, pj_size_t size, 
    304                                           pj_list *hlist ); 
     306PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, char *input, 
     307                                          pj_size_t size, pjsip_hdr *hlist, 
     308                                          unsigned options); 
    305309 
    306310 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r3222 r3243  
    11871187 
    11881188    /** 
    1189      * Optional message body. 
     1189     * Optional message body to be added to the message, only when the 
     1190     * message doesn't have a body. 
    11901191     */ 
    11911192    pj_str_t    msg_body; 
    11921193 
     1194    /** 
     1195     * Content type of the multipart body. If application wants to send 
     1196     * multipart message bodies, it puts the parts in \a parts and set 
     1197     * the content type in \a multipart_ctype. If the message already 
     1198     * contains a body, the body will be added to the multipart bodies. 
     1199     */ 
     1200    pjsip_media_type  multipart_ctype; 
     1201 
     1202    /** 
     1203     * List of multipart parts. If application wants to send multipart 
     1204     * message bodies, it puts the parts in \a parts and set the content 
     1205     * type in \a multipart_ctype. If the message already contains a body, 
     1206     * the body will be added to the multipart bodies. 
     1207     */ 
     1208    pjsip_multipart_part multipart_parts; 
    11931209}; 
    11941210 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r3222 r3243  
    2424#include <pjsip/sip_endpoint.h> 
    2525#include <pjsip/sip_event.h> 
     26#include <pjsip/sip_multipart.h> 
    2627#include <pjsip/sip_transaction.h> 
    2728#include <pjmedia/sdp.h> 
     
    746747} 
    747748 
     749PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata) 
     750{ 
     751    pjsip_rdata_sdp_info *sdp_info; 
     752    pjsip_msg_body *body = rdata->msg_info.msg->body; 
     753    pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype; 
     754    pjsip_media_type app_sdp; 
     755 
     756    sdp_info = (pjsip_rdata_sdp_info*) 
     757               rdata->endpt_info.mod_data[mod_inv.mod.id]; 
     758    if (sdp_info) 
     759        return sdp_info; 
     760 
     761    sdp_info = PJ_POOL_ZALLOC_T(rdata->tp_info.pool, 
     762                                pjsip_rdata_sdp_info); 
     763    PJ_ASSERT_RETURN(mod_inv.mod.id >= 0, sdp_info); 
     764    rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info; 
     765 
     766    pjsip_media_type_init2(&app_sdp, "application", "sdp"); 
     767 
     768    if (body && ctype_hdr && 
     769        pj_stricmp(&ctype_hdr->media.type, &app_sdp.type)==0 && 
     770        pj_stricmp(&ctype_hdr->media.subtype, &app_sdp.subtype)==0) 
     771    { 
     772        sdp_info->body.ptr = (char*)body->data; 
     773        sdp_info->body.slen = body->len; 
     774    } else if  (body && ctype_hdr && 
     775                pj_stricmp2(&ctype_hdr->media.type, "multipart")==0 && 
     776                (pj_stricmp2(&ctype_hdr->media.subtype, "mixed")==0 || 
     777                 pj_stricmp2(&ctype_hdr->media.subtype, "alternative")==0)) 
     778    { 
     779        pjsip_multipart_part *part; 
     780 
     781        part = pjsip_multipart_find_part(body, &app_sdp, NULL); 
     782        if (part) { 
     783            sdp_info->body.ptr = (char*)part->body->data; 
     784            sdp_info->body.slen = part->body->len; 
     785        } 
     786    } 
     787 
     788    if (sdp_info->body.ptr) { 
     789        pj_status_t status; 
     790        status = pjmedia_sdp_parse(rdata->tp_info.pool, 
     791                                   sdp_info->body.ptr, 
     792                                   sdp_info->body.slen, 
     793                                   &sdp_info->sdp); 
     794        if (status == PJ_SUCCESS) 
     795            status = pjmedia_sdp_validate(sdp_info->sdp); 
     796 
     797        if (status != PJ_SUCCESS) { 
     798            sdp_info->sdp = NULL; 
     799            PJ_PERROR(1,(THIS_FILE, status, 
     800                         "Error parsing/validating SDP body")); 
     801        } 
     802 
     803        sdp_info->sdp_err = status; 
     804    } 
     805 
     806    return sdp_info; 
     807} 
     808 
     809 
    748810/* 
    749811 * Verify incoming INVITE request. 
     
    766828    pj_status_t status = PJ_SUCCESS; 
    767829    pjsip_hdr res_hdr_list; 
     830    pjsip_rdata_sdp_info *sdp_info; 
    768831 
    769832    /* Init return arguments. */ 
     
    822885     * only when the body hasn't been parsed before. 
    823886     */ 
     887    if (r_sdp == NULL) { 
     888        sdp_info = pjsip_rdata_get_sdp_info(rdata); 
     889    } else { 
     890        sdp_info = NULL; 
     891    } 
     892 
    824893    if (r_sdp==NULL && msg->body) { 
    825         pjsip_msg_body *body = msg->body; 
    826         pj_str_t str_application = {"application", 11}; 
    827         pj_str_t str_sdp = { "sdp", 3 }; 
    828         pjmedia_sdp_session *sdp; 
    829  
    830         /* Check content type. */ 
    831         if (pj_stricmp(&body->content_type.type, &str_application) != 0 || 
    832             pj_stricmp(&body->content_type.subtype, &str_sdp) != 0) 
    833         { 
    834             /* Not "application/sdp" */ 
     894 
     895        /* Check if body really contains SDP. */ 
     896        if (sdp_info->body.ptr == NULL) { 
     897            /* Couldn't find "application/sdp" */ 
    835898            code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE; 
    836899            status = PJSIP_ERRNO_FROM_SIP_STATUS(code); 
     
    849912        } 
    850913 
    851         /* Parse and validate SDP */ 
    852         status = pjmedia_sdp_parse(rdata->tp_info.pool,  
    853                                    (char*)body->data, body->len, &sdp); 
    854         if (status == PJ_SUCCESS) 
    855             status = pjmedia_sdp_validate(sdp); 
    856  
    857         if (status != PJ_SUCCESS) { 
     914        if (sdp_info->sdp_err != PJ_SUCCESS) { 
    858915            /* Unparseable or invalid SDP */ 
    859916            code = PJSIP_SC_BAD_REQUEST; 
     
    865922                w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool, 
    866923                                                         pjsip_endpt_name(endpt), 
    867                                                          status); 
     924                                                         sdp_info->sdp_err); 
    868925                PJ_ASSERT_RETURN(w, PJ_ENOMEM); 
    869926 
     
    874931        } 
    875932 
    876         r_sdp = sdp; 
     933        r_sdp = sdp_info->sdp; 
    877934    } 
    878935 
     
    11641221    struct tsx_inv_data *tsx_inv_data; 
    11651222    pjsip_msg *msg; 
    1166     pjmedia_sdp_session *rem_sdp = NULL; 
     1223    pjsip_rdata_sdp_info *sdp_info; 
    11671224    pj_status_t status; 
    11681225 
     
    12121269    pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg); 
    12131270 
    1214     /* Parse SDP in message body, if present. */ 
    1215     if (msg->body) { 
    1216         pjsip_msg_body *body = msg->body; 
    1217  
    1218         /* Parse and validate SDP */ 
    1219         status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len, 
    1220                                    &rem_sdp); 
    1221         if (status == PJ_SUCCESS) 
    1222             status = pjmedia_sdp_validate(rem_sdp); 
    1223  
    1224         if (status != PJ_SUCCESS) { 
    1225             pjsip_dlg_dec_lock(dlg); 
    1226             return status; 
    1227         } 
     1271    /* Process SDP in message body, if present. */ 
     1272    sdp_info = pjsip_rdata_get_sdp_info(rdata); 
     1273    if (sdp_info->sdp_err) { 
     1274        pjsip_dlg_dec_lock(dlg); 
     1275        return sdp_info->sdp_err; 
    12281276    } 
    12291277 
    12301278    /* Create negotiator. */ 
    1231     if (rem_sdp) { 
    1232         status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool,  
    1233                                                        local_sdp, rem_sdp,  
     1279    if (sdp_info->sdp) { 
     1280        status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp, 
     1281                                                       sdp_info->sdp, 
    12341282                                                       &inv->neg); 
    12351283                                                 
     
    13751423    PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM); 
    13761424 
    1377     body->content_type.type = STR_APPLICATION; 
    1378     body->content_type.subtype = STR_SDP; 
     1425    pjsip_media_type_init(&body->content_type, (pj_str_t*)&STR_APPLICATION, 
     1426                          (pj_str_t*)&STR_SDP); 
    13791427    body->data = sdp; 
    13801428    body->len = 0; 
     
    15281576} 
    15291577 
     1578 
    15301579/* 
    15311580 * Initiate SDP negotiation in the SDP negotiator. 
     
    15761625{ 
    15771626    struct tsx_inv_data *tsx_inv_data; 
    1578     static const pj_str_t str_application = { "application", 11 }; 
    1579     static const pj_str_t str_sdp = { "sdp", 3 }; 
    15801627    pj_status_t status; 
    15811628    pjsip_msg *msg; 
    1582     pjmedia_sdp_session *rem_sdp; 
     1629    pjsip_rdata_sdp_info *sdp_info; 
    15831630 
    15841631    /* Check if SDP is present in the message. */ 
     
    15901637    } 
    15911638 
    1592     if (pj_stricmp(&msg->body->content_type.type, &str_application) || 
    1593         pj_stricmp(&msg->body->content_type.subtype, &str_sdp)) 
    1594     { 
     1639    sdp_info = pjsip_rdata_get_sdp_info(rdata); 
     1640    if (sdp_info->body.ptr == NULL) { 
    15951641        /* Message body is not "application/sdp" */ 
    15961642        return PJMEDIA_SDP_EINSDP; 
     
    16611707    } 
    16621708 
    1663     /* Parse the SDP body. */ 
    1664  
    1665     status = pjmedia_sdp_parse(rdata->tp_info.pool,  
    1666                                (char*)msg->body->data, 
    1667                                msg->body->len, &rem_sdp); 
    1668     if (status == PJ_SUCCESS) 
    1669         status = pjmedia_sdp_validate(rem_sdp); 
    1670  
    1671     if (status != PJ_SUCCESS) { 
    1672         char errmsg[PJ_ERR_MSG_SIZE]; 
    1673         pj_strerror(status, errmsg, sizeof(errmsg)); 
    1674         PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s", 
    1675                   pjsip_rx_data_get_info(rdata), errmsg)); 
     1709    /* Process the SDP body. */ 
     1710    if (sdp_info->sdp_err) { 
     1711        PJ_PERROR(4,(THIS_FILE, sdp_info->sdp_err, 
     1712                     "Error parsing SDP in %s", 
     1713                     pjsip_rx_data_get_info(rdata))); 
    16761714        return PJMEDIA_SDP_EINSDP; 
    16771715    } 
     1716 
     1717    pj_assert(sdp_info->sdp != NULL); 
    16781718 
    16791719    /* The SDP can be an offer or answer, depending on negotiator's state */ 
     
    16901730        if (inv->neg == NULL) { 
    16911731            status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL, 
    1692                                                          rem_sdp, &inv->neg); 
     1732                                                         sdp_info->sdp, 
     1733                                                         &inv->neg); 
    16931734        } else { 
    16941735            status=pjmedia_sdp_neg_set_remote_offer(inv->pool_prov, inv->neg,  
    1695                                                     rem_sdp); 
     1736                                                    sdp_info->sdp); 
    16961737        } 
    16971738 
    16981739        if (status != PJ_SUCCESS) { 
    1699             char errmsg[PJ_ERR_MSG_SIZE]; 
    1700             pj_strerror(status, errmsg, sizeof(errmsg)); 
    1701             PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s", 
    1702                       pjsip_rx_data_get_info(rdata), errmsg)); 
     1740            PJ_PERROR(4,(THIS_FILE, status, "Error processing SDP offer in %", 
     1741                      pjsip_rx_data_get_info(rdata))); 
    17031742            return PJMEDIA_SDP_EINSDP; 
    17041743        } 
     
    17081747        if (mod_inv.cb.on_rx_offer && inv->notify) { 
    17091748 
    1710             (*mod_inv.cb.on_rx_offer)(inv, rem_sdp); 
     1749            (*mod_inv.cb.on_rx_offer)(inv, sdp_info->sdp); 
    17111750 
    17121751        } 
     
    17251764 
    17261765        status = pjmedia_sdp_neg_set_remote_answer(inv->pool_prov, inv->neg, 
    1727                                                    rem_sdp); 
     1766                                                   sdp_info->sdp); 
    17281767 
    17291768        if (status != PJ_SUCCESS) { 
    1730             char errmsg[PJ_ERR_MSG_SIZE]; 
    1731             pj_strerror(status, errmsg, sizeof(errmsg)); 
    1732             PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s", 
    1733                       pjsip_rx_data_get_info(rdata), errmsg)); 
     1769            PJ_PERROR(4,(THIS_FILE, status, "Error processing SDP answer in %s", 
     1770                      pjsip_rx_data_get_info(rdata))); 
    17341771            return PJMEDIA_SDP_EINSDP; 
    17351772        } 
     
    38563893            pjsip_tx_data *tdata; 
    38573894            pj_status_t status; 
     3895            pjsip_rdata_sdp_info *sdp_info; 
    38583896            pjsip_status_code st_code; 
    38593897 
     
    39263964             * Otherwise generate offer from local active SDP. 
    39273965             */ 
    3928             if (rdata->msg_info.msg->body != NULL) { 
     3966            sdp_info = pjsip_rdata_get_sdp_info(rdata); 
     3967            if (sdp_info->sdp != NULL) { 
    39293968                status = process_answer(inv, 200, tdata, NULL); 
    39303969            } else { 
  • pjproject/trunk/pjsip/src/pjsip/sip_parser.c

    r3003 r3243  
    2121#include <pjsip/sip_uri.h> 
    2222#include <pjsip/sip_msg.h> 
     23#include <pjsip/sip_multipart.h> 
    2324#include <pjsip/sip_auth_parser.h> 
    2425#include <pjsip/sip_errno.h> 
     
    3435#include <pj/ctype.h> 
    3536#include <pj/assert.h> 
     37 
     38#define THIS_FILE           "sip_parser.c" 
    3639 
    3740#define ALNUM 
     
    269272} 
    270273 
    271 /* Concatenate unrecognized params into single string. */ 
    272 static void concat_param( pj_str_t *param, pj_pool_t *pool,  
    273                           const pj_str_t *pname, const pj_str_t *pvalue ) 
    274 { 
    275     pjsip_concat_param_imp(param, pool, pname, pvalue, ';'); 
    276 } 
    277  
    278274/* Initialize static properties of the parser. */ 
    279275static pj_status_t init_parser() 
     
    10531049         */ 
    10541050        if (ctype_hdr && scanner->curptr!=scanner->end) { 
    1055             pjsip_msg_body *body = PJ_POOL_ALLOC_T(pool, pjsip_msg_body); 
    1056             body->content_type.type = ctype_hdr->media.type; 
    1057             body->content_type.subtype = ctype_hdr->media.subtype; 
    1058             body->content_type.param = ctype_hdr->media.param; 
    1059  
    1060             body->data = scanner->curptr; 
    1061             body->len = scanner->end - scanner->curptr; 
    1062             body->print_body = &pjsip_print_text_body; 
    1063             body->clone_data = &pjsip_clone_text_data; 
     1051            /* New: if Content-Type indicates that this is a multipart 
     1052             * message body, parse it. 
     1053             */ 
     1054            const pj_str_t STR_MULTIPART = { "multipart", 9 }; 
     1055            pjsip_msg_body *body; 
     1056 
     1057            if (pj_stricmp(&ctype_hdr->media.type, &STR_MULTIPART)==0) { 
     1058                body = pjsip_multipart_parse(pool, scanner->curptr, 
     1059                                             scanner->end - scanner->curptr, 
     1060                                             &ctype_hdr->media, 0); 
     1061            } else { 
     1062                body = PJ_POOL_ALLOC_T(pool, pjsip_msg_body); 
     1063                body->content_type.type = ctype_hdr->media.type; 
     1064                body->content_type.subtype = ctype_hdr->media.subtype; 
     1065                body->content_type.param = ctype_hdr->media.param; 
     1066 
     1067                body->data = scanner->curptr; 
     1068                body->len = scanner->end - scanner->curptr; 
     1069                body->print_body = &pjsip_print_text_body; 
     1070                body->clone_data = &pjsip_clone_text_data; 
     1071            } 
    10641072 
    10651073            msg->body = body; 
     
    18481856    /* Parse media parameters */ 
    18491857    while (*scanner->curptr == ';') { 
    1850         pj_str_t pname, pvalue; 
    1851         int_parse_param(scanner, ctx->pool, &pname, &pvalue, 0); 
    1852         concat_param(&hdr->media.param, ctx->pool, &pname, &pvalue); 
     1858        pjsip_param *param = PJ_POOL_ALLOC_T(ctx->pool, pjsip_param); 
     1859        int_parse_param(scanner, ctx->pool, &param->name, &param->value, 0); 
     1860        pj_list_push_back(&hdr->media.param, param); 
    18531861    } 
    18541862 
     
    22652273} 
    22662274 
     2275/* Parse multiple header lines */ 
     2276PJ_DEF(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, char *input, 
     2277                                         pj_size_t size, pjsip_hdr *hlist, 
     2278                                         unsigned options) 
     2279{ 
     2280    enum { STOP_ON_ERROR = 1 }; 
     2281    pj_scanner scanner; 
     2282    pjsip_parse_ctx ctx; 
     2283    pj_str_t hname; 
     2284    PJ_USE_EXCEPTION; 
     2285 
     2286    pj_scan_init(&scanner, input, size, PJ_SCAN_AUTOSKIP_WS_HEADER, 
     2287                 &on_syntax_error); 
     2288 
     2289    pj_bzero(&ctx, sizeof(ctx)); 
     2290    ctx.scanner = &scanner; 
     2291    ctx.pool = pool; 
     2292 
     2293retry_parse: 
     2294    PJ_TRY 
     2295    { 
     2296        /* Parse headers. */ 
     2297        do { 
     2298            pjsip_parse_hdr_func * handler; 
     2299            pjsip_hdr *hdr = NULL; 
     2300 
     2301            /* Init hname just in case parsing fails. 
     2302             * Ref: PROTOS #2412 
     2303             */ 
     2304            hname.slen = 0; 
     2305 
     2306            /* Get hname. */ 
     2307            pj_scan_get( &scanner, &pconst.pjsip_TOKEN_SPEC, &hname); 
     2308            if (pj_scan_get_char( &scanner ) != ':') { 
     2309                PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); 
     2310            } 
     2311 
     2312            /* Find handler. */ 
     2313            handler = find_handler(&hname); 
     2314 
     2315            /* Call the handler if found. 
     2316             * If no handler is found, then treat the header as generic 
     2317             * hname/hvalue pair. 
     2318             */ 
     2319            if (handler) { 
     2320                hdr = (*handler)(&ctx); 
     2321            } else { 
     2322                hdr = parse_hdr_generic_string(&ctx); 
     2323                hdr->name = hdr->sname = hname; 
     2324            } 
     2325 
     2326            /* Single parse of header line can produce multiple headers. 
     2327             * For example, if one Contact: header contains Contact list 
     2328             * separated by comma, then these Contacts will be split into 
     2329             * different Contact headers. 
     2330             * So here we must insert list instead of just insert one header. 
     2331             */ 
     2332            if (hdr) 
     2333                pj_list_insert_nodes_before(hlist, hdr); 
     2334 
     2335            /* Parse until EOF or an empty line is found. */ 
     2336        } while (!pj_scan_is_eof(&scanner) && !IS_NEWLINE(*scanner.curptr)); 
     2337 
     2338        /* If empty line is found, eat it. */ 
     2339        if (!pj_scan_is_eof(&scanner)) { 
     2340            if (IS_NEWLINE(*scanner.curptr)) { 
     2341                pj_scan_get_newline(&scanner); 
     2342            } 
     2343        } 
     2344    } 
     2345    PJ_CATCH_ANY 
     2346    { 
     2347        PJ_LOG(4,(THIS_FILE, "Error parsing header: '%.*s' line %d col %d", 
     2348                  (int)hname.slen, hname.ptr, scanner.line, 
     2349                  pj_scan_get_col(&scanner))); 
     2350 
     2351        /* Exception was thrown during parsing. */ 
     2352        if ((options & STOP_ON_ERROR) == STOP_ON_ERROR) { 
     2353            pj_scan_fini(&scanner); 
     2354            return PJSIP_EINVALIDHDR; 
     2355        } 
     2356 
     2357        /* Skip until newline, and parse next header. */ 
     2358        if (!pj_scan_is_eof(&scanner)) { 
     2359            /* Skip until next line. 
     2360             * Watch for header continuation. 
     2361             */ 
     2362            do { 
     2363                pj_scan_skip_line(&scanner); 
     2364            } while (IS_SPACE(*scanner.curptr)); 
     2365        } 
     2366 
     2367        /* Restore flag. Flag may be set in int_parse_sip_url() */ 
     2368        scanner.skip_ws = PJ_SCAN_AUTOSKIP_WS_HEADER; 
     2369 
     2370        /* Continue parse next header, if any. */ 
     2371        if (!pj_scan_is_eof(&scanner) && !IS_NEWLINE(*scanner.curptr)) { 
     2372            goto retry_parse; 
     2373        } 
     2374 
     2375    } 
     2376    PJ_END; 
     2377 
     2378    return PJ_SUCCESS; 
     2379} 
     2380 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r3239 r3243  
    646646    int call_id = -1; 
    647647    int sip_err_code; 
    648     pjmedia_sdp_session *offer, *answer; 
     648    pjmedia_sdp_session *offer=NULL, *answer; 
    649649    pj_status_t status; 
    650650 
     
    766766    /* Parse SDP from incoming request */ 
    767767    if (rdata->msg_info.msg->body) { 
    768         status = pjmedia_sdp_parse(rdata->tp_info.pool,  
    769                                    (char*)rdata->msg_info.msg->body->data, 
    770                                    rdata->msg_info.msg->body->len, &offer); 
    771         if (status == PJ_SUCCESS) { 
    772             /* Validate */ 
    773             status = pjmedia_sdp_validate(offer); 
    774         } 
     768        pjsip_rdata_sdp_info *sdp_info; 
     769 
     770        sdp_info = pjsip_rdata_get_sdp_info(rdata); 
     771        offer = sdp_info->sdp; 
     772 
     773        status = sdp_info->sdp_err; 
     774        if (status==PJ_SUCCESS && sdp_info->sdp==NULL) 
     775            status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE); 
    775776 
    776777        if (status != PJ_SUCCESS) { 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r3216 r3243  
    143143    pj_bzero(msg_data, sizeof(*msg_data)); 
    144144    pj_list_init(&msg_data->hdr_list); 
     145    pjsip_media_type_init(&msg_data->multipart_ctype, NULL, NULL); 
     146    pj_list_init(&msg_data->multipart_parts); 
    145147} 
    146148 
     
    22262228        tdata->msg->body = body; 
    22272229    } 
     2230 
     2231    /* Multipart */ 
     2232    if (!pj_list_empty(&msg_data->multipart_parts) && 
     2233        msg_data->multipart_ctype.type.slen) 
     2234    { 
     2235        pjsip_msg_body *bodies; 
     2236        pjsip_multipart_part *part; 
     2237        pj_str_t *boundary = NULL; 
     2238 
     2239        bodies = pjsip_multipart_create(tdata->pool, 
     2240                                        &msg_data->multipart_ctype, 
     2241                                        boundary); 
     2242        part = msg_data->multipart_parts.next; 
     2243        while (part != &msg_data->multipart_parts) { 
     2244            pjsip_multipart_part *part_copy; 
     2245 
     2246            part_copy = pjsip_multipart_clone_part(tdata->pool, part); 
     2247            pjsip_multipart_add_part(tdata->pool, bodies, part_copy); 
     2248            part = part->next; 
     2249        } 
     2250 
     2251        if (tdata->msg->body) { 
     2252            part = pjsip_multipart_create_part(tdata->pool); 
     2253            part->body = tdata->msg->body; 
     2254            pjsip_multipart_add_part(tdata->pool, bodies, part); 
     2255 
     2256            tdata->msg->body = NULL; 
     2257        } 
     2258 
     2259        tdata->msg->body = bodies; 
     2260    } 
    22282261} 
    22292262 
  • pjproject/trunk/pjsip/src/test/test.c

    r2660 r3243  
    302302#endif 
    303303 
     304#if INCLUDE_MULTIPART_TEST 
     305    DO_TEST(multipart_test()); 
     306#endif 
     307 
    304308#if INCLUDE_TXDATA_TEST 
    305309    DO_TEST(txdata_test()); 
  • pjproject/trunk/pjsip/src/test/test.h

    r2638 r3243  
    5757#define INCLUDE_URI_TEST        INCLUDE_MESSAGING_GROUP 
    5858#define INCLUDE_MSG_TEST        INCLUDE_MESSAGING_GROUP 
     59#define INCLUDE_MULTIPART_TEST  INCLUDE_MESSAGING_GROUP 
    5960#define INCLUDE_TXDATA_TEST     INCLUDE_MESSAGING_GROUP 
    6061#define INCLUDE_TSX_BENCH       INCLUDE_MESSAGING_GROUP 
     
    7273int msg_test(void); 
    7374int msg_err_test(void); 
     75int multipart_test(void); 
    7476int txdata_test(void); 
    7577int tsx_bench(void); 
  • pjproject/trunk/tests/pjsua/inc_sip.py

    r3194 r3243  
    108108                return msg 
    109109 
    110         def create_req(self, method, sdp, branch="", extra_headers=""): 
     110        def create_req(self, method, sdp, branch="", extra_headers="", body=""): 
    111111                if branch=="": 
    112112                        self.cseq = self.cseq + 1 
     
    120120                        msg = msg.replace("$CONTENT_LENGTH", str(len(sdp))) 
    121121                        msg = msg + "Content-Type: application/sdp\r\n" 
     122                        msg = msg + "\r\n" 
     123                        msg = msg + sdp 
     124                elif body!="": 
     125                        msg = msg.replace("$CONTENT_LENGTH", str(len(body))) 
     126                        msg = msg + "\r\n" 
     127                        msg = msg + body 
    122128                else: 
    123129                        msg = msg.replace("$CONTENT_LENGTH", "0") 
    124                 msg = msg + "\r\n" 
    125                 msg = msg + sdp 
    126130                return self.update_fields(msg) 
    127131 
     
    139143                return response 
    140144 
    141         def create_invite(self, sdp, extra_headers=""): 
     145        def create_invite(self, sdp, extra_headers="", body=""): 
    142146                self.inv_branch = str(random.random()) 
    143                 return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers) 
     147                return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers, body=body) 
    144148 
    145149        def create_ack(self, sdp="", extra_headers=""): 
     
    253257        # List of RE patterns that must NOT exist in response 
    254258        resp_exclude = [] 
     259        # Full (non-SDP) body 
     260        body = "" 
    255261        # Constructor 
    256262        def __init__(self, name, pjsua_args, sdp, resp_code,  
    257263                     resp_inc=[], resp_exc=[], use_tcp=False, 
    258                      extra_headers="", complete_msg="", 
     264                     extra_headers="", body="", complete_msg="", 
    259265                     enable_buffer = False): 
    260266                self.complete_msg = complete_msg 
     
    265271                self.use_tcp = use_tcp 
    266272                self.extra_headers = extra_headers 
     273                self.body = body 
    267274                self.inst_param = cfg.InstanceParam("pjsua", pjsua_args) 
    268275                self.inst_param.enable_buffer = enable_buffer  
  • pjproject/trunk/tests/pjsua/mod_sendto.py

    r2440 r3243  
    2222                req = dlg.update_fields(cfg.complete_msg) 
    2323        else: 
    24                 req = dlg.create_invite(cfg.sdp, cfg.extra_headers) 
     24                req = dlg.create_invite(cfg.sdp, cfg.extra_headers, cfg.body) 
    2525        resp = dlg.send_request_wait(req, 10) 
    2626        if resp=="": 
Note: See TracChangeset for help on using the changeset viewer.