void nict_snd_request (osip_transaction_t * nict, osip_event_t * evt) { int i; osip_t *osip = (osip_t *) nict->config; /* Here we have ict->orig_request == NULL */ nict->orig_request = evt->sip; i = osip->cb_send_message (nict, evt->sip, nict->nict_context->destination, nict->nict_context->port, nict->out_socket); if (i == 0) { /* invoke the right callback! */ if (MSG_IS_REGISTER (evt->sip)) __osip_message_callback (OSIP_NICT_REGISTER_SENT, nict, nict->orig_request); else if (MSG_IS_BYE (evt->sip)) __osip_message_callback (OSIP_NICT_BYE_SENT, nict, nict->orig_request); else if (MSG_IS_OPTIONS (evt->sip)) __osip_message_callback (OSIP_NICT_OPTIONS_SENT, nict, nict->orig_request); else if (MSG_IS_INFO (evt->sip)) __osip_message_callback (OSIP_NICT_INFO_SENT, nict, nict->orig_request); else if (MSG_IS_CANCEL (evt->sip)) __osip_message_callback (OSIP_NICT_CANCEL_SENT, nict, nict->orig_request); else if (MSG_IS_NOTIFY (evt->sip)) __osip_message_callback (OSIP_NICT_NOTIFY_SENT, nict, nict->orig_request); else if (MSG_IS_SUBSCRIBE (evt->sip)) __osip_message_callback (OSIP_NICT_SUBSCRIBE_SENT, nict, nict->orig_request); else __osip_message_callback (OSIP_NICT_UNKNOWN_REQUEST_SENT, nict, nict->orig_request); __osip_transaction_set_state (nict, NICT_TRYING); } else { nict_handle_transport_error (nict, i); } }
static int udp_tl_send_message (osip_transaction_t * tr, osip_message_t * sip, char *host, int port, int out_socket) { int len = 0; size_t length = 0; struct addrinfo *addrinfo; struct __eXosip_sockaddr addr; char *message; char *crypt_date; char ipbuf[INET6_ADDRSTRLEN]; int i; if (udp_socket <= 0) return -1; if (host == NULL) { host = sip->req_uri->host; if (sip->req_uri->port != NULL) port = osip_atoi (sip->req_uri->port); else port = 5060; } eXtl_update_local_target (sip); i = -1; #ifndef MINISIZE if (tr != NULL && tr->record.name[0] != '\0' && tr->record.srventry[0].srv[0] != '\0') { /* always choose the first here. if a network error occur, remove first entry and replace with next entries. */ osip_srv_entry_t *srv; int n = 0; for (srv = &tr->record.srventry[0]; n < 10 && tr->record.srventry[0].srv[0]; srv = &tr->record.srventry[0]) { i = eXosip_get_addrinfo (&addrinfo, srv->srv, srv->port, IPPROTO_UDP); if (i == 0) { host = srv->srv; port = srv->port; break; } memmove (&tr->record.srventry[0], &tr->record.srventry[1], 9 * sizeof (osip_srv_entry_t)); memset (&tr->record.srventry[9], 0, sizeof (osip_srv_entry_t)); i = -1; /* copy next element */ n++; } } #endif /* if SRV was used, distination may be already found */ if (i != 0) { i = eXosip_get_addrinfo (&addrinfo, host, port, IPPROTO_UDP); } if (i != 0) { return -1; } memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); len = addrinfo->ai_addrlen; eXosip_freeaddrinfo (addrinfo); /* remove preloaded route if there is no tag in the To header */ { osip_route_t *route = NULL; osip_generic_param_t *tag = NULL; osip_message_get_route (sip, 0, &route); osip_to_get_tag (sip->to, &tag); if (tag == NULL && route != NULL && route->url != NULL) { osip_list_remove (&sip->routes, 0); } i = osip_message_to_str (sip, &message, &length); if (tag == NULL && route != NULL && route->url != NULL) { osip_list_add (&sip->routes, route, 0); } } if (i != 0 || length <= 0) { return -1; } switch (((struct sockaddr *) &addr)->sa_family) { case AF_INET: inet_ntop (((struct sockaddr *) &addr)->sa_family, &(((struct sockaddr_in *) &addr)->sin_addr), ipbuf, sizeof (ipbuf)); break; case AF_INET6: inet_ntop (((struct sockaddr *) &addr)->sa_family, &(((struct sockaddr_in6 *) &addr)->sin6_addr), ipbuf, sizeof (ipbuf)); break; default: strncpy (ipbuf, "(unknown)", sizeof (ipbuf)); break; } OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "Message sent: (to dest=%s:%i)\n%s\n", ipbuf, port, message)); if (tr != NULL) { if (tr->ict_context != NULL) osip_ict_set_destination (tr->ict_context, osip_strdup (ipbuf), port); if (tr->nict_context != NULL) osip_nict_set_destination (tr->nict_context, osip_strdup (ipbuf), port); } //SIP加密点 crypt_date = (char *)malloc(length); memcpy(crypt_date,(const char *)message, length); #ifdef ENABLE_MYCRYPT CRYPT_DATA_SIP((unsigned char *)crypt_date,length); #endif // ENABLE_MYCRYPT if (0 > sendto (udp_socket, (const void *) crypt_date, length, 0, (struct sockaddr *) &addr, len)) { #ifdef WIN32 if (WSAECONNREFUSED == WSAGetLastError ()) #else if (ECONNREFUSED == errno) #endif { /* This can be considered as an error, but for the moment, I prefer that the application continue to try sending message again and again... so we are not in a error case. Nevertheless, this error should be announced! ALSO, UAS may not have any other options than retry always on the same port. */ osip_free (message); return 1; } else { #ifndef MINISIZE /* delete first SRV entry that is not reachable */ if (tr != NULL && tr->record.name[0] != '\0' && tr->record.srventry[0].srv[0] != '\0') { memmove (&tr->record.srventry[0], &tr->record.srventry[1], 9 * sizeof (osip_srv_entry_t)); memset (&tr->record.srventry[9], 0, sizeof (osip_srv_entry_t)); osip_free (message); return OSIP_SUCCESS; /* retry for next retransmission! */ } #endif /* SIP_NETWORK_ERROR; */ osip_free (message); return -1; } } if (eXosip.keep_alive > 0) { if (MSG_IS_REGISTER (sip)) { eXosip_reg_t *reg = NULL; if (_eXosip_reg_find (®, tr) == 0) { memcpy (&(reg->addr), &addr, len); reg->len = len; } } } osip_free (message); return OSIP_SUCCESS; }
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); }
/* * PROXY_REQUEST * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error * * RFC3261 * Section 16.3: Proxy Behavior - Request Validation * 1. Reasonable Syntax * 2. URI scheme * 3. Max-Forwards * 4. (Optional) Loop Detection * 5. Proxy-Require * 6. Proxy-Authorization * * Section 16.6: Proxy Behavior - Request Forwarding * 1. Make a copy of the received request * 2. Update the Request-URI * 3. Update the Max-Forwards header field * 4. Optionally add a Record-route header field value * 5. Optionally add additional header fields * 6. Postprocess routing information * 7. Determine the next-hop address, port, and transport * 8. Add a Via header field value * 9. Add a Content-Length header field if necessary * 10. Forward the new request * 11. Set timer C */ int proxy_request (sip_ticket_t *ticket) { int i; int sts; int type; struct in_addr sendto_addr; osip_uri_t *url; int port; char *buffer; int buflen; osip_message_t *request; struct sockaddr_in *from; DEBUGC(DBCLASS_PROXY,"proxy_request"); if (ticket==NULL) { ERROR("proxy_request: called with NULL ticket"); return STS_FAILURE; } request=ticket->sipmsg; from=&ticket->from; /* * RFC 3261, Section 16.4 * Proxy Behavior - Route Information Preprocessing * (process Route header) */ route_preprocess(ticket); /* * figure out whether this is an incoming or outgoing request * by doing a lookup in the registration table. */ #define _OLD_DIRECTION_EVALUATION 0 #if _OLD_DIRECTION_EVALUATION type = 0; for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/ if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host: "*NULL*"); break; } /* outgoing request ('from' == 'reg') */ if (compare_url(request->from->url, urlmap[i].reg_url)==STS_SUCCESS) { type=REQTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host: "*NULL*"); break; } } #else type = 0; /* * did I receive the telegram from a REGISTERED host? * -> it must be an OUTGOING request */ 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_request: cannot resolve host [%s]", urlmap[i].true_url); } else { DEBUGC(DBCLASS_PROXY, "proxy_request: 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=REQTYP_OUTGOING; break; } } } /* * is the telegram directed to an internally registered host? * -> it must be an INCOMING request */ if (type == 0) { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* RFC3261: * 'To' contains a display name (Bob) and a SIP or SIPS URI * (sip:[email protected]) towards which the request was originally * directed. Display names are described in RFC 2822 [3]. */ /* So this means, that we must check the SIP URI supplied with the * INVITE method, as this points to the real wanted target. * Q: does there exist a situation where the SIP URI itself does * point to "somewhere" but the To: points to the correct UA? * So for now, we just look at both of them (SIP URI and To: header) */ /* incoming request (SIP URI == 'masq') || ((SIP URI == 'reg') && !REGISTER)*/ if ((compare_url(request->req_uri, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->req_uri, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; break; } /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/ if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; break; } } } #endif ticket->direction=type; /* * logging of passing calls */ if (configuration.log_calls) { osip_uri_t *cont_url = NULL; if (!osip_list_eol(request->contacts, 0)) cont_url = ((osip_contact_t*)(request->contacts->node->element))->url; /* INVITE */ if (MSG_IS_INVITE(request)) { if (cont_url) { INFO("%s Call from: %s@%s", (type==REQTYP_INCOMING) ? "Incoming":"Outgoing", cont_url->username ? cont_url->username:"******", cont_url->host ? cont_url->host : "*NULL*"); } else { INFO("%s Call (w/o contact header) from: %s@%s", (type==REQTYP_INCOMING) ? "Incoming":"Outgoing", request->from->url->username ? request->from->url->username:"******", request->from->url->host ? request->from->url->host : "*NULL*"); } /* BYE / CANCEL */ } else if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { if (cont_url) { INFO("Ending Call from: %s@%s", cont_url->username ? cont_url->username:"******", cont_url->host ? cont_url->host : "*NULL*"); } else { INFO("Ending Call (w/o contact header) from: %s@%s", request->from->url->username ? request->from->url->username:"******", request->from->url->host ? request->from->url->host : "*NULL*"); } } } /* log_calls */ /* * RFC 3261, Section 16.6 step 1 * Proxy Behavior - Request Forwarding - Make a copy */ /* nothing to do here, copy is ready in 'request'*/ /* get destination address */ url=osip_message_get_uri(request); switch (type) { /* * from an external host to the internal masqueraded host */ case REQTYP_INCOMING: DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host: "*NULL*"); /* * RFC 3261, Section 16.6 step 2 * Proxy Behavior - Request Forwarding - Request-URI * (rewrite request URI to point to the real host) */ /* 'i' still holds the valid index into the URLMAP table */ if (check_rewrite_rq_uri(request) == STS_TRUE) { proxy_rewrite_request_uri(request, i); } /* if this is CANCEL/BYE request, stop RTP proxying */ if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { /* stop the RTP proxying stream(s) */ rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING); /* check for incoming request */ } else if (MSG_IS_INVITE(request)) { /* Rewrite the body */ sts = proxy_rewrite_invitation_body(request, DIR_INCOMING); } else if (MSG_IS_ACK(request)) { /* Rewrite the body */ sts = proxy_rewrite_invitation_body(request, DIR_INCOMING); } break; /* * from the internal masqueraded host to an external host */ case REQTYP_OUTGOING: DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host: "*NULL*"); /* * RFC 3261, Section 16.6 step 2 * Proxy Behavior - Request Forwarding - Request-URI */ /* nothing to do for an outgoing request */ /* if it is addressed to myself, then it must be some request * method that I as a proxy do not support. Reject */ #if 0 /* careful - an internal UA might send an request to another internal UA. This would be caught here, so don't do this. This situation should be caught in the default part of the CASE statement below */ if (is_sipuri_local(ticket) == STS_TRUE) { WARN("unsupported request [%s] directed to proxy from %s@%s -> %s@%s", request->sip_method? request->sip_method:"*NULL*", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host : "*NULL*", url->username? url->username : "******", url->host? url->host : "*NULL*"); sip_gen_response(ticket, 403 /*forbidden*/); return STS_FAILURE; } #endif /* rewrite Contact header to represent the masqued address */ sip_rewrite_contact(ticket, DIR_OUTGOING); /* if an INVITE, rewrite body */ if (MSG_IS_INVITE(request)) { sts = proxy_rewrite_invitation_body(request, DIR_OUTGOING); } else if (MSG_IS_ACK(request)) { sts = proxy_rewrite_invitation_body(request, DIR_OUTGOING); } /* if this is CANCEL/BYE request, stop RTP proxying */ if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { /* stop the RTP proxying stream(s) */ rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING); rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING); } break; default: DEBUGC(DBCLASS_PROXY, "request [%s] from/to unregistered UA " "(RQ: %s@%s -> %s@%s)", request->sip_method? request->sip_method:"*NULL*", request->from->url->username? request->from->url->username:"******", request->from->url->host? request->from->url->host : "*NULL*", url->username? url->username : "******", url->host? url->host : "*NULL*"); /* * we may end up here for two reasons: * 1) An incomming request (from outbound) that is directed to * an unknown (not registered) local UA * 2) an outgoing request from a local UA that is not registered. * * Case 1) we should probably answer with "404 Not Found", * case 2) more likely a "403 Forbidden" * * How about "408 Request Timeout" ? * */ sip_gen_response(ticket, 408 /* Request Timeout */); return STS_FAILURE; } /* * RFC 3261, Section 16.6 step 3 * Proxy Behavior - Request Forwarding - Max-Forwards * (if Max-Forwards header exists, decrement by one, if it does not * exist, add a new one with value SHOULD be 70) */ { osip_header_t *max_forwards; int forwards_count = DEFAULT_MAXFWD; char mfwd[8]; osip_message_get_max_forwards(request, 0, &max_forwards); if (max_forwards == NULL) { sprintf(mfwd, "%i", forwards_count); osip_message_set_max_forwards(request, mfwd); } else { if (max_forwards->hvalue) { forwards_count = atoi(max_forwards->hvalue); forwards_count -=1; osip_free (max_forwards->hvalue); } sprintf(mfwd, "%i", forwards_count); max_forwards->hvalue = osip_strdup(mfwd); } DEBUGC(DBCLASS_PROXY,"setting Max-Forwards=%s",mfwd); } /* * RFC 3261, Section 16.6 step 4 * Proxy Behavior - Request Forwarding - Add a Record-route header */ /* * for ALL incoming requests, 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 == REQTYP_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); } /* * RFC 3261, Section 16.6 step 5 * Proxy Behavior - Request Forwarding - Add Additional Header Fields */ /* NOT IMPLEMENTED (optional) */ /* * RFC 3261, Section 16.6 step 6 * Proxy Behavior - Request Forwarding - Postprocess routing information * * If the copy contains a Route header field, the proxy MUST * inspect the URI in its first value. If that URI does not * contain an lr parameter, the proxy MUST modify the copy as * follows: * * - The proxy MUST place the Request-URI into the Route header * field as the last value. * * - The proxy MUST then place the first Route header field value * into the Request-URI and remove that value from the Route * header field. */ #if 0 route_postprocess(ticket); #endif /* * RFC 3261, Section 16.6 step 7 * Proxy Behavior - Determine Next-Hop Address */ /*&&&& priority probably should be: * 1) Route header * 2) fixed outbound proxy * 3) SIP URI */ /* * fixed or domain outbound proxy defined ? */ if ((type == REQTYP_OUTGOING) && (sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) { DEBUGC(DBCLASS_PROXY, "proxy_request: 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 == REQTYP_OUTGOING) && (request->routes && !osip_list_eol(request->routes, 0))) { sts=route_determine_nexthop(ticket, &sendto_addr, &port); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_request: route_determine_nexthop failed"); return STS_FAILURE; } DEBUGC(DBCLASS_PROXY, "proxy_request: have Route header to %s:%i", utils_inet_ntoa(sendto_addr), port); /* * destination from SIP URI */ } else { /* get the destination from the SIP URI */ sts = get_ip_by_host(url->host, &sendto_addr); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]", url->host); return STS_FAILURE; } if (url->port) { port=atoi(url->port); } else { port=SIP_PORT; } DEBUGC(DBCLASS_PROXY, "proxy_request: have SIP URI to %s:%i", url->host, port); } /* * RFC 3261, Section 16.6 step 8 * Proxy Behavior - Add a Via header field value */ /* add my Via header line (outbound interface)*/ if (type == REQTYP_INCOMING) { sts = sip_add_myvia(ticket, IF_INBOUND); if (sts == STS_FAILURE) { ERROR("adding my inbound via failed!"); } } else { sts = sip_add_myvia(ticket, IF_OUTBOUND); if (sts == STS_FAILURE) { ERROR("adding my outbound via failed!"); return STS_FAILURE; } } /* * RFC 3261, Section 16.6 step 9 * Proxy Behavior - Add a Content-Length header field if necessary */ /* not necessary, already in message and we do not support TCP */ /* * RFC 3261, Section 16.6 step 10 * Proxy Behavior - Forward the new request */ sts = sip_message_to_str(request, &buffer, &buflen); if (sts != 0) { ERROR("proxy_request: sip_message_to_str failed"); return STS_FAILURE; } sipsock_send(sendto_addr, port, ticket->protocol, buffer, buflen); osip_free (buffer); /* * RFC 3261, Section 16.6 step 11 * Proxy Behavior - Set timer C */ /* NOT IMPLEMENTED - does this really apply for stateless proxies? */ return STS_SUCCESS; }
int Node::SndResponse(int status , osip_message_t *request , osip_transaction_t *tr, REG_TYPE type , ChordId contact, BOOL IncludeSuccList) { char *message1; size_t length = 0; // osip_generic_param_t *tag; osip_message_t *response; osip_event_t *evt ; char *tmp; char * tmp_uri; int pos; int i; i = osip_message_init (&response); if (i != 0) return -1; osip_message_set_version (response, osip_strdup ("SIP/2.0")); osip_message_set_status_code (response, status); tmp = osip_strdup(osip_message_get_reason (status)); if (tmp == NULL) osip_message_set_reason_phrase (response, osip_strdup ("Unknown status code")); else osip_message_set_reason_phrase (response, tmp); osip_message_set_method (response, NULL); osip_message_set_uri (response, NULL); i = osip_to_clone (request->to, &(response->to)); if (i != 0) goto si2perror1; i = osip_to_get_tag (response->to, &tag); if (i != 0) { /* we only add a tag if it does not already contains one! */ if (status == 200 && MSG_IS_REGISTER (request)) { osip_to_set_tag (response->to, osip_to_tag_new_random ()); } else if (status >= 200) { osip_to_set_tag (response->to, osip_to_tag_new_random ()); } } i = osip_from_clone (request->from, &(response->from)); if (i != 0) goto si2perror1; pos = 0; while (!osip_list_eol (request->vias, pos)) { osip_via_t *via; osip_via_t *via2; via = (osip_via_t *) osip_list_get (request->vias, pos); i = osip_via_clone (via, &via2); if (i != -0) goto si2perror1; osip_list_add (response->vias, via2, -1); pos++; } i = osip_call_id_clone (request->call_id, &(response->call_id)); if (i != 0) goto si2perror1; i = osip_cseq_clone (request->cseq, &(response->cseq)); if (i != 0) goto si2perror1; //set server osip_message_set_server (response, osip_strdup ("SI2P")); /*add contact*/ //predecessor if(status == 200) { if(type == USER_REGISTRATION || type == TRANSFER_REGISTRATION || type == THIRD_PARTY) { osip_contact_t *tmp; char *dest; int pos=0; while(pos<osip_list_size(request->contacts)) { pos=osip_message_get_contact(request,0,&tmp); osip_contact_to_str(tmp,&dest); osip_message_set_contact(response,dest); if(dest) osip_free(dest) ; pos++; } } else { tmp_uri = ChordId2Uri(chordId,false); char * pre_uri = ChordId2Uri(getFingerTable()->getPredecessor(),false) ; char *ctt = (char *) osip_malloc(strlen(tmp_uri) + strlen(";predecessor=") + strlen(pre_uri) +1) ; if (ctt == NULL) return NULL; sprintf (ctt, "%s;predecessor=%s", tmp_uri,pre_uri); osip_free(tmp_uri) ; osip_free(pre_uri) ; osip_message_set_contact(response, ctt ); osip_free(ctt) ; } } else//302 { if(type == USER_REGISTRATION || type == TRANSFER_REGISTRATION || type == THIRD_PARTY) { tmp_uri = ChordId2Uri(contact,false); osip_message_set_contact(response,tmp_uri ); osip_free(tmp_uri) ; } else { tmp_uri = ChordId2Uri(contact,false) ; char *ctt = (char *) osip_malloc(strlen(tmp_uri) + strlen(";predecessor=notprovided") +1) ; if (ctt == NULL) return NULL; sprintf (ctt, "%s;predecessor=notprovided", tmp_uri); if(tmp_uri) osip_free(tmp_uri) ; osip_message_set_contact(response, ctt ); if(tmp_uri) osip_free(ctt) ; } } if(IncludeSuccList) { for(i = 0 ; i < getFingerTable()->getSuccNum() ; i++) { tmp_uri = ChordId2Uri(getFingerTable()->getSuccessor(i),false) ; osip_message_set_contact(response, tmp_uri ); osip_free(tmp_uri) ; } } i = osip_message_to_str(response, &message1, &length); LogStream("SEND======================================>>\n") ; LogStream(message1) ; if(message1) osip_free(message1) ; // printf("SEND======================================>>\n") ; // printf(message1) ; evt = osip_new_outgoing_sipmessage (response); evt->transactionid = tr->transactionid; osip_transaction_add_event(tr, evt); adosip->ThreadWakeUp(); return 0; si2perror1: osip_message_free (response); return -1; }
//--------------------------------------------------------------------- int Node::SndResponse4Query(int status, const char *contact, osip_transaction_t *tr, osip_message_t *request) { char *message1; size_t length = 0; // osip_generic_param_t *tag; osip_message_t *response; osip_event_t *evt ; char *tmp; int pos; int i; i = osip_message_init (&response); if (i != 0) return -1; osip_message_set_version (response, osip_strdup ("SIP/2.0")); osip_message_set_status_code (response, status); tmp = osip_strdup(osip_message_get_reason (status)); if (tmp == NULL) osip_message_set_reason_phrase (response, osip_strdup ("Unknown status code")); else osip_message_set_reason_phrase (response, tmp); osip_message_set_method (response, NULL); osip_message_set_uri (response, NULL); i = osip_to_clone (request->to, &(response->to)); if (i != 0) goto si2perror1; i = osip_to_get_tag (response->to, &tag); if (i != 0) { /* we only add a tag if it does not already contains one! */ if (status == 200 && MSG_IS_REGISTER (request)) { osip_to_set_tag (response->to, osip_to_tag_new_random ()); } else if (status >= 200) { osip_to_set_tag (response->to, osip_to_tag_new_random ()); } } i = osip_from_clone (request->from, &(response->from)); if (i != 0) goto si2perror1; pos = 0; while (!osip_list_eol (request->vias, pos)) { osip_via_t *via; osip_via_t *via2; via = (osip_via_t *) osip_list_get (request->vias, pos); i = osip_via_clone (via, &via2); if (i != -0) goto si2perror1; osip_list_add (response->vias, via2, -1); pos++; } i = osip_call_id_clone (request->call_id, &(response->call_id)); if (i != 0) goto si2perror1; i = osip_cseq_clone (request->cseq, &(response->cseq)); if (i != 0) goto si2perror1; //set server osip_message_set_server (response, osip_strdup ("SI2P")); /*add contact*/ if(contact !=NULL) osip_message_set_contact(response,contact); i = osip_message_to_str(response, &message1, &length); LogStream("SEND======================================>>\n") ; LogStream(message1) ; if(message1) osip_free(message1) ; evt = osip_new_outgoing_sipmessage (response); evt->transactionid = tr->transactionid; osip_transaction_add_event(tr, evt); adosip->ThreadWakeUp(); return 0; si2perror1: osip_message_free (response); return -1; }
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); }
void nict_snd_request (osip_transaction_t * nict, osip_event_t * evt) { int i; osip_t *osip = (osip_t *) nict->config; /* Here we have ict->orig_request == NULL */ nict->orig_request = evt->sip; i = osip->cb_send_message (nict, evt->sip, nict->nict_context->destination, nict->nict_context->port, nict->out_socket); if (i >= 0) { /* invoke the right callback! */ if (MSG_IS_REGISTER (evt->sip)) __osip_message_callback (OSIP_NICT_REGISTER_SENT, nict, nict->orig_request); else if (MSG_IS_BYE (evt->sip)) __osip_message_callback (OSIP_NICT_BYE_SENT, nict, nict->orig_request); else if (MSG_IS_OPTIONS (evt->sip)) __osip_message_callback (OSIP_NICT_OPTIONS_SENT, nict, nict->orig_request); else if (MSG_IS_INFO (evt->sip)) __osip_message_callback (OSIP_NICT_INFO_SENT, nict, nict->orig_request); else if (MSG_IS_CANCEL (evt->sip)) __osip_message_callback (OSIP_NICT_CANCEL_SENT, nict, nict->orig_request); else if (MSG_IS_NOTIFY (evt->sip)) __osip_message_callback (OSIP_NICT_NOTIFY_SENT, nict, nict->orig_request); else if (MSG_IS_SUBSCRIBE (evt->sip)) __osip_message_callback (OSIP_NICT_SUBSCRIBE_SENT, nict, nict->orig_request); else __osip_message_callback (OSIP_NICT_UNKNOWN_REQUEST_SENT, nict, nict->orig_request); #ifndef USE_BLOCKINGSOCKET /* stop timer E in reliable transport - non blocking socket: the message was just sent */ { osip_via_t *via; char *proto; int k; k = osip_message_get_via (nict->orig_request, 0, &via); /* get top via */ if (k < 0) { nict_handle_transport_error (nict, -1); return; } proto = via_get_protocol (via); if (proto == NULL) { nict_handle_transport_error (nict, -1); return; } if (i == 0) { /* but message was really sent */ if (osip_strcasecmp (proto, "TCP") != 0 && osip_strcasecmp (proto, "TLS") != 0 && osip_strcasecmp (proto, "SCTP") != 0) { } else { /* reliable protocol is used: */ nict->nict_context->timer_e_length = -1; /* E is not ACTIVE */ nict->nict_context->timer_e_start.tv_sec = -1; } } else { if (osip_strcasecmp (proto, "TCP") != 0 && osip_strcasecmp (proto, "TLS") != 0 && osip_strcasecmp (proto, "SCTP") != 0) { } else { /* reliable protocol is used: */ nict->nict_context->timer_e_length = DEFAULT_T1_TCP_PROGRESS; } } } #endif if (nict->nict_context->timer_e_length > 0) { osip_gettimeofday (&nict->nict_context->timer_e_start, NULL); add_gettimeofday (&nict->nict_context->timer_e_start, nict->nict_context->timer_e_length); } __osip_transaction_set_state (nict, NICT_TRYING); } else { nict_handle_transport_error (nict, i); } }
int main (int argc, char *argv[]) { int port = 5060; eXosip_event_t *event = NULL; succeed_type flag; #if !defined(__arc__) struct servent *service = NULL; #endif struct regparam_t regparam = { 0, 3600, 0 }; int debug = 1; port = 5060; #if 0 if (debug > 0) TRACE_INITIALIZE (6, NULL); #endif context_eXosip = eXosip_malloc (); if (eXosip_init (context_eXosip)) { printf("eXosip_init failed\r\n"); exit (1); } if (eXosip_listen_addr (context_eXosip, IPPROTO_UDP, "192.168.5.118", port, AF_INET, 0)) { printf("eXosip_listen_addr failed\r\n"); exit (1); } /*start the notify thread */ #ifndef OSIP_MONOTHREAD notify_thread = osip_thread_create(20000, notify_proc, ®param); #endif for(;;) { eXosip_event_t *event; if (!(event = eXosip_event_wait (context_eXosip, 0, 1))) { #ifdef OSIP_MONOTHREAD eXosip_execute (context_eXosip); eXosip_automatic_action (context_eXosip); #endif // osip_usleep (10000); continue; } eXosip_lock(context_eXosip); #ifdef OSIP_MONOTHREAD eXosip_execute (context_eXosip); #endif // eXosip_automatic_action (context_eXosip); eXosip_unlock(context_eXosip); eXosip_automatic_action(context_eXosip); switch (event->type) { case EXOSIP_CALL_INVITE: if(MSG_IS_INVITE(event->request)) { flag = handle_request_invite(context_eXosip, event); if(flag == succeed_type_failed) { printf("handle invite request failed\r\n"); }else{ printf("handle invite request succeed\r\n"); } continue; } break; case EXOSIP_CALL_REINVITE: break; case EXOSIP_CALL_NOANSWER: break; case EXOSIP_CALL_PROCEEDING: break; case EXOSIP_CALL_RINGING: break; case EXOSIP_CALL_ANSWERED: break; case EXOSIP_CALL_REDIRECTED: break; case EXOSIP_CALL_REQUESTFAILURE: break; case EXOSIP_CALL_SERVERFAILURE: break; case EXOSIP_CALL_GLOBALFAILURE: break; case EXOSIP_CALL_ACK: break; case EXOSIP_CALL_CANCELLED: break; case EXOSIP_CALL_MESSAGE_NEW: break; case EXOSIP_CALL_MESSAGE_PROCEEDING: printf("EXOSIP_CALL_MESSAGE_PROCEEDING\r\n"); break; case EXOSIP_CALL_MESSAGE_ANSWERED: break; case EXOSIP_CALL_MESSAGE_REDIRECTED: break; case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: break; case EXOSIP_CALL_MESSAGE_SERVERFAILURE: break; case EXOSIP_CALL_MESSAGE_GLOBALFAILURE: break; case EXOSIP_CALL_CLOSED: break; case EXOSIP_CALL_RELEASED: break; case EXOSIP_MESSAGE_NEW: printf("answer EXOSIP_MESSAGE_NEW\r\n"); if(MSG_IS_MESSAGE(event->request)) { flag = handle_request_message(context_eXosip, event); if(flag == succeed_type_failed) { printf("handle message request failed\r\n"); }else{ printf("handle message request succeed\r\n"); } continue; } if(MSG_IS_REGISTER(event->request)) { flag = handle_request_register(context_eXosip, event); if(flag == succeed_type_failed) { printf("handle register request failed\r\n"); }else{ printf("handle register request succeed\r\n"); } continue; } break; case EXOSIP_MESSAGE_PROCEEDING: break; case EXOSIP_MESSAGE_ANSWERED: break; case EXOSIP_MESSAGE_REDIRECTED: break; case EXOSIP_MESSAGE_REQUESTFAILURE: break; case EXOSIP_MESSAGE_SERVERFAILURE: break; case EXOSIP_MESSAGE_GLOBALFAILURE: break; case EXOSIP_SUBSCRIPTION_NOANSWER: break; case EXOSIP_SUBSCRIPTION_PROCEEDING: break; case EXOSIP_SUBSCRIPTION_ANSWERED: break; case EXOSIP_SUBSCRIPTION_REDIRECTED: break; case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: break; case EXOSIP_SUBSCRIPTION_SERVERFAILURE: break; case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: break; case EXOSIP_SUBSCRIPTION_NOTIFY: break; case EXOSIP_IN_SUBSCRIPTION_NEW: //subscribe event if(MSG_IS_SUBSCRIBE(event->request)) { flag = handle_request_subscribe(context_eXosip, event); if(flag == succeed_type_failed) { printf("handle subscribe request failed\r\n"); }else{ printf("handle subscribe request succeed\r\n"); } continue; } break; case EXOSIP_NOTIFICATION_NOANSWER: break; case EXOSIP_NOTIFICATION_PROCEEDING: break; case EXOSIP_NOTIFICATION_ANSWERED: break; case EXOSIP_NOTIFICATION_REDIRECTED: break; case EXOSIP_NOTIFICATION_REQUESTFAILURE: break; case EXOSIP_NOTIFICATION_SERVERFAILURE: break; case EXOSIP_NOTIFICATION_GLOBALFAILURE: break; case EXOSIP_EVENT_COUNT: break; default: printf( "recieved unknown eXosip event (type, did, cid) = (%d, %d, %d)", event->type, event->did, event->cid); } eXosip_event_free (event); } }
static int udp_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host, int port, int out_socket) { int len = 0; size_t length = 0; struct addrinfo *addrinfo; struct __eXosip_sockaddr addr; char *message = NULL; char ipbuf[INET6_ADDRSTRLEN]; int i; osip_naptr_t *naptr_record=NULL; if (udp_socket <= 0) return -1; if (host == NULL) { host = sip->req_uri->host; if (sip->req_uri->port != NULL) port = osip_atoi(sip->req_uri->port); else port = 5060; } eXtl_update_local_target(sip); i = -1; #ifndef MINISIZE if (tr==NULL) { _eXosip_srv_lookup(sip, &naptr_record); if (naptr_record!=NULL) { eXosip_dnsutils_dns_process(naptr_record, 1); if (naptr_record->naptr_state==OSIP_NAPTR_STATE_NAPTRDONE ||naptr_record->naptr_state==OSIP_NAPTR_STATE_SRVINPROGRESS) eXosip_dnsutils_dns_process(naptr_record, 1); } if (naptr_record!=NULL && naptr_record->naptr_state==OSIP_NAPTR_STATE_SRVDONE) { /* 4: check if we have the one we want... */ if (naptr_record->sipudp_record.name[0] != '\0' && naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].srv[0] != '\0') { /* always choose the first here. if a network error occur, remove first entry and replace with next entries. */ osip_srv_entry_t *srv; int n = 0; for (srv = &naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index]; n < 10 && naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].srv[0]; srv = &naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index]) { if (srv->ipaddress[0]) i = eXosip_get_addrinfo(&addrinfo, srv->ipaddress, srv->port, IPPROTO_UDP); else i = eXosip_get_addrinfo(&addrinfo, srv->srv, srv->port, IPPROTO_UDP); if (i == 0) { host = srv->srv; port = srv->port; break; } i = eXosip_dnsutils_rotate_srv(&naptr_record->sipudp_record); if (i<=0) { return -1; } if (i>=n) { return -1; } i = -1; /* copy next element */ n++; } } } if (naptr_record!=NULL && naptr_record->keep_in_cache==0) osip_free(naptr_record); naptr_record=NULL; } else { naptr_record = tr->naptr_record; } if (naptr_record!=NULL) { /* 1: make sure there is no pending DNS */ eXosip_dnsutils_dns_process(naptr_record, 0); if (naptr_record->naptr_state==OSIP_NAPTR_STATE_NAPTRDONE ||naptr_record->naptr_state==OSIP_NAPTR_STATE_SRVINPROGRESS) eXosip_dnsutils_dns_process(naptr_record, 0); if (naptr_record->naptr_state==OSIP_NAPTR_STATE_UNKNOWN) { /* fallback to DNS A */ if (naptr_record->keep_in_cache==0) osip_free(naptr_record); naptr_record=NULL; if (tr!=NULL) tr->naptr_record=NULL; /* must never happen? */ } else if (naptr_record->naptr_state==OSIP_NAPTR_STATE_INPROGRESS) { /* 2: keep waiting (naptr answer not received) */ return OSIP_SUCCESS + 1; } else if (naptr_record->naptr_state==OSIP_NAPTR_STATE_NAPTRDONE) { /* 3: keep waiting (naptr answer received/no srv answer received) */ return OSIP_SUCCESS + 1; } else if (naptr_record->naptr_state==OSIP_NAPTR_STATE_SRVINPROGRESS) { /* 3: keep waiting (naptr answer received/no srv answer received) */ return OSIP_SUCCESS + 1; } else if (naptr_record->naptr_state==OSIP_NAPTR_STATE_SRVDONE) { /* 4: check if we have the one we want... */ if (naptr_record->sipudp_record.name[0] != '\0' && naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].srv[0] != '\0') { /* always choose the first here. if a network error occur, remove first entry and replace with next entries. */ osip_srv_entry_t *srv; int n = 0; for (srv = &naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index]; n < 10 && naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].srv[0]; srv = &naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index]) { if (srv->ipaddress[0]) i = eXosip_get_addrinfo(&addrinfo, srv->ipaddress, srv->port, IPPROTO_UDP); else i = eXosip_get_addrinfo(&addrinfo, srv->srv, srv->port, IPPROTO_UDP); if (i == 0) { host = srv->srv; port = srv->port; break; } i = eXosip_dnsutils_rotate_srv(&naptr_record->sipudp_record); if (i<=0) { return -1; } if (i>=n) { return -1; } i = -1; /* copy next element */ n++; } } } else if (naptr_record->naptr_state==OSIP_NAPTR_STATE_NOTSUPPORTED ||naptr_record->naptr_state==OSIP_NAPTR_STATE_RETRYLATER) { /* 5: fallback to DNS A */ if (naptr_record->keep_in_cache==0) osip_free(naptr_record); naptr_record=NULL; if (tr!=NULL) tr->naptr_record=NULL; } } #endif /* if SRV was used, destination may be already found */ if (i != 0) { i = eXosip_get_addrinfo(&addrinfo, host, port, IPPROTO_UDP); } if (i != 0) { return -1; } memcpy(&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); len = addrinfo->ai_addrlen; eXosip_freeaddrinfo(addrinfo); /* remove preloaded route if there is no tag in the To header */ { osip_route_t *route = NULL; osip_generic_param_t *tag = NULL; osip_message_get_route(sip, 0, &route); osip_to_get_tag(sip->to, &tag); if (tag == NULL && route != NULL && route->url != NULL) { osip_list_remove(&sip->routes, 0); } i = osip_message_to_str(sip, &message, &length); if (tag == NULL && route != NULL && route->url != NULL) { osip_list_add(&sip->routes, route, 0); } } if (i != 0 || length <= 0) { osip_free(message); return -1; } switch (((struct sockaddr *) &addr)->sa_family) { case AF_INET: inet_ntop(((struct sockaddr *) &addr)->sa_family, &(((struct sockaddr_in *) &addr)->sin_addr), ipbuf, sizeof(ipbuf)); break; case AF_INET6: inet_ntop(((struct sockaddr *) &addr)->sa_family, &(((struct sockaddr_in6 *) &addr)->sin6_addr), ipbuf, sizeof(ipbuf)); break; default: strncpy(ipbuf, "(unknown)", sizeof(ipbuf)); break; } OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "Message sent: (to dest=%s:%i)\n%s\n", ipbuf, port, message)); if (osip_strcasecmp(host, ipbuf)!=0 && MSG_IS_REQUEST(sip)) { if (MSG_IS_REGISTER(sip)) { struct eXosip_dns_cache entry; memset(&entry, 0, sizeof(struct eXosip_dns_cache)); snprintf(entry.host, sizeof(entry.host), "%s", host); snprintf(entry.ip, sizeof(entry.ip), "%s", ipbuf); eXosip_set_option(EXOSIP_OPT_ADD_DNS_CACHE, (void *) &entry); } } if (tr != NULL) { if (tr->ict_context != NULL) osip_ict_set_destination(tr->ict_context, osip_strdup(ipbuf), port); if (tr->nict_context != NULL) osip_nict_set_destination(tr->nict_context, osip_strdup(ipbuf), port); } if (0 > sendto(udp_socket, (const void *) message, length, 0, (struct sockaddr *) &addr, len)) { #ifndef MINISIZE if (naptr_record!=NULL) { /* rotate on failure! */ if (eXosip_dnsutils_rotate_srv(&naptr_record->sipudp_record)>0) { osip_free(message); return OSIP_SUCCESS + 1; /* retry for next retransmission! */ } } #endif /* SIP_NETWORK_ERROR; */ osip_free(message); return -1; } if (eXosip.keep_alive > 0) { if (MSG_IS_REGISTER(sip)) { eXosip_reg_t *reg = NULL; if (_eXosip_reg_find(®, tr) == 0) { memcpy(&(reg->addr), &addr, len); reg->len = len; } } } #ifndef MINISIZE if (naptr_record!=NULL) { if (tr!=NULL && MSG_IS_REGISTER(sip) && tr->last_response==NULL) { /* failover for outgoing transaction */ time_t now; now = time(NULL); OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "not yet answered\n")); if (tr != NULL && now - tr->birth_time > 10 && now - tr->birth_time < 13) { /* avoid doing this twice... */ if (eXosip_dnsutils_rotate_srv(&naptr_record->sipudp_record)>0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "Doing failover: %s:%i->%s:%i\n", host, port, naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].srv, naptr_record->sipudp_record.srventry[naptr_record->sipudp_record.index].port)); osip_free(message); return OSIP_SUCCESS + 1; /* retry for next retransmission! */ } } } } #endif osip_free(message); return OSIP_SUCCESS; }
static int dtls_tl_send_message(osip_transaction_t * tr, osip_message_t * sip, char *host, int port, int out_socket) { int len = 0; size_t length = 0; struct addrinfo *addrinfo; struct __eXosip_sockaddr addr; char *message; char ipbuf[INET6_ADDRSTRLEN]; int i; int pos; struct socket_tab *socket_tab_used=NULL; BIO *sbio=NULL; if (dtls_socket <= 0) return -1; if (host == NULL) { host = sip->req_uri->host; if (sip->req_uri->port != NULL) port = osip_atoi (sip->req_uri->port); else port = 5061; } if (port == 5060) port = 5061; if (MSG_IS_REQUEST(sip)) { if (MSG_IS_REGISTER(sip) ||MSG_IS_INVITE(sip) ||MSG_IS_SUBSCRIBE(sip) || MSG_IS_NOTIFY(sip)) eXtl_update_local_target(sip); } i=-1; #ifndef MINISIZE if (tr!=NULL && tr->record.name[0]!='\0' && tr->record.srventry[0].srv[0]!='\0') { /* always choose the first here. if a network error occur, remove first entry and replace with next entries. */ osip_srv_entry_t *srv; int n=0; for (srv = &tr->record.srventry[0]; n<10 && tr->record.srventry[0].srv[0]; srv = &tr->record.srventry[0]) { i = eXosip_get_addrinfo (&addrinfo, srv->srv, srv->port, IPPROTO_UDP); if (i == 0) { host = srv->srv; port = srv->port; break; } memmove(&tr->record.srventry[0], &tr->record.srventry[1], 9*sizeof(osip_srv_entry_t)); memset(&tr->record.srventry[9], 0, sizeof(osip_srv_entry_t)); i=-1; /* copy next element */ n++; } } #endif /* if SRV was used, distination may be already found */ if (i != 0) { i = eXosip_get_addrinfo (&addrinfo, host, port, IPPROTO_UDP); } if (i != 0) { return -1; } memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); len = addrinfo->ai_addrlen; eXosip_freeaddrinfo (addrinfo); /* remove preloaded route if there is no tag in the To header */ { osip_route_t *route=NULL; osip_generic_param_t *tag=NULL; osip_message_get_route (sip, 0, &route); osip_to_get_tag (sip->to, &tag); if (tag==NULL && route != NULL && route->url != NULL) { osip_list_remove(&sip->routes, 0); } i = osip_message_to_str (sip, &message, &length); if (tag==NULL && route != NULL && route->url != NULL) { osip_list_add(&sip->routes, route, 0); } } if (i != 0 || length <= 0) { return -1; } switch ( ((struct sockaddr *)&addr)->sa_family ) { case AF_INET: inet_ntop (((struct sockaddr *)&addr)->sa_family, &(((struct sockaddr_in *) &addr)->sin_addr), ipbuf, sizeof (ipbuf)); break; case AF_INET6: inet_ntop (((struct sockaddr *)&addr)->sa_family, &(((struct sockaddr_in6 *) &addr)->sin6_addr), ipbuf, sizeof (ipbuf)); break; default: strncpy (ipbuf, "(unknown)", sizeof (ipbuf)); break; } OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "Message sent: \n%s (to dest=%s:%i)\n", message, ipbuf, port)); for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) { if (dtls_socket_tab[pos].ssl_conn != NULL && dtls_socket_tab[pos].ssl_type == EXOSIP_AS_A_SERVER) { if (dtls_socket_tab[pos].remote_port == port && (strcmp (dtls_socket_tab[pos].remote_ip, ipbuf) == 0)) { BIO *rbio; socket_tab_used = &dtls_socket_tab[pos]; rbio = BIO_new_dgram (dtls_socket, BIO_NOCLOSE); BIO_dgram_set_peer (rbio, &addr); dtls_socket_tab[pos].ssl_conn->rbio = rbio; break; } } } if (socket_tab_used==NULL) { for (pos = 0; pos < EXOSIP_MAX_SOCKETS; pos++) { if (dtls_socket_tab[pos].ssl_conn != NULL && dtls_socket_tab[pos].ssl_type == EXOSIP_AS_A_CLIENT) { if (dtls_socket_tab[pos].remote_port == port && (strcmp (dtls_socket_tab[pos].remote_ip, ipbuf) == 0)) { BIO *rbio; socket_tab_used = &dtls_socket_tab[pos]; rbio = BIO_new_dgram (dtls_socket, BIO_NOCLOSE); BIO_dgram_set_peer (rbio, &addr); dtls_socket_tab[pos].ssl_conn->rbio = rbio; break; } } } } if (socket_tab_used==NULL) { /* delete an old one! */ pos=0; if (dtls_socket_tab[pos].ssl_conn != NULL) { shutdown_free_client_dtls (pos); shutdown_free_server_dtls (pos); } memset(&dtls_socket_tab[pos], 0, sizeof(struct socket_tab)); } if (dtls_socket_tab[pos].ssl_conn == NULL) { /* create a new one */ SSL_CTX_set_read_ahead (client_ctx, 1); dtls_socket_tab[pos].ssl_conn = SSL_new (client_ctx); if (dtls_socket_tab[pos].ssl_conn == NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "DTLS SSL_new error\n")); if (dtls_socket_tab[pos].ssl_conn != NULL) { shutdown_free_client_dtls (pos); shutdown_free_server_dtls (pos); } memset(&dtls_socket_tab[pos], 0, sizeof(struct socket_tab)); osip_free (message); return -1; } if (connect (dtls_socket, (struct sockaddr *) &addr, sizeof (addr)) == -1) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "DTLS connect error\n")); if (dtls_socket_tab[pos].ssl_conn != NULL) { shutdown_free_client_dtls (pos); shutdown_free_server_dtls (pos); } memset(&dtls_socket_tab[pos], 0, sizeof(struct socket_tab)); osip_free (message); return -1; } SSL_set_options (dtls_socket_tab[pos].ssl_conn, SSL_OP_NO_QUERY_MTU); SSL_set_mtu (dtls_socket_tab[pos].ssl_conn, 2000); SSL_set_connect_state (dtls_socket_tab[pos].ssl_conn); sbio = BIO_new_dgram (dtls_socket, BIO_NOCLOSE); BIO_ctrl_set_connected (sbio, 1, (struct sockaddr *) &addr); SSL_set_bio (dtls_socket_tab[pos].ssl_conn, sbio, sbio); dtls_socket_tab[pos].ssl_type = 2; dtls_socket_tab[pos].ssl_state = 2; osip_strncpy (dtls_socket_tab[pos].remote_ip, ipbuf, sizeof (dtls_socket_tab[pos].remote_ip)); dtls_socket_tab[pos].remote_port = port; } i = SSL_write (dtls_socket_tab[pos].ssl_conn, message, length); if (i<0) { i = SSL_get_error (dtls_socket_tab[pos].ssl_conn, i); print_ssl_error (i); if (i==SSL_ERROR_SSL || i==SSL_ERROR_SYSCALL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "DTLS SSL_write error\n")); if (dtls_socket_tab[pos].ssl_conn != NULL) { shutdown_free_client_dtls (pos); shutdown_free_server_dtls (pos); } memset(&dtls_socket_tab[pos], 0, sizeof(struct socket_tab)); } #ifndef MINISIZE /* delete first SRV entry that is not reachable */ if (tr->record.name[0]!='\0' && tr->record.srventry[0].srv[0]!='\0') { memmove(&tr->record.srventry[0], &tr->record.srventry[1], 9*sizeof(osip_srv_entry_t)); memset(&tr->record.srventry[9], 0, sizeof(osip_srv_entry_t)); osip_free (message); return 0; /* retry for next retransmission! */ } #endif /* SIP_NETWORK_ERROR; */ osip_free (message); return -1; } if (eXosip.keep_alive > 0) { if (MSG_IS_REGISTER (sip)) { eXosip_reg_t *reg = NULL; if (_eXosip_reg_find (®, tr) == 0) { memcpy (&(reg->addr), &addr, len); reg->len = len; } } } osip_free (message); return 0; }
int main (int argc, char *argv[]) { int sts; int i; int buflen; int access; char buff [BUFFER_SIZE]; sip_ticket_t ticket; extern char *optarg; /* Defined in libc getopt and unistd.h */ int ch1; char configfile[64]="siproxd"; /* basename of configfile */ int config_search=1; /* search the config file */ int cmdline_debuglevel=0; char *pidfilename=NULL; struct sigaction act; log_set_stderr(1); /* * setup signal handlers */ act.sa_handler=sighandler; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; if (sigaction(SIGTERM, &act, NULL)) { ERROR("Failed to install SIGTERM handler"); } if (sigaction(SIGINT, &act, NULL)) { ERROR("Failed to install SIGINT handler"); } if (sigaction(SIGUSR2, &act, NULL)) { ERROR("Failed to install SIGUSR2 handler"); } /* * prepare default configuration */ make_default_config(); log_set_pattern(configuration.debuglevel); /* * parse command line */ { #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"debug", required_argument, NULL, 'd'}, {"pid-file", required_argument, NULL,'p'}, {0,0,0,0} }; while ((ch1 = getopt_long(argc, argv, "hc:d:p:", long_options, &option_index)) != -1) { #else /* ! HAVE_GETOPT_LONG */ while ((ch1 = getopt(argc, argv, "hc:d:p:")) != -1) { #endif switch (ch1) { case 'h': /* help */ DEBUGC(DBCLASS_CONFIG,"option: help"); fprintf(stderr,str_helpmsg); exit(0); break; case 'c': /* load config file */ DEBUGC(DBCLASS_CONFIG,"option: config file=%s",optarg); i=sizeof(configfile)-1; strncpy(configfile,optarg,i-1); configfile[i]='\0'; config_search=0; break; case 'd': /* set debug level */ DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg); cmdline_debuglevel=atoi(optarg); log_set_pattern(cmdline_debuglevel); break; case 'p': pidfilename = optarg; break; default: DEBUGC(DBCLASS_CONFIG,"no command line options"); break; } } } /* * Init stuff */ INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" starting up"); /* read the config file */ if (read_config(configfile, config_search) == STS_FAILURE) exit(1); /* if a debug level > 0 has been given on the commandline use its value and not what is in the config file */ if (cmdline_debuglevel != 0) { configuration.debuglevel=cmdline_debuglevel; } /* * open a the pwfile instance, so we still have access after * we possibly have chroot()ed to somewhere. */ if (configuration.proxy_auth_pwfile) { siproxd_passwordfile = fopen(configuration.proxy_auth_pwfile, "r"); } else { siproxd_passwordfile = NULL; } /* set debug level as desired */ log_set_pattern(configuration.debuglevel); log_set_listen_port(configuration.debugport); /* change user and group IDs */ secure_enviroment(); /* daemonize if requested to */ if (configuration.daemonize) { DEBUGC(DBCLASS_CONFIG,"daemonizing"); if (fork()!=0) exit(0); setsid(); if (fork()!=0) exit(0); log_set_stderr(0); INFO("daemonized, pid=%i", getpid()); } /* write PID file of main thread */ if (pidfilename == NULL) pidfilename = configuration.pid_file; if (pidfilename) { FILE *pidfile; DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename); sts=unlink(configuration.pid_file); if ((sts==0) ||(errno == ENOENT)) { if ((pidfile=fopen(pidfilename, "w"))) { fprintf(pidfile,"%i\n",(int)getpid()); fclose(pidfile); } else { WARN("couldn't create new PID file: %s", strerror(errno)); } } else { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* initialize the RTP proxy */ sts=rtpproxy_init(); if (sts != STS_SUCCESS) { ERROR("unable to initialize RTP proxy - aborting"); exit(1); } /* init the oSIP parser */ parser_init(); /* listen for incoming messages */ sts=sipsock_listen(); if (sts == STS_FAILURE) { /* failure to allocate SIP socket... */ ERROR("unable to bind to SIP listening socket - aborting"); exit(1); } /* initialize the registration facility */ register_init(); /* * silence the log - if so required... */ log_set_silence(configuration.silence_log); INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" started"); /***************************** * Main loop *****************************/ while (!exit_program) { DEBUGC(DBCLASS_BABBLE,"going into sipsock_wait\n"); while (sipsock_wait()<=0) { /* got no input, here by timeout. do aging */ register_agemap(); /* TCP log: check for a connection */ log_tcp_connect(); /* dump memory stats if requested to do so */ if (dmalloc_dump) { dmalloc_dump=0; #ifdef DMALLOC INFO("SIGUSR2 - DMALLOC statistics is dumped"); dmalloc_log_stats(); dmalloc_log_unfreed(); #else INFO("SIGUSR2 - DMALLOC support is not compiled in"); #endif } if (exit_program) goto exit_prg; } /* * got input, process */ DEBUGC(DBCLASS_BABBLE,"back from sipsock_wait"); ticket.direction=0; buflen=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol); buff[buflen]='\0'; /* * evaluate the access lists (IP based filter) */ access=accesslist_check(ticket.from); if (access == 0) { DEBUGC(DBCLASS_ACCESS,"access for this packet was denied"); continue; /* there are no resources to free */ } /* * integrity checks */ sts=security_check_raw(buff, buflen); if (sts != STS_SUCCESS) { DEBUGC(DBCLASS_SIP,"security check (raw) failed"); continue; /* there are no resources to free */ } /* * init sip_msg */ sts=osip_message_init(&ticket.sipmsg); ticket.sipmsg->message=NULL; if (sts != 0) { ERROR("osip_message_init() failed... this is not good"); continue; /* skip, there are no resources to free */ } /* * RFC 3261, Section 16.3 step 1 * Proxy Behavior - Request Validation - Reasonable Syntax * (parse the received message) */ sts=sip_message_parse(ticket.sipmsg, buff, buflen); if (sts != 0) { ERROR("sip_message_parse() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * integrity checks - parsed buffer */ sts=security_check_sip(&ticket); if (sts != STS_SUCCESS) { ERROR("security_check_sip() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 2 * Proxy Behavior - Request Validation - URI scheme * (check request URI and refuse with 416 if not understood) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.3 step 3 * Proxy Behavior - Request Validation - Max-Forwards check * (check Max-Forwards header and refuse with 483 if too many hops) */ { osip_header_t *max_forwards; int forwards_count = DEFAULT_MAXFWD; osip_message_get_max_forwards(ticket.sipmsg, 0, &max_forwards); if (max_forwards && max_forwards->hvalue) { forwards_count = atoi(max_forwards->hvalue); } DEBUGC(DBCLASS_PROXY,"checking Max-Forwards (=%i)",forwards_count); if (forwards_count <= 0) { DEBUGC(DBCLASS_SIP, "Forward count reached 0 -> 483 response"); sip_gen_response(&ticket, 483 /*Too many hops*/); goto end_loop; /* skip and free resources */ } } /* * RFC 3261, Section 16.3 step 4 * Proxy Behavior - Request Validation - Loop Detection check * (check for loop and return 482 if a loop is detected) */ if (check_vialoop(&ticket) == STS_TRUE) { /* make sure we don't end up in endless loop when detecting * an loop in an "loop detected" message - brrr */ if (MSG_IS_RESPONSE(ticket.sipmsg) && MSG_TEST_CODE(ticket.sipmsg, 482)) { DEBUGC(DBCLASS_SIP,"loop in loop-response detected, ignoring"); } else { DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request"); sip_gen_response(&ticket, 482 /*Loop detected*/); } goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 5 * Proxy Behavior - Request Validation - Proxy-Require check * (check Proxy-Require header and return 420 if unsupported option) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.5 * Proxy Behavior - Determining Request Targets */ /* NOT IMPLEMENTED */ DEBUGC(DBCLASS_SIP,"received SIP type %s:%s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", (MSG_IS_REQUEST(ticket.sipmsg) ? ((ticket.sipmsg->sip_method)? ticket.sipmsg->sip_method : "NULL") : ((ticket.sipmsg->reason_phrase) ? ticket.sipmsg->reason_phrase : "NULL"))); /********************************* * The message did pass all the * tests above and is now ready * to be proxied. * Before we do so, we apply some * additional preprocessing *********************************/ /* Dial shortcuts */ if (configuration.pi_shortdial) { sts = plugin_shortdial(&ticket); if (sts == STS_SIP_SENT) goto end_loop; } /********************************* * finally proxy the message. * This includes the masquerading * of the local UA and starting/ * stopping the RTP proxy for this * call *********************************/ /* * if a REQ REGISTER, check if it is directed to myself, * or am I just the outbound proxy but no registrar. * - If I'm the registrar, register & generate answer * - If I'm just the outbound proxy, register, rewrite & forward */ if (MSG_IS_REGISTER(ticket.sipmsg) && MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_REG) { osip_uri_t *url; struct in_addr addr1, addr2, addr3; int dest_port; url = osip_message_get_uri(ticket.sipmsg); dest_port= (url->port)?atoi(url->port):SIP_PORT; if ( (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) && (get_interface_ip(IF_INBOUND,&addr2) == STS_SUCCESS) && (get_interface_ip(IF_OUTBOUND,&addr3) == STS_SUCCESS)) { if ((configuration.sip_listen_port == dest_port) && ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) || (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) { /* I'm the registrar, send response myself */ sts = register_client(&ticket, 0); sts = register_response(&ticket, sts); } else { /* I'm just the outbound proxy */ DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s", url->host); sts = register_client(&ticket, 1); if (sts == STS_SUCCESS) { sts = proxy_request(&ticket); } } } else { sip_gen_response(&ticket, 408 /*request timeout*/); } } else { WARN("non-authorized registration attempt from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * check if outbound interface is UP. * If not, send back error to UA and * skip any proxying attempt */ } else if (get_interface_ip(IF_OUTBOUND,NULL) != STS_SUCCESS) { DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface " "is down", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES"); if (MSG_IS_REQUEST(ticket.sipmsg)) sip_gen_response(&ticket, 408 /*request timeout*/); /* * MSG is a request, add current via entry, * do a lookup in the URLMAP table and * send to the final destination */ } else if (MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_request(&ticket); } else { INFO("non-authorized request received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * MSG is a response, remove current via and * send to the next VIA in chain */ } else if (MSG_IS_RESPONSE(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_response(&ticket); } else { INFO("non-authorized response received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * unsupported message */ } else { ERROR("received unsupported SIP type %s %s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", ticket.sipmsg->sip_method); } /********************************* * Done with proxying. Message * has been sent to its destination. *********************************/ /* * free the SIP message buffers */ end_loop: osip_message_free(ticket.sipmsg); } /* while TRUE */ exit_prg: /* save current known SIP registrations */ register_save(); INFO("properly terminating siproxd"); /* remove PID file */ if (pidfilename) { DEBUGC(DBCLASS_CONFIG,"deleting PID file [%s]", pidfilename); sts=unlink(pidfilename); if (sts != 0) { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* END */ return 0; } /* main */ /* * Signal handler * * this one is called asynchronously whevener a registered * signal is applied. Just set a flag and don't do any funny * things here. */ static void sighandler(int sig) { if (sig==SIGTERM) exit_program=1; if (sig==SIGINT) exit_program=1; if (sig==SIGUSR2) dmalloc_dump=1; return; }
/* * SIP_IS_OUTGOING * * Figures out if this is an outgoing or incoming request/response. * The direction is stored in the ticket->direction property. * * RETURNS * STS_SUCCESS on success * STS_FAILURE if unable to determine */ int sip_find_direction(sip_ticket_t *ticket, int *urlidx) { int type; int i, sts; struct sockaddr_in *from; osip_message_t *request; osip_message_t *response; from=&ticket->from; request=ticket->sipmsg; response=ticket->sipmsg; type = 0; ticket->direction = 0; /* * did I receive the telegram from a REGISTERED host? * -> it must be an OUTGOING request */ 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_SIP, "sip_find_direction: cannot resolve host [%s]", urlmap[i].true_url->host); } else { DEBUGC(DBCLASS_SIP, "sip_find_direction: 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) { if (MSG_IS_REQUEST(ticket->sipmsg)) { type=REQTYP_OUTGOING; } else { type=RESTYP_OUTGOING; } break; } } } /* * is the telegram directed to an internally registered host? * -> it must be an INCOMING request */ if (type == 0) { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* RFC3261: * 'To' contains a display name (Bob) and a SIP or SIPS URI * (sip:[email protected]) towards which the request was originally * directed. Display names are described in RFC 2822 [3]. */ /* So this means, that we must check the SIP URI supplied with the * INVITE method, as this points to the real wanted target. * Q: does there exist a situation where the SIP URI itself does * point to "somewhere" but the To: points to the correct UA? * So for now, we just look at both of them (SIP URI and To: header) */ if (MSG_IS_REQUEST(ticket->sipmsg)) { /* REQUEST */ /* incoming request (SIP URI == 'masq') || ((SIP URI == 'reg') && !REGISTER)*/ if ((compare_url(request->req_uri, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->req_uri, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; break; } /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/ if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; break; } } else { /* RESPONSE */ /* 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; } } /* is request */ } /* for i */ } /* if type == 0 */ if (MSG_IS_RESPONSE(ticket->sipmsg)) { /* &&&& 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_SIP, "sip_find_direction: check via [%s] for " "registered UA",via->host); sts=get_ip_by_host(via->host, &addr_via); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_SIP, "sip_find_direction: 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_SIP, "sip_find_direction: 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_SIP, "sip_find_direction: 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; } } /* for i */ } } /* if type == 0 */ } /* is response */ if (type == 0) { DEBUGC(DBCLASS_SIP, "sip_find_direction: unable to determine " "direction of SIP packet"); return STS_FAILURE; } ticket->direction=type; if (urlidx) *urlidx=i; return STS_SUCCESS; }