int _eXosip_pub_update (struct eXosip_t *excontext, eXosip_pub_t ** pub, osip_transaction_t * tr, osip_message_t * answer) { eXosip_pub_t *jpub; *pub = NULL; for (jpub = excontext->j_pub; jpub != NULL; jpub = jpub->next) { if (jpub->p_last_tr == NULL) { /*bug? */ } else if (tr == jpub->p_last_tr) { /* update the sip_etag parameter */ if (answer == NULL) { /* bug? */ } else if (MSG_IS_STATUS_2XX (answer)) { osip_header_t *sip_etag = NULL; osip_message_header_get_byname (answer, "SIP-ETag", 0, &sip_etag); if (sip_etag != NULL && sip_etag->hvalue != NULL) snprintf (jpub->p_sip_etag, 64, "%s", sip_etag->hvalue); } *pub = jpub; return OSIP_SUCCESS; } } return OSIP_NOTFOUND; }
int osip_dialog_update_route_set_as_uac (osip_dialog_t * dialog, osip_message_t * response) { /* only the remote target URI is updated here... */ osip_contact_t *contact; int i; if (dialog == NULL) return -1; if (response == NULL) return -1; if (osip_list_eol (&response->contacts, 0)) { /* no contact header in response? */ OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "missing a contact in response!\n")); } else { /* I personally think it's a bad idea to keep the old value in case the new one is broken... */ if (dialog->remote_contact_uri != NULL) { osip_contact_free (dialog->remote_contact_uri); } dialog->remote_contact_uri = NULL; contact = osip_list_get (&response->contacts, 0); i = osip_contact_clone (contact, &(dialog->remote_contact_uri)); if (i != 0) return -1; } if (dialog->state == DIALOG_EARLY && osip_list_size (&dialog->route_set) == 0) { /* update the route set */ int pos = 0; while (!osip_list_eol (&response->record_routes, pos)) { osip_record_route_t *rr; osip_record_route_t *rr2; rr = (osip_record_route_t *) osip_list_get (&response->record_routes, pos); i = osip_record_route_clone (rr, &rr2); if (i != 0) return -1; osip_list_add (&dialog->route_set, rr2, 0); pos++; } } if (MSG_IS_STATUS_2XX (response)) dialog->state = DIALOG_CONFIRMED; return 0; }
type_t evt_set_type_incoming_sipmessage (osip_message_t * sip) { if (MSG_IS_REQUEST (sip)) { if (MSG_IS_INVITE (sip)) return RCV_REQINVITE; else if (MSG_IS_ACK (sip)) return RCV_REQACK; return RCV_REQUEST; } else { if (MSG_IS_STATUS_1XX (sip)) return RCV_STATUS_1XX; else if (MSG_IS_STATUS_2XX (sip)) return RCV_STATUS_2XX; return RCV_STATUS_3456XX; } }
void ist_rcv_invite (osip_transaction_t * ist, osip_event_t * evt) { int i; if (ist->state == IST_PRE_PROCEEDING) { /* announce new INVITE */ /* Here we have ist->orig_request == NULL */ ist->orig_request = evt->sip; __osip_message_callback (OSIP_IST_INVITE_RECEIVED, ist, evt->sip); } else { /* IST_PROCEEDING or IST_COMPLETED */ /* delete retransmission */ osip_message_free (evt->sip); __osip_message_callback (OSIP_IST_INVITE_RECEIVED_AGAIN, ist, ist->orig_request); if (ist->last_response != NULL) { /* retransmit last response */ i = __osip_transaction_snd_xxx (ist, ist->last_response); if (i != 0) { ist_handle_transport_error (ist, i); return; } else { if (MSG_IS_STATUS_1XX (ist->last_response)) __osip_message_callback (OSIP_IST_STATUS_1XX_SENT, ist, ist->last_response); else if (MSG_IS_STATUS_2XX (ist->last_response)) __osip_message_callback (OSIP_IST_STATUS_2XX_SENT_AGAIN, ist, ist->last_response); else __osip_message_callback (OSIP_IST_STATUS_3456XX_SENT_AGAIN, ist, ist->last_response); } } return; } /* we come here only if it was the first INVITE received */ __osip_transaction_set_state (ist, IST_PROCEEDING); }
void nist_rcv_request (osip_transaction_t * nist, osip_event_t * evt) { int i; if (nist->state == NIST_PRE_TRYING) /* announce new REQUEST */ { /* Here we have ist->orig_request == NULL */ nist->orig_request = evt->sip; if (MSG_IS_REGISTER (evt->sip)) __osip_message_callback (OSIP_NIST_REGISTER_RECEIVED, nist, nist->orig_request); else if (MSG_IS_BYE (evt->sip)) __osip_message_callback (OSIP_NIST_BYE_RECEIVED, nist, nist->orig_request); else if (MSG_IS_OPTIONS (evt->sip)) __osip_message_callback (OSIP_NIST_OPTIONS_RECEIVED, nist, nist->orig_request); else if (MSG_IS_INFO (evt->sip)) __osip_message_callback (OSIP_NIST_INFO_RECEIVED, nist, nist->orig_request); else if (MSG_IS_CANCEL (evt->sip)) __osip_message_callback (OSIP_NIST_CANCEL_RECEIVED, nist, nist->orig_request); else if (MSG_IS_NOTIFY (evt->sip)) __osip_message_callback (OSIP_NIST_NOTIFY_RECEIVED, nist, nist->orig_request); else if (MSG_IS_SUBSCRIBE (evt->sip)) __osip_message_callback (OSIP_NIST_SUBSCRIBE_RECEIVED, nist, nist->orig_request); else __osip_message_callback (OSIP_NIST_UNKNOWN_REQUEST_RECEIVED, nist, nist->orig_request); } else /* NIST_PROCEEDING or NIST_COMPLETED */ { /* delete retransmission */ osip_message_free (evt->sip); __osip_message_callback (OSIP_NIST_REQUEST_RECEIVED_AGAIN, nist, nist->orig_request); if (nist->last_response != NULL) /* retransmit last response */ { i = __osip_transaction_snd_xxx(nist, nist->last_response); if (i != 0) { nist_handle_transport_error (nist, i); return; } else { if (MSG_IS_STATUS_1XX (nist->last_response)) __osip_message_callback (OSIP_NIST_STATUS_1XX_SENT, nist, nist->last_response); else if (MSG_IS_STATUS_2XX (nist->last_response)) __osip_message_callback (OSIP_NIST_STATUS_2XX_SENT_AGAIN, nist, nist->last_response); else __osip_message_callback (OSIP_NIST_STATUS_3456XX_SENT_AGAIN, nist, nist->last_response); return; } } /* we are already in the proper state */ return; } /* we come here only if it was the first REQUEST received */ __osip_transaction_set_state (nist, NIST_TRYING); }
void eXosip_automatic_action (void) { eXosip_call_t *jc; eXosip_dialog_t *jd; #ifndef MINISIZE eXosip_subscribe_t *js; eXosip_notify_t *jn; #endif eXosip_reg_t *jr; time_t now; now = time (NULL); for (jc = eXosip.j_calls; jc != NULL; jc = jc->next) { if (jc->c_id < 1) { } else if (jc->c_dialogs == NULL || jc->c_dialogs->d_dialog == NULL) { /* an EARLY dialog may have failed with 401,407 or 3Xx */ osip_transaction_t *out_tr = NULL; out_tr = jc->c_out_tr; if (out_tr != NULL && (out_tr->state == ICT_TERMINATED || out_tr->state == NICT_TERMINATED || out_tr->state == ICT_COMPLETED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code == 401 || out_tr->last_response->status_code == 407)) { /* retry with credential */ if (jc->c_retry < 3) { int i; i = _eXosip_call_retry_request (jc, NULL, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for authentication\n")); } jc->c_retry++; } } else if (out_tr != NULL && (out_tr->state == ICT_TERMINATED || out_tr->state == NICT_TERMINATED || out_tr->state == ICT_COMPLETED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code >= 300 && out_tr->last_response->status_code <= 399)) { /* retry with credential */ int i; i = _eXosip_call_retry_request (jc, NULL, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for redirection\n")); } } } for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) { if (jd->d_dialog == NULL) /* finished call */ { } else { osip_transaction_t *out_tr = NULL; out_tr = osip_list_get (jd->d_out_trs, 0); if (out_tr == NULL) out_tr = jc->c_out_tr; if (out_tr != NULL && (out_tr->state == ICT_TERMINATED || out_tr->state == NICT_TERMINATED || out_tr->state == ICT_COMPLETED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code == 401 || out_tr->last_response->status_code == 407)) { /* retry with credential */ if (jd->d_retry < 3) { int i; i = _eXosip_call_retry_request (jc, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for authentication\n")); } jd->d_retry++; } } else if (out_tr != NULL && (out_tr->state == ICT_TERMINATED || out_tr->state == NICT_TERMINATED || out_tr->state == ICT_COMPLETED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code >= 300 && out_tr->last_response->status_code <= 399)) { /* retry with credential */ int i; i = _eXosip_call_retry_request (jc, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for redirection\n")); } } } } } #ifndef MINISIZE for (js = eXosip.j_subscribes; js != NULL; js = js->next) { if (js->s_id < 1) { } else if (js->s_dialogs == NULL) { osip_transaction_t *out_tr = NULL; out_tr = js->s_out_tr; if (out_tr != NULL && (out_tr->state == NICT_TERMINATED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code == 401 || out_tr->last_response->status_code == 407)) { /* retry with credential */ if (js->s_retry < 3) { int i; i = _eXosip_subscribe_send_request_with_credential (js, NULL, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone msg for authentication\n")); } js->s_retry++; } } } for (jd = js->s_dialogs; jd != NULL; jd = jd->next) { if (jd->d_dialog != NULL) /* finished call */ { if (jd->d_id >= 1) { osip_transaction_t *out_tr = NULL; out_tr = osip_list_get (jd->d_out_trs, 0); if (out_tr == NULL) out_tr = js->s_out_tr; if (out_tr != NULL && (out_tr->state == NICT_TERMINATED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code == 401 || out_tr->last_response->status_code == 407)) { /* retry with credential */ if (jd->d_retry < 3) { int i; i = _eXosip_subscribe_send_request_with_credential (js, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone suscbribe for authentication\n")); } jd->d_retry++; } } else if (js->s_reg_period == 0 || out_tr == NULL) { } else if (now - out_tr->birth_time > js->s_reg_period - 60) { /* will expires in 60 sec: send refresh! */ int i; i = _eXosip_subscribe_automatic_refresh(js, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone subscribe for refresh\n")); } } } } } } for (jn = eXosip.j_notifies; jn != NULL; jn = jn->next) { for (jd = jn->n_dialogs; jd != NULL; jd = jd->next) { if (jd->d_dialog != NULL) /* finished call */ { if (jd->d_id >= 1) { osip_transaction_t *out_tr = NULL; out_tr = osip_list_get (jd->d_out_trs, 0); if (out_tr != NULL && (out_tr->state == NICT_TERMINATED || out_tr->state == NICT_COMPLETED) && now - out_tr->birth_time < 120 && out_tr->orig_request != NULL && out_tr->last_response != NULL && (out_tr->last_response->status_code == 401 || out_tr->last_response->status_code == 407)) { /* retry with credential */ if (jd->d_retry < 3) { int i; i = _eXosip_insubscription_send_request_with_credential (jn, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not clone notify for authentication\n")); } jd->d_retry++; } } } } } } #endif for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) { if (jr->r_id >= 1 && jr->r_last_tr != NULL) { if (jr->r_reg_period != 0 && now - jr->r_last_tr->birth_time > 900) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } else if (jr->r_reg_period != 0 && now - jr->r_last_tr->birth_time > jr->r_reg_period - 60) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } else if (jr->r_reg_period != 0 && now - jr->r_last_tr->birth_time > 120 && (jr->r_last_tr->last_response == NULL || (!MSG_IS_STATUS_2XX (jr->r_last_tr->last_response)))) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } else if (now - jr->r_last_tr->birth_time < 120 && jr->r_last_tr->orig_request != NULL && (jr->r_last_tr->last_response != NULL && (jr->r_last_tr->last_response->status_code == 401 || jr->r_last_tr->last_response->status_code == 407))) { if (jr->r_retry < 3) { /* TODO: improve support for several retries when several credentials are needed */ eXosip_register_send_register (jr->r_id, NULL); jr->r_retry++; } } } } }
void eXosip_automatic_refresh (void) { eXosip_subscribe_t *js; eXosip_dialog_t *jd; eXosip_reg_t *jr; time_t now; now = time (NULL); for (js = eXosip.j_subscribes; js != NULL; js = js->next) { for (jd = js->s_dialogs; jd != NULL; jd = jd->next) { if (jd->d_dialog != NULL && (jd->d_id >= 1)) /* finished call */ { osip_transaction_t *out_tr = NULL; out_tr = osip_list_get (jd->d_out_trs, 0); if (out_tr == NULL) out_tr = js->s_out_tr; if (js->s_reg_period == 0 || out_tr == NULL) { } else if (now - out_tr->birth_time > js->s_reg_period - 60) { /* will expires in 60 sec: send refresh! */ int i; i = _eXosip_subscribe_automatic_refresh(js, jd, out_tr); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: could not send subscribe for refresh\n")); } } } } } for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) { if (jr->r_id >= 1 && jr->r_last_tr != NULL) { if (jr->r_reg_period == 0) { /* skip refresh! */ } else if (now - jr->r_last_tr->birth_time > 900) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } else if (now - jr->r_last_tr->birth_time > jr->r_reg_period - 60) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } else if (now - jr->r_last_tr->birth_time > 120 && (jr->r_last_tr->last_response == NULL || (!MSG_IS_STATUS_2XX (jr->r_last_tr->last_response)))) { /* automatic refresh */ eXosip_register_send_register (jr->r_id, NULL); } } } }
/* * 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; }
NS_EVENT Node::ReportRCVEvent(osip_message_t *M) { osip_generic_param_t *param ; osip_uri_param_get_byname(M->from->gen_params,"user",¶m) ; // if(!strcmp(param->gvalue,"multicast")) { if(MSG_IS_REQUEST(M)) { return MULTICAST_REQ_RCV ; } else { if(MSG_IS_STATUS_2XX(M)) return MULTICAST_RESP_2XX ; else return EVT_OTHER ; } } // else if(!strcmp(param->gvalue,"join")) { if(MSG_IS_REQUEST(M)) { return JOIN_REQ_RCV ; } else { if(MSG_IS_STATUS_2XX(M)) return JOIN_RESP_2XX ; else if(MSG_IS_STATUS_3XX(M)) return JOIN_RESP_3XX ; else return EVT_OTHER ; } } // else if(!strcmp(param->gvalue,"findsucc")) { if(MSG_IS_REQUEST(M)) { return FINDSUCC_REQ_RCV ; } else { if(MSG_IS_STATUS_2XX(M)) return FINDSUCC_RESP_2XX ; else if(MSG_IS_STATUS_3XX(M)) return FINDSUCC_RESP_3XX ; else return EVT_OTHER ; } } // else if(!strcmp(param->gvalue,"stabilize")) { if(MSG_IS_REQUEST(M)) { return STABILIZE_REQ_RCV ; } else { if(MSG_IS_STATUS_2XX(M)) return STABILIZE_RESP_2XX ; else return EVT_OTHER ; } } // else if(!strcmp(param->gvalue,"leave")) { if(MSG_IS_REQUEST(M)) { return LEAVE_REQ_RCV ; } else return EVT_OTHER ; } // else if(!strcmp(param->gvalue,"user_registration")) { if(MSG_IS_REQUEST(M)) { return USER_REG_RCV ; } else if(MSG_IS_STATUS_2XX(M)) return USER_REG_RESP_2XX; else if(MSG_IS_STATUS_3XX(M)) return USER_REG_RESP_3XX; else return EVT_OTHER ; } else if(!strcmp(param->gvalue,"red_register")) { if(MSG_IS_REQUEST(M)) return RED_REGISTER_RCV; else if(MSG_IS_STATUS_2XX(M)) return RED_REGISTER_RESP_2XX; else return EVT_OTHER; } // else if(!strcmp(param->gvalue,"user_query")) { if(MSG_IS_REQUEST(M)) { return USER_QUERY_RCV ; } else if(MSG_IS_STATUS_2XX(M)) return USER_QUERY_RESP_2XX; else if(MSG_IS_STATUS_3XX(M)) return USER_QUERY_RESP_3XX; else return EVT_OTHER ; } // else { return EVT_OTHER ; } }
static int __osip_dialog_init (osip_dialog_t ** dialog, osip_message_t * invite, osip_message_t * response, osip_from_t * local, osip_to_t * remote, osip_message_t * remote_msg) { int i; int pos; osip_generic_param_t *tag; *dialog = NULL; if (response == NULL) return OSIP_BADPARAMETER; if (response->cseq == NULL || local == NULL || remote == NULL) return OSIP_SYNTAXERROR; (*dialog) = (osip_dialog_t *) osip_malloc (sizeof (osip_dialog_t)); if (*dialog == NULL) return OSIP_NOMEM; memset (*dialog, 0, sizeof (osip_dialog_t)); (*dialog)->your_instance = NULL; if (MSG_IS_STATUS_2XX (response)) (*dialog)->state = DIALOG_CONFIRMED; else /* 1XX */ (*dialog)->state = DIALOG_EARLY; i = osip_call_id_to_str (response->call_id, &((*dialog)->call_id)); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } i = osip_to_get_tag (local, &tag); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } (*dialog)->local_tag = osip_strdup (tag->gvalue); i = osip_from_get_tag (remote, &tag); if (i == 0) (*dialog)->remote_tag = osip_strdup (tag->gvalue); /* VR-2785: remember line value */ if (invite) { osip_uri_param_t *line_param; i = osip_uri_param_get_byname (&invite->req_uri->url_params, "line", &line_param); if (i == 0 && line_param != NULL && line_param->gvalue != NULL) (*dialog)->line_param = osip_strdup (line_param->gvalue); } osip_list_init (&(*dialog)->route_set); pos = 0; while (!osip_list_eol (&response->record_routes, pos)) { osip_record_route_t *rr; osip_record_route_t *rr2; rr = (osip_record_route_t *) osip_list_get (&response->record_routes, pos); i = osip_record_route_clone (rr, &rr2); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } if (invite == NULL) osip_list_add (&(*dialog)->route_set, rr2, 0); else osip_list_add (&(*dialog)->route_set, rr2, -1); pos++; } /* local_cseq is set to response->cseq->number for better handling of bad UA */ (*dialog)->local_cseq = osip_atoi (response->cseq->number); i = osip_from_clone (remote, &((*dialog)->remote_uri)); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } i = osip_to_clone (local, &((*dialog)->local_uri)); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } { osip_contact_t *contact; if (!osip_list_eol (&remote_msg->contacts, 0)) { contact = osip_list_get (&remote_msg->contacts, 0); i = osip_contact_clone (contact, &((*dialog)->remote_contact_uri)); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_dialog_free (*dialog); *dialog = NULL; return i; } } else { (*dialog)->remote_contact_uri = NULL; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "Remote UA is not compliant: missing a contact in remote message!\n")); } } (*dialog)->secure = -1; /* non secure */ return OSIP_SUCCESS; }
int eXosip_call_send_answer (int tid, int status, osip_message_t * answer) { eXosip_dialog_t *jd = NULL; eXosip_call_t *jc = NULL; osip_transaction_t *tr = NULL; osip_event_t *evt_answer; if (tid < 0) { osip_message_free (answer); return OSIP_BADPARAMETER; } if (status <= 100) { osip_message_free (answer); return OSIP_BADPARAMETER; } if (status > 699) { osip_message_free (answer); return OSIP_BADPARAMETER; } if (tid > 0) { _eXosip_call_transaction_find (tid, &jc, &jd, &tr); } if (jd == NULL || tr == NULL || tr->orig_request == NULL || tr->orig_request->sip_method == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No call here or no transaction for call\n")); osip_message_free (answer); return OSIP_NOTFOUND; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (status >= 200 && status <= 299) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: Wrong parameter?\n")); osip_message_free (answer); return OSIP_BADPARAMETER; } } } /* is the transaction already answered? */ if (tr->state == IST_COMPLETED || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED || tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: transaction already answered\n")); osip_message_free (answer); return OSIP_WRONG_STATE; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { osip_message_t *response; return _eXosip_answer_invite_123456xx (jc, jd, status, &response, 1); } osip_message_free (answer); return OSIP_BADPARAMETER; } if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) { if (MSG_IS_STATUS_2XX (answer) && jd != NULL) { if (status >= 200 && status < 300 && jd != NULL) { eXosip_dialog_set_200ok (jd, answer); /* wait for a ACK */ osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); } } } evt_answer = osip_new_outgoing_sipmessage (answer); evt_answer->transactionid = tr->transactionid; osip_transaction_add_event (tr, evt_answer); eXosip_update (); __eXosip_wakeup (); return OSIP_SUCCESS; }
void nist_rcv_request (osip_transaction_t * nist, osip_event_t * evt) { int i; osip_t *osip = (osip_t *) nist->config; if (nist->state == NIST_PRE_TRYING) /* announce new REQUEST */ { /* Here we have ist->orig_request == NULL */ nist->orig_request = evt->sip; if (MSG_IS_REGISTER (evt->sip)) __osip_message_callback (OSIP_NIST_REGISTER_RECEIVED, nist, nist->orig_request); else if (MSG_IS_BYE (evt->sip)) __osip_message_callback (OSIP_NIST_BYE_RECEIVED, nist, nist->orig_request); else if (MSG_IS_OPTIONS (evt->sip)) __osip_message_callback (OSIP_NIST_OPTIONS_RECEIVED, nist, nist->orig_request); else if (MSG_IS_INFO (evt->sip)) __osip_message_callback (OSIP_NIST_INFO_RECEIVED, nist, nist->orig_request); else if (MSG_IS_CANCEL (evt->sip)) __osip_message_callback (OSIP_NIST_CANCEL_RECEIVED, nist, nist->orig_request); else if (MSG_IS_NOTIFY (evt->sip)) __osip_message_callback (OSIP_NIST_NOTIFY_RECEIVED, nist, nist->orig_request); else if (MSG_IS_SUBSCRIBE (evt->sip)) __osip_message_callback (OSIP_NIST_SUBSCRIBE_RECEIVED, nist, nist->orig_request); else __osip_message_callback (OSIP_NIST_UNKNOWN_REQUEST_RECEIVED, nist, nist->orig_request); } else /* NIST_PROCEEDING or NIST_COMPLETED */ { /* delete retransmission */ osip_message_free (evt->sip); __osip_message_callback (OSIP_NIST_REQUEST_RECEIVED_AGAIN, nist, nist->orig_request); if (nist->last_response != NULL) /* retransmit last response */ { osip_via_t *via; via = (osip_via_t *) osip_list_get (nist->last_response->vias, 0); if (via) { char *host; int port; osip_generic_param_t *maddr; osip_generic_param_t *received; osip_generic_param_t *rport; osip_via_param_get_byname (via, "maddr", &maddr); osip_via_param_get_byname (via, "received", &received); osip_via_param_get_byname (via, "rport", &rport); /* 1: user should not use the provided information (host and port) if they are using a reliable transport. Instead, they should use the already open socket attached to this transaction. */ /* 2: check maddr and multicast usage */ if (maddr != NULL) host = maddr->gvalue; /* we should check if this is a multicast address and use set the "ttl" in this case. (this must be done in the UDP message (not at the SIP layer) */ else if (received != NULL) host = received->gvalue; else host = via->host; if (rport == NULL || rport->gvalue == NULL) { if (via->port != NULL) port = osip_atoi (via->port); else port = 5060; } else port = osip_atoi (rport->gvalue); i = osip->cb_send_message (nist, nist->last_response, host, port, nist->out_socket); } else i = -1; if (i != 0) { nist_handle_transport_error (nist, i); return; } else { if (MSG_IS_STATUS_1XX (nist->last_response)) __osip_message_callback (OSIP_NIST_STATUS_1XX_SENT, nist, nist->last_response); else if (MSG_IS_STATUS_2XX (nist->last_response)) __osip_message_callback (OSIP_NIST_STATUS_2XX_SENT_AGAIN, nist, nist->last_response); else __osip_message_callback (OSIP_NIST_STATUS_3456XX_SENT_AGAIN, nist, nist->last_response); return; } } /* we are already in the proper state */ return; } /* we come here only if it was the first REQUEST received */ __osip_transaction_set_state (nist, NIST_TRYING); }
int eXosip_insubscription_send_answer (int tid, int status, osip_message_t * answer) { int i = -1; eXosip_dialog_t *jd = NULL; eXosip_notify_t *jn = NULL; osip_transaction_t *tr = NULL; osip_event_t *evt_answer; if (tid > 0) { _eXosip_insubscription_transaction_find (tid, &jn, &jd, &tr); } if (jd == NULL || tr == NULL || tr->orig_request == NULL || tr->orig_request->sip_method == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: No incoming subscription here?\n")); osip_message_free (answer); return -1; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) { if (status >= 101 && status <= 199) { } else if (status >= 300 && status <= 699) { } else { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: Wrong parameter?\n")); return -1; } } } /* is the transaction already answered? */ if (tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: transaction already answered\n")); osip_message_free (answer); return -1; } if (answer == NULL) { if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) { if (status < 200) i = _eXosip_insubscription_answer_1xx (jn, jd, status); else i = _eXosip_insubscription_answer_3456xx (jn, jd, status); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: cannot send response!\n")); return -1; } } else { /* TODO */ OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: a response must be given!\n")); return -1; } return 0; } else { i = 0; } if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) { if (MSG_IS_STATUS_1XX (answer)) { } else if (MSG_IS_STATUS_2XX (answer)) { eXosip_dialog_set_200ok (jd, answer); osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); } else if (answer->status_code >= 300 && answer->status_code <= 699) { i = 0; } else { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "eXosip: wrong status code (101<status<699)\n")); osip_message_free (answer); return -1; } if (i != 0) { osip_message_free (answer); return -1; } } evt_answer = osip_new_outgoing_sipmessage (answer); evt_answer->transactionid = tr->transactionid; osip_transaction_add_event (tr, evt_answer); eXosip_update (); __eXosip_wakeup (); return 0; }
int osip_dialog_init_as_uas (osip_dialog_t ** dialog, osip_message_t * invite, osip_message_t * response) { int i; int pos; osip_generic_param_t *tag; (*dialog) = (osip_dialog_t *) osip_malloc (sizeof (osip_dialog_t)); if (*dialog == NULL) return -1; (*dialog)->type = CALLEE; if (MSG_IS_STATUS_2XX (response)) (*dialog)->state = DIALOG_CONFIRMED; else /* 1XX */ (*dialog)->state = DIALOG_EARLY; i = osip_call_id_to_str (response->call_id, &((*dialog)->call_id)); if (i != 0) goto diau_error_0; i = osip_to_get_tag (response->to, &tag); if (i != 0) goto diau_error_1; (*dialog)->local_tag = osip_strdup (tag->gvalue); i = osip_from_get_tag (response->from, &tag); if (i != 0) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "Remote UA is not compliant: missing a tag in response!\n")); (*dialog)->remote_tag = NULL; } else (*dialog)->remote_tag = osip_strdup (tag->gvalue); (*dialog)->route_set = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); osip_list_init ((*dialog)->route_set); pos = 0; while (!osip_list_eol (response->record_routes, pos)) { osip_record_route_t *rr; osip_record_route_t *rr2; rr = (osip_record_route_t *) osip_list_get (response->record_routes, pos); i = osip_record_route_clone (rr, &rr2); if (i != 0) goto diau_error_2; osip_list_add ((*dialog)->route_set, rr2, -1); pos++; } /* local_cseq is set to response->cseq->number for better handling of bad UA */ (*dialog)->local_cseq = osip_atoi (response->cseq->number); (*dialog)->remote_cseq = osip_atoi (response->cseq->number); i = osip_from_clone (response->from, &((*dialog)->remote_uri)); if (i != 0) goto diau_error_3; i = osip_to_clone (response->to, &((*dialog)->local_uri)); if (i != 0) goto diau_error_4; { osip_contact_t *contact; if (!osip_list_eol (invite->contacts, 0)) { contact = osip_list_get (invite->contacts, 0); i = osip_contact_clone (contact, &((*dialog)->remote_contact_uri)); if (i != 0) goto diau_error_5; } else { (*dialog)->remote_contact_uri = NULL; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, "Remote UA is not compliant: missing a contact in response!\n")); } } (*dialog)->secure = -1; /* non secure */ return 0; diau_error_5: osip_from_free ((*dialog)->local_uri); diau_error_4: osip_from_free ((*dialog)->remote_uri); diau_error_3: diau_error_2: osip_list_special_free ((*dialog)->route_set, (void *(*)(void *)) &osip_record_route_free); osip_free ((*dialog)->remote_tag); osip_free ((*dialog)->local_tag); diau_error_1: osip_free ((*dialog)->call_id); diau_error_0: OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Could not establish dialog!\n")); osip_free (*dialog); *dialog = NULL; return -1; }