/* * PROXY_REWRITE_INVITATION_BODY * * rewrites the outgoing INVITATION request or response packet * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */ int proxy_rewrite_invitation_body(osip_message_t *mymsg, int direction){ osip_body_t *body; sdp_message_t *sdp; struct in_addr map_addr, addr_sess, addr_media, outside_addr, inside_addr; int sts; char *bodybuff; int bodybuflen; char clen[8]; /* content length: probably never more than 7 digits !*/ int map_port, msg_port; int media_stream_no; sdp_connection_t *sdp_conn; sdp_media_t *sdp_med; int rtp_direction=0; int have_c_media=0; if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; /* * get SDP structure */ sts = osip_message_get_body(mymsg, 0, &body); if (sts != 0) { #if 0 if ((MSG_IS_RESPONSE_FOR(mymsg,"INVITE")) && (MSG_IS_STATUS_1XX(mymsg))) { /* 1xx responses *MAY* contain SDP data */ DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: " "no body found in message"); return STS_SUCCESS; } else { /* INVITE request and 200 response *MUST* contain SDP data */ ERROR("rewrite_invitation_body: no body found in message"); return STS_FAILURE; } #else DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: " "no body found in message"); return STS_SUCCESS; #endif } sts = sip_body_to_str(body, &bodybuff, &bodybuflen); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sip_body_to_str"); } sts = sdp_message_init(&sdp); sts = sdp_message_parse (sdp, bodybuff); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sdp_message_parse body"); DUMP_BUFFER(-1, bodybuff, bodybuflen); osip_free(bodybuff); sdp_message_free(sdp); return STS_FAILURE; } osip_free(bodybuff); if (configuration.debuglevel) { /* just dump the buffer */ char *tmp, *tmp2; int tmplen; sts = osip_message_get_body(mymsg, 0, &body); sts = sip_body_to_str(body, &tmp, &tmplen); osip_content_length_to_str(mymsg->content_length, &tmp2); DEBUG("Body before rewrite (clen=%s, strlen=%i):\n%s\n----", tmp2, tmplen, tmp); osip_free(tmp); osip_free(tmp2); } /* * RTP proxy: get ready and start forwarding * start forwarding for each media stream ('m=' item in SIP message) */ /* get outbound address */ if (get_interface_ip(IF_OUTBOUND, &outside_addr) != STS_SUCCESS) { sdp_message_free(sdp); return STS_FAILURE; } /* get inbound address */ if (get_interface_ip(IF_INBOUND, &inside_addr) != STS_SUCCESS) { sdp_message_free(sdp); return STS_FAILURE; } /* figure out what address to use for RTP masquerading */ if (MSG_IS_REQUEST(mymsg)) { if (direction == DIR_INCOMING) { memcpy(&map_addr, &inside_addr, sizeof (map_addr)); rtp_direction = DIR_OUTGOING; } else { memcpy(&map_addr, &outside_addr, sizeof (map_addr)); rtp_direction = DIR_INCOMING; } } else /* MSG_IS_REPONSE(mymsg) */ { if (direction == DIR_INCOMING) { memcpy(&map_addr, &inside_addr, sizeof (map_addr)); rtp_direction = DIR_OUTGOING; } else { memcpy(&map_addr, &outside_addr, sizeof (map_addr)); rtp_direction = DIR_INCOMING; } } DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: SIP[%s %s] RTP[%s %s]", MSG_IS_REQUEST(mymsg)? "RQ" : "RS", (direction==DIR_INCOMING)? "IN" : "OUT", (rtp_direction==DIR_INCOMING)? "IN" : "OUT", utils_inet_ntoa(map_addr)); /* * first, check presence of a 'c=' item on session level */ if (sdp->c_connection==NULL || sdp->c_connection->c_addr==NULL) { /* * No 'c=' on session level, search on media level now * * According to RFC2327, ALL media description must * include a 'c=' item now: */ media_stream_no=0; while (!sdp_message_endof_media(sdp, media_stream_no)) { /* check if n'th media stream is present */ if (sdp_message_c_addr_get(sdp, media_stream_no, 0) == NULL) { ERROR("SDP: have no 'c=' on session level and neither " "on media level (media=%i)",media_stream_no); sdp_message_free(sdp); return STS_FAILURE; } media_stream_no++; } /* while */ } /* Required 'c=' items ARE present */ /* * rewrite 'c=' item on session level if present and not yet done. * remember the original address in addr_sess */ memset(&addr_sess, 0, sizeof(addr_sess)); if (sdp->c_connection && sdp->c_connection->c_addr) { sts = get_ip_by_host(sdp->c_connection->c_addr, &addr_sess); if (sts == STS_FAILURE) { ERROR("SDP: cannot resolve session 'c=' host [%s]", sdp->c_connection->c_addr); sdp_message_free(sdp); return STS_FAILURE; } /* * Rewrite * an IP address of 0.0.0.0 means *MUTE*, don't rewrite such */ if (strcmp(sdp->c_connection->c_addr, "0.0.0.0") != 0) { osip_free(sdp->c_connection->c_addr); sdp->c_connection->c_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp->c_connection->c_addr, "%s", utils_inet_ntoa(map_addr)); } else { /* 0.0.0.0 - don't rewrite */ DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "got a MUTE c= record (on session level - legal?)"); } } /* * rewrite 'o=' item (originator) on session level if present. */ if (sdp->o_addrtype && sdp->o_addr) { if (strcmp(sdp->o_addrtype, "IP4") != 0) { ERROR("got IP6 in SDP originator - not yet suported by siproxd"); sdp_message_free(sdp); return STS_FAILURE; } osip_free(sdp->o_addr); sdp->o_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp->o_addr, "%s", utils_inet_ntoa(map_addr)); } /* * loop through all media descritions, * start RTP proxy and rewrite them */ for (media_stream_no=0;;media_stream_no++) { /* check if n'th media stream is present */ if (sdp_message_m_port_get(sdp, media_stream_no) == NULL) break; /* * check if a 'c=' item is present in this media description, * if so -> rewrite it */ memset(&addr_media, 0, sizeof(addr_media)); have_c_media=0; sdp_conn=sdp_message_connection_get(sdp, media_stream_no, 0); if (sdp_conn && sdp_conn->c_addr) { if (strcmp(sdp_conn->c_addr, "0.0.0.0") != 0) { sts = get_ip_by_host(sdp_conn->c_addr, &addr_media); have_c_media=1; /* have a valid address */ osip_free(sdp_conn->c_addr); sdp_conn->c_addr=osip_malloc(HOSTNAME_SIZE); sprintf(sdp_conn->c_addr, "%s", utils_inet_ntoa(map_addr)); } else { /* 0.0.0.0 - don't rewrite */ DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: got a " "MUTE c= record (media level)"); } } /* start an RTP proxying stream */ if (sdp_message_m_port_get(sdp, media_stream_no)) { msg_port=atoi(sdp_message_m_port_get(sdp, media_stream_no)); if (msg_port > 0) { osip_uri_t *cont_url = NULL; char *client_id=NULL; /* try to get some additional UA specific unique ID. * Try: * 1) User part of Contact header * 2) Host part of Contact header (will be different * between internal UA and external UA) */ if (!osip_list_eol(mymsg->contacts, 0)) cont_url = ((osip_contact_t*)(mymsg->contacts->node->element))->url; if (cont_url) { client_id=cont_url->username; if (client_id == NULL) client_id=cont_url->host; } /* * do we have a 'c=' item on media level? * if not, use the same as on session level */ if (have_c_media == 0) { memcpy(&addr_media, &addr_sess, sizeof(addr_sess)); } /* * Am I running in front of the routing device? Then I cannot * use the external IP to bind a listen socket to, so force * the use of my inbound IP for listening. */ if ((rtp_direction == DIR_INCOMING) && (configuration.outbound_host) && (strcmp(configuration.outbound_host, "")!=0)) { DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "in-front-of-NAT-Router"); memcpy(&map_addr, &inside_addr, sizeof (map_addr)); } sts = rtp_start_fwd(osip_message_get_call_id(mymsg), client_id, rtp_direction, media_stream_no, map_addr, &map_port, addr_media, msg_port); if (sts == STS_SUCCESS) { /* and rewrite the port */ sdp_med=osip_list_get(sdp->m_medias, media_stream_no); if (sdp_med && sdp_med->m_port) { osip_free(sdp_med->m_port); sdp_med->m_port=osip_malloc(8); /* 5 digits, \0 + align */ sprintf(sdp_med->m_port, "%i", map_port); DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: " "m= rewrote port to [%i]",map_port); } else { ERROR("rewriting port in m= failed sdp_med=%p, " "m_number_of_port=%p", sdp_med, sdp_med->m_port); } } /* sts == success */ } /* if msg_port > 0 */ } else { /* no port defined - skip entry */ WARN("no port defined in m=(media) stream_no=%i", media_stream_no); continue; } } /* for media_stream_no */ /* remove old body */ sts = osip_list_remove(mymsg->bodies, 0); osip_body_free(body); /* dump new body */ sdp_message_to_str(sdp, &bodybuff); bodybuflen=strlen(bodybuff); /* free sdp structure */ sdp_message_free(sdp); /* include new body */ sip_message_set_body(mymsg, bodybuff, bodybuflen); if (sts != 0) { ERROR("rewrite_invitation_body: unable to sip_message_set_body body"); } /* free content length resource and include new one*/ osip_content_length_free(mymsg->content_length); mymsg->content_length=NULL; sprintf(clen,"%i",bodybuflen); sts = osip_message_set_content_length(mymsg, clen); /* free old body */ osip_free(bodybuff); if (configuration.debuglevel) { /* just dump the buffer */ char *tmp, *tmp2; int tmplen; sts = osip_message_get_body(mymsg, 0, &body); sts = sip_body_to_str(body, &tmp, &tmplen); osip_content_length_to_str(mymsg->content_length, &tmp2); DEBUG("Body after rewrite (clen=%s, strlen=%i):\n%s\n----", tmp2, tmplen, tmp); osip_free(tmp); osip_free(tmp2); } return STS_SUCCESS; }
/* * PROXY_RESPONSE * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error * RFC3261 * Section 16.7: Proxy Behavior - Response Processing * 1. Find the appropriate response context * 2. Update timer C for provisional responses * 3. Remove the topmost Via * 4. Add the response to the response context * 5. Check to see if this response should be forwarded immediately * 6. When necessary, choose the best final response from the * response context * 7. Aggregate authorization header field values if necessary * 8. Optionally rewrite Record-Route header field values * 9. Forward the response * 10. Generate any necessary CANCEL requests * */ int proxy_response (sip_ticket_t *ticket) { int i; int sts; int type; struct in_addr sendto_addr; osip_via_t *via; int port; char *buffer; int buflen; osip_message_t *response; struct sockaddr_in *from; DEBUGC(DBCLASS_PROXY,"proxy_response"); if (ticket==NULL) { ERROR("proxy_response: called with NULL ticket"); return STS_FAILURE; } response=ticket->sipmsg; from=&ticket->from; /* * RFC 3261, Section 16.7 step 3 * Proxy Behavior - Response Processing - Remove my Via header field value */ /* remove my Via header line */ sts = sip_del_myvia(ticket); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response"); return STS_FAILURE; } /* * figure out if this is an request coming from the outside * world to one of our registered clients */ /* Ahhrghh...... a response seems to have NO contact information... * so let's take FROM instead... * the TO and FROM headers are EQUAL to the request - that means * they are swapped in their meaning for a response... */ #if _OLD_DIRECTION_EVALUATION type = 0; for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response ('from' == 'masq') || ('from' == 'reg') */ if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) || (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) { type=RESTYP_INCOMING; DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); break; } /* outgoing response ('to' == 'reg') || ('to' == 'masq' ) */ if ((compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) || (compare_url(response->to->url, urlmap[i].reg_url)==STS_SUCCESS)){ type=RESTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username ? response->from->url->username : "******", response->from->url->host ? response->from->url->host : "*NULL*"); break; } } #else type = 0; /* * did I receive the telegram from a REGISTERED host? * -> it must be an OUTGOING response */ for (i=0; i<URLMAP_SIZE; i++) { struct in_addr tmp_addr; if (urlmap[i].active == 0) continue; if (get_ip_by_host(urlmap[i].true_url->host, &tmp_addr) == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve host [%s]", urlmap[i].true_url); } else { DEBUGC(DBCLASS_PROXY, "proxy_response: reghost:%s ip:%s", urlmap[i].true_url->host, utils_inet_ntoa(from->sin_addr)); if (memcmp(&tmp_addr, &from->sin_addr, sizeof(tmp_addr)) == 0) { type=RESTYP_OUTGOING; break; } } } /* * is the telegram directed to an internal registered host? * -> it must be an INCOMING response */ if (type == 0) { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response ('from' == 'masq') || ('from' == 'reg') */ if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) || (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) { type=RESTYP_INCOMING; break; } } } /* &&&& Open Issue &&&& it has been seen with cross-provider calls that the FROM may be 'garbled' (e.g [email protected] for calls made sipphone -> FWD) How can we deal with this? Should I take into consideration the 'Via' headers? This is the only clue I have, pointing to the *real* UA. Maybe I should put in a 'siproxd' ftag value to recognize it as a header inserted by myself */ if ((type == 0) && (!osip_list_eol(response->vias, 0))) { osip_via_t *via; struct in_addr addr_via, addr_myself; int port_via, port_ua; /* get the via address */ via = (osip_via_t *) osip_list_get (response->vias, 0); DEBUGC(DBCLASS_PROXY, "proxy_response: check via [%s] for " "registered UA",via->host); sts=get_ip_by_host(via->host, &addr_via); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve VIA [%s]", via->host); } else { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response (1st via in list points to a registered UA) */ sts=get_ip_by_host(urlmap[i].true_url->host, &addr_myself); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve " "true_url [%s]", via->host); continue; } port_via=0; if (via->port) port_via=atoi(via->port); if (port_via <= 0) port_via=SIP_PORT; port_ua=0; if (urlmap[i].true_url->port) port_ua=atoi(urlmap[i].true_url->port); if (port_ua <= 0) port_ua=SIP_PORT; DEBUGC(DBCLASS_BABBLE, "proxy_response: checking for registered " "host [%s:%i] <-> [%s:%i]", urlmap[i].true_url->host, port_ua, via->host, port_via); if ((memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) && (port_via == port_ua)) { type=RESTYP_INCOMING; break; } } } } #endif ticket->direction=type; /* * ok, we got a response that we are allowed to process. */ switch (type) { /* * from an external host to the internal masqueraded host */ case RESTYP_INCOMING: DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); /* * Response for INVITE - deal with RTP data in body and * start RTP proxy stream(s). In case * of a negative answer, stop RTP stream */ if (MSG_IS_RESPONSE_FOR(response,"INVITE")) { /* positive response, start RTP stream */ if ((MSG_IS_STATUS_1XX(response)) || (MSG_IS_STATUS_2XX(response))) { if (configuration.rtp_proxy_enable == 1) { sts = proxy_rewrite_invitation_body(response, DIR_INCOMING); } /* negative - stop a possibly started RTP stream */ } else if ((MSG_IS_STATUS_4XX(response)) || (MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_6XX(response))) { rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); } } /* if INVITE */ /* * Response for REGISTER - special handling of Contact header */ if (MSG_IS_RESPONSE_FOR(response,"REGISTER")) { /* * REGISTER returns *my* Contact header information. * Rewrite Contact header back to represent the true address. * Other responses do return the Contact header of the sender. */ sip_rewrite_contact(ticket, DIR_INCOMING); } /* * Response for SUBSCRIBE * * HACK for Grandstream SIP phones (with newer firmware like 1.0.4.40): * They send a SUBSCRIBE request to the registration server. In * case of beeing registering directly to siproxd, this request of * course will eventually be forwarded back to the same UA. * Grandstream then does reply with an '202' response (A 202 * response merely indicates that the subscription has been * understood, and that authorization may or may not have been * granted), which then of course is forwarded back to the phone. * Ans it seems that the Grandstream can *not* *handle* this * response, as it immediately sends another SUBSCRIBE request. * And this games goes on and on and on... * * As a workaround we will transform any 202 response to a * '404 unknown destination' * */ { osip_header_t *ua_hdr=NULL; osip_message_get_user_agent(response, 0, &ua_hdr); if (ua_hdr && ua_hdr->hvalue && (osip_strncasecmp(ua_hdr->hvalue,"grandstream", 11)==0) && (MSG_IS_RESPONSE_FOR(response,"SUBSCRIBE")) && (MSG_TEST_CODE(response, 202))) { DEBUGC(DBCLASS_PROXY, "proxy_response: Grandstream hack 202->404"); response->status_code=404; } } break; /* * from the internal masqueraded host to an external host */ case RESTYP_OUTGOING: DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username ? response->from->url->username : "******", response->from->url->host ? response->from->url->host : "*NULL*"); /* rewrite Contact header to represent the masqued address */ sip_rewrite_contact(ticket, DIR_OUTGOING); /* * If an 2xx OK or 1xx response, answer to an INVITE request, * rewrite body * * In case of a negative answer, stop RTP stream */ if (MSG_IS_RESPONSE_FOR(response,"INVITE")) { /* positive response, start RTP stream */ if ((MSG_IS_STATUS_1XX(response)) || (MSG_IS_STATUS_2XX(response))) { /* This is an outgoing response, therefore an outgoing stream */ sts = proxy_rewrite_invitation_body(response, DIR_OUTGOING); /* megative - stop a possibly started RTP stream */ } else if ((MSG_IS_STATUS_4XX(response)) || (MSG_IS_STATUS_5XX(response)) || (MSG_IS_STATUS_6XX(response))) { rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING); } } /* if INVITE */ break; default: DEBUGC(DBCLASS_PROXY, "response from/to unregistered UA (%s@%s)", response->from->url->username? response->from->url->username:"******", response->from->url->host? response->from->url->host : "*NULL*"); return STS_FAILURE; } /* * for ALL incoming response include my Record-Route header. * The local UA will probably send its answer to the topmost * Route Header (8.1.2 of RFC3261) */ if (type == RESTYP_INCOMING) { DEBUGC(DBCLASS_PROXY,"Adding my Record-Route"); route_add_recordroute(ticket); } else { /* * outgoing packets must not have my record route header, as * this likely will contain a private IP address (my inbound). */ DEBUGC(DBCLASS_PROXY,"Purging Record-Routes (outgoing packet)"); route_purge_recordroute(ticket); } /* * Determine Next-Hop Address */ /*&&&& priority probably should be: * 1) Route header * 2) fixed outbound proxy * 3) SIP URI */ /* * check if we need to send to an outbound proxy */ if ((type == RESTYP_OUTGOING) && (sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) { DEBUGC(DBCLASS_PROXY, "proxy_response: have outbound proxy %s:%i", utils_inet_ntoa(sendto_addr), port); /* * Route present? * If so, fetch address from topmost Route: header and remove it. */ } else if ((type == RESTYP_OUTGOING) && (response->routes && !osip_list_eol(response->routes, 0))) { sts=route_determine_nexthop(ticket, &sendto_addr, &port); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: route_determine_nexthop failed"); return STS_FAILURE; } DEBUGC(DBCLASS_PROXY, "proxy_response: have Route header to %s:%i", utils_inet_ntoa(sendto_addr), port); } else { /* get target address and port from VIA header */ via = (osip_via_t *) osip_list_get (response->vias, 0); if (via == NULL) { ERROR("proxy_response: list_get via failed"); return STS_FAILURE; } sts = get_ip_by_host(via->host, &sendto_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve VIA [%s]", via->host); return STS_FAILURE; } if (via->port) { port=atoi(via->port); } else { port=SIP_PORT; } } sts = sip_message_to_str(response, &buffer, &buflen); if (sts != 0) { ERROR("proxy_response: sip_message_to_str failed"); return STS_FAILURE; } sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen); osip_free (buffer); return STS_SUCCESS; }
char * generating_sdp_answer(osip_message_t *request, osip_negotiation_ctx_t *context) { sdp_message_t *remote_sdp; sdp_message_t *local_sdp = NULL; int i; char *local_body; if (context==NULL) return NULL; local_body = NULL; if (MSG_IS_INVITE(request)||MSG_IS_OPTIONS(request)||MSG_IS_RESPONSE_FOR(request, "INVITE")) { osip_body_t *body; body = (osip_body_t *)osip_list_get(&request->bodies,0); if(body == NULL) return NULL; /* remote_sdp = (sdp_message_t *) osip_malloc(sizeof(sdp_message_t)); */ i = sdp_message_init(&remote_sdp); if (i!=0) return NULL; /* WE ASSUME IT IS A SDP BODY AND THAT */ /* IT IS THE ONLY ONE, OF COURSE, THIS IS */ /* NOT TRUE */ i = sdp_message_parse(remote_sdp,body->body); if (i!=0) return NULL; i = osip_negotiation_ctx_set_remote_sdp(context, remote_sdp); i = osip_negotiation_ctx_execute_negotiation(eXosip.osip_negotiation, context); if (i==200) { local_sdp = osip_negotiation_ctx_get_local_sdp(context); i = sdp_message_to_str(local_sdp, &local_body); remote_sdp = osip_negotiation_ctx_get_remote_sdp(context); sdp_message_free(remote_sdp); osip_negotiation_ctx_set_remote_sdp(context, NULL); if (i!=0) { OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: Could not parse local SDP answer %i\n",i)); return NULL; } return local_body; } else if (i==415) { OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO1,NULL,"WARNING: Unsupported media %i\n",i)); } else { OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_ERROR,NULL,"ERROR: while building answer to SDP (%i)\n",i)); } remote_sdp = osip_negotiation_ctx_get_remote_sdp(context); sdp_message_free(remote_sdp); osip_negotiation_ctx_set_remote_sdp(context, NULL); } return NULL; }
static struct session *sip_callback(struct session *sip, u_char *data, uint32_t len) { osip_message_t *msg; struct tuple4 addr; struct session *start; struct session *rtp; osip_call_id_t *call_id; osip_message_init(&msg); if (!osip_message_parse(msg, (char *)data, len)) { if (NULL == sip->u.sip_params.call_id) { /* * If the session object was created by udp_callback * we need to fill in the call_id field here because * udp_callback doesn't know anything about SIP */ if (NULL != (call_id = osip_message_get_call_id(msg))) osip_call_id_clone(call_id, &sip->u.sip_params.call_id); } else { /* * Otherwise check if the session object passed to this * function call was really the one corresponding to the * call ID in the SIP packet, in case several SIP calls * are passed upon the same transport layer protocol, * source and destination IPv4 address & port combination. * udp_callback has no way of knowing how to distinguish * SIP session objects based on call ID, so we have to do * it here. We just continue searching in the list of all * tracked sessions for similar SIP objects until we find * one that has the same call ID, or else we create a new * SIP session object that corresponds to the new call. */ start = sip; do { if (NULL == (call_id = osip_message_get_call_id(msg))) continue; if (!osip_call_id_match(sip->u.sip_params.call_id, call_id)) break; } while ((sip = sessions_find(sip->next, TYPE_SIP, 0, &sip->addr))); if (NULL == sip) { if (bonus_time) { osip_message_free(msg); return start; } sip = sessions_add(start->type, &start->addr, NULL); if (NULL != (call_id = osip_message_get_call_id(msg))) osip_call_id_clone(call_id, &sip->u.sip_params.call_id); } } /* * If the current SIP packet is an INVITE message, store the * advertised source port and IPv4 address. It is not very * important, since we can do only with the destination part * (useful in case the capture missed the INVITE packet), but * it helps discriminating from unrelated packets. * * Unfortunately, some SIP implementations such as the one in * Audiocodes Mediant 1000 SIP gateways actually use a source * port different from the one they advertised in the INVITE * message parameters - how outrageous! - so we have to make * our sessions search engine ignore the source port part by * zeroing it :-/ */ if (MSG_IS_INVITE(msg)) { if (!bonus_time) { sip_get_address(msg, &sip->u.sip_params.rtp_addr.saddr, &sip->u.sip_params.rtp_addr.source); #ifndef USING_NON_STUPID_SIP_IMPLEMENTATIONS sip->u.sip_params.rtp_addr.source = 0; #endif } } else if (MSG_TEST_CODE(msg, 200)) { if (MSG_IS_RESPONSE_FOR(msg, "INVITE")) { if (!bonus_time && sip_get_address(msg, &sip->u.sip_params.rtp_addr.daddr, &sip->u.sip_params.rtp_addr.dest)) { sessions_add(TYPE_UDP | TYPE_RTP, &sip->u.sip_params.rtp_addr, sip); sip->u.sip_params.picked_up = 1; } } else if (MSG_IS_RESPONSE_FOR(msg, "BYE") || MSG_IS_RESPONSE_FOR(msg, "CANCEL")) { start = first_session; while (NULL != (rtp = sessions_find(start, TYPE_RTP, sip->id, NULL))) { sessions_del(rtp); start = rtp->next; } /* * Mark for deletion in 2 seconds, in order to give some * time to the extra ACK packets that might be exchanged */ if (sip->type & TYPE_UDP) sip->timeout = nids_last_pcap_header->ts.tv_sec + 2; } } } osip_message_free(msg); return sip; }
void CIctCallBack::icb_Rev1xx( int type, CSipTransaction* tr, CSipMessage* sip ) { CZhDialog* jd; CZhCall* jc; #ifndef MINISIZE CZhSubscribe* js; CZhNotify* jn; #endif CTransactionInfo* jinfo = (CTransactionInfo*) tr->GetInstance(); udp_tl_learn_port_from_via(sip); if (jinfo == NULL) return; jd = jinfo->jd; jc = jinfo->jc; #ifndef MINISIZE jn = jinfo->jn; js = jinfo->js; #endif if ((MSG_IS_RESPONSE_FOR(sip, "INVITE") #ifndef MINISIZE || MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE") #endif ) && !MSG_TEST_CODE(sip, 100)) { int i; if (jd == NULL) /* This transaction initiate a dialog in the case of INVITE (else it would be attached to a "jd" element. */ { /* allocate a jd */ jd = new CZhDialog; i = jd->InitAsUac(sip); if (i != 0) { return; } if (jc != NULL) { jc->c_dialogs.Add(jd); jinfo->jd = jd; CSipTransactionManager *ptm = CSipTransactionManager::getInstance(); ptm->eXosip_update(); } #ifndef MINISIZE else if (js != NULL) { js->s_dialogs.Add(jd); jinfo->jd = jd; CSipTransactionManager *ptm = CSipTransactionManager::getInstance(); ptm->eXosip_update(); } else if (jn != NULL) { jn->n_dialogs.Add(jd); jinfo->jd = jd; CSipTransactionManager *ptm = CSipTransactionManager::getInstance(); ptm->eXosip_update(); } #endif else { } tr->SetInstance(jinfo); } else { if (jd->d_dialog == NULL) { } else if (jd->d_dialog->remote_tag == NULL) { jd->d_dialog->UpdateRouteSetAsUac(sip); jd->d_dialog->UpdateTagAsUac(sip); } else { CUrlParam* tag; int i; i = sip->m_to->GetTag(&tag); if (tag != NULL && tag->gvalue != NULL && 0 == strcmp(jd->d_dialog->remote_tag,tag->gvalue)) { /* Update only if it is the same dialog */ jd->d_dialog->UpdateRouteSetAsUac(sip); } } } if (jd != NULL) jd->d_STATE = JD_TRYING; if (jd != NULL && MSG_IS_RESPONSE_FOR(sip, "INVITE") && sip->m_iStatusCode < 180) { //report_call_event(EXOSIP_CALL_PROCEEDING, jc, jd, tr); } else if (jd != NULL && MSG_IS_RESPONSE_FOR(sip, "INVITE") && sip->m_iStatusCode >= 180) { //report_call_event(EXOSIP_CALL_RINGING, jc, jd, tr); } #ifndef MINISIZE else if (jd != NULL && MSG_IS_RESPONSE_FOR(sip, "SUBSCRIBE")) { } #endif if (MSG_TEST_CODE(sip, 180) && jd != NULL) { jd->d_STATE = JD_RINGING; } else if (MSG_TEST_CODE(sip, 183) && jd != NULL) { jd->d_STATE = JD_QUEUED; } } }