static void send_tcp_ping(t_event *event) { string log_msg; t_event_tcp_ping *e = dynamic_cast<t_event_tcp_ping *>(event); assert(e); t_connection *conn = connection_table->get_connection( e->get_dst_addr(), e->get_dst_port()); if (!conn) { // There is no connection to send the ping. log_msg = "Connection to "; log_msg += h_ip2str(e->get_dst_addr()); log_msg += ":"; log_msg += int2str(e->get_dst_port()); log_msg += " is gone."; log_file->write_report(log_msg, "::send_tcp_ping", LOG_SIP, LOG_WARNING); // Signal the transaction layer that the connection is gone. evq_trans_layer->push_broken_connection(e->get_user_uri()); return; } conn->async_send(TCP_PING_PACKET, strlen(TCP_PING_PACKET)); connection_table->unlock(); }
// Create a request within a dialog // RFC 3261 12.2.1.1 t_request *t_abstract_dialog::create_request(t_method m) { t_user *user_config = phone_user->get_user_profile(); t_request *r = new t_request(m); MEMMAN_NEW(r); // To header r->hdr_to.set_uri(remote_uri); r->hdr_to.set_display(remote_display); r->hdr_to.set_tag(remote_tag); // From header r->hdr_from.set_uri(local_uri); r->hdr_from.set_display(local_display); r->hdr_from.set_tag(local_tag); // Call-ID header r->hdr_call_id.set_call_id(call_id); // CSeq header r->hdr_cseq.set_method(m); r->hdr_cseq.set_seqnr(++local_seqnr); // Set Max-Forwards header r->hdr_max_forwards.set_max_forwards(MAX_FORWARDS); // User-Agent SET_HDR_USER_AGENT(r->hdr_user_agent); // RFC 3261 12.2.1.1 // Request URI and Route header r->set_route(remote_target_uri, route_set); // Caculate destination set. A DNS request can result in multiple // IP address. In failover scenario's the request must be sent to // the next IP address in the list. As the request will be copied // in various places, the destination set must be calculated now. // In previous version the DNS request was done by the transaction // manager. This is too late as the transaction manager gets a copy // of the request. The destination set should be set in the copy // kept by the dialog. r->calc_destinations(*user_config); // The Via header can only be created after the destinations // are calculated, because the destination deterimines which // local IP address should be used. // Via header unsigned long local_ip = r->get_local_ip(); t_via via(USER_HOST(user_config, h_ip2str(local_ip)), PUBLIC_SIP_PORT(user_config)); r->hdr_via.add_via(via); return r; }
static void send_sip_udp(t_event *event) { t_event_network *e; e = (t_event_network *)event; assert(e->dst_addr != 0); assert(e->dst_port != 0); // Set correct transport in topmost Via header of a request. // For a response the Via header is copied from the incoming request. t_sip_message *sip_msg = e->get_msg(); if (sip_msg->get_type() == MSG_REQUEST) { sip_msg->hdr_via.via_list.front().transport = "UDP"; } string m = sip_msg->encode(); log_file->write_header("::send_sip_udp", LOG_SIP); log_file->write_raw("Send to: udp:"); log_file->write_raw(h_ip2str(e->dst_addr)); log_file->write_raw(":"); log_file->write_raw(e->dst_port); log_file->write_endl(); log_file->write_raw(m); log_file->write_endl(); log_file->write_footer(); bool msg_sent = false; int transmit_count = 0; while (!msg_sent && transmit_count++ <= MAX_TRANSMIT_RETRIES) { try { sip_socket->sendto(e->dst_addr, e->dst_port, m.c_str(), m.size()); num_non_icmp_errors = 0; msg_sent = true; } catch (int err) { if (!handle_socket_err(err, e->dst_addr, e->dst_port)) { // Discard packet. msg_sent = true; } else { if (transmit_count <= MAX_TRANSMIT_RETRIES) { // Sleep 100 ms struct timespec sleeptimer; sleeptimer.tv_sec = 0; sleeptimer.tv_nsec = 100000000; nanosleep(&sleeptimer, NULL); } } } } }
void t_abstract_dialog::resend_request(t_client_request *cr) { t_user *user_config = phone_user->get_user_profile(); t_request *req = cr->get_request(); // A new sequence number must be assigned req->hdr_cseq.set_seqnr(++local_seqnr); // Create a new via-header. Otherwise the // request will be seen as a retransmission unsigned long local_ip = req->get_local_ip(); req->hdr_via.via_list.clear(); t_via via(USER_HOST(user_config, h_ip2str(local_ip)), PUBLIC_SIP_PORT(user_config)); req->hdr_via.add_via(via); cr->renew(0); send_request(req, cr->get_tuid()); }
static void send_stun(t_event *event) { t_event_stun_request *e; e = (t_event_stun_request *)event; assert(e->dst_addr != 0); assert(e->dst_port != 0); log_file->write_header("::send_stun", LOG_STUN); log_file->write_raw("Send to: "); log_file->write_raw(h_ip2str(e->dst_addr)); log_file->write_raw(":"); log_file->write_raw(e->dst_port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(*e->get_msg())); log_file->write_footer(); StunAtrString stun_pass; stun_pass.sizeValue = 0; char m[STUN_MAX_MESSAGE_SIZE]; int msg_size = stunEncodeMessage(*e->get_msg(), m, STUN_MAX_MESSAGE_SIZE, stun_pass, false); bool msg_sent = false; int transmit_count = 0; while (!msg_sent && transmit_count++ <= MAX_TRANSMIT_RETRIES) { try { sip_socket->sendto(e->dst_addr, e->dst_port, m, msg_size); num_non_icmp_errors = 0; msg_sent = true; } catch (int err) { if (!handle_socket_err(err, e->dst_addr, e->dst_port)) { // Discard packet. msg_sent = true; } else { if (transmit_count <= MAX_TRANSMIT_RETRIES) { // Sleep 100 ms struct timespec sleeptimer; sleeptimer.tv_sec = 0; sleeptimer.tv_nsec = 100000000; nanosleep(&sleeptimer, NULL); } } } } }
void t_phone_user::resend_request(t_request *req, bool is_register, t_client_request *cr) { // A new sequence number must be assigned if (is_register) { req->hdr_cseq.set_seqnr(++register_seqnr); } else { req->hdr_cseq.seqnr++; } // Create a new via-header. Otherwise the // request will be seen as a retransmission unsigned long local_ip = req->get_local_ip(); req->hdr_via.via_list.clear(); t_via via(USER_HOST(user_config, h_ip2str(local_ip)), PUBLIC_SIP_PORT(user_config)); req->hdr_via.add_via(via); cr->renew(0); phone->send_request(user_config, req, cr->get_tuid()); }
t_request *t_phone_user::create_request(t_method m, const t_url &request_uri) const { t_request *req = new t_request(m); MEMMAN_NEW(req); // From req->hdr_from.set_uri(user_config->create_user_uri(false)); req->hdr_from.set_display(user_config->get_display(false)); req->hdr_from.set_tag(NEW_TAG); // Max-Forwards header (mandatory) req->hdr_max_forwards.set_max_forwards(MAX_FORWARDS); // User-Agent SET_HDR_USER_AGENT(req->hdr_user_agent); // Set request URI and calculate destinations. By calculating // destinations now, the request can be resend to a next destination // if failover is needed. if (m == REGISTER) { // For a REGISTER do not use the service route for routing. req->uri = request_uri; } else { // RFC 3608 // For all other requests, use the service route set for routing. req->set_route(request_uri, service_route); } req->calc_destinations(*user_config); // The Via header can only be created after the destinations // are calculated, because the destination deterimines which // local IP address should be used. // Via unsigned long local_ip = req->get_local_ip(); t_via via(USER_HOST(user_config, h_ip2str(local_ip)), PUBLIC_SIP_PORT(user_config)); req->hdr_via.add_via(via); return req; }
t_request *t_subscription_dialog::create_request(t_method m) { t_user *user_config = phone_user->get_user_profile(); t_request *r = t_abstract_dialog::create_request(m); // Contact header t_contact_param contact; switch (m) { case REFER: case SUBSCRIBE: case NOTIFY: // RFC 3265 7.1, RFC 3515 2.2 // Contact header is mandatory contact.uri.set_url(user_config->create_user_contact(false, h_ip2str(r->get_local_ip()))); r->hdr_contact.add_contact(contact); break; default: break; } return r; }
bool get_stun_binding(t_user *user_config, unsigned short src_port, unsigned long &mapped_ip, unsigned short &mapped_port, int &err_code, string &err_reason) { list<t_ip_port> destinations = user_config->get_stun_server().get_h_ip_srv("udp"); if (destinations.empty()) { // Cannot resolve STUN server address. log_file->write_header("::get_stun_binding", LOG_NORMAL, LOG_CRITICAL); log_file->write_raw("Failed to resolve: "); log_file->write_raw(user_config->get_stun_server().encode()); log_file->write_endl(); log_file->write_raw("Return internal STUN bind error: 404 Not Found"); log_file->write_endl(); log_file->write_footer(); err_code = 404; err_reason = "Not Found"; return false; } int num_transmissions = 0; int wait_intval = DUR_STUN_START_INTVAL; t_socket_udp sock(src_port); sock.connect(destinations.front().ipaddr, destinations.front().port); // Build STUN request char buf[STUN_MAX_MESSAGE_SIZE + 1]; StunMessage req_bind; StunAtrString stun_null_str; stun_null_str.sizeValue = 0; stunBuildReqSimple(&req_bind, stun_null_str, false, false); char req_msg[STUN_MAX_MESSAGE_SIZE]; int req_msg_size = stunEncodeMessage(req_bind, req_msg, STUN_MAX_MESSAGE_SIZE, stun_null_str, false); // Send STUN request and retransmit till a response is received. while (num_transmissions < STUN_MAX_TRANSMISSIONS) { bool ret; try { sock.send(req_msg, req_msg_size); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Send failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } log_file->write_header("::get_stun_binding", LOG_STUN); log_file->write_raw("Send to: "); log_file->write_raw(h_ip2str(destinations.front().ipaddr)); log_file->write_raw(":"); log_file->write_raw(destinations.front().port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(req_bind)); log_file->write_footer(); try { ret = sock.select_read(wait_intval); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Select failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } if (!ret) { // Time out num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } // A message has been received int resp_msg_size; try { resp_msg_size = sock.recv(buf, STUN_MAX_MESSAGE_SIZE + 1); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Recv failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } StunMessage resp_bind; if (!stunParseMessage(buf, resp_msg_size, resp_bind, false)) { log_file->write_report( "Received faulty STUN message", "::get_stun_binding", LOG_STUN); num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } log_file->write_header("::get_stun_binding", LOG_STUN); log_file->write_raw("Received from: "); log_file->write_raw(h_ip2str(destinations.front().ipaddr)); log_file->write_raw(":"); log_file->write_raw(destinations.front().port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(resp_bind)); log_file->write_footer(); // Check if id in msgHdr matches if (!stunEqualId(resp_bind, req_bind)) { num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } if (resp_bind.msgHdr.msgType == BindResponseMsg && resp_bind.hasMappedAddress) { // Bind response received mapped_ip = resp_bind.mappedAddress.ipv4.addr; mapped_port = resp_bind.mappedAddress.ipv4.port; return true; } if (resp_bind.msgHdr.msgType == BindErrorResponseMsg && resp_bind.hasErrorCode) { // Bind error received err_code = resp_bind.errorCode.errorClass * 100 + resp_bind.errorCode.number; char s[STUN_MAX_STRING + 1]; strncpy(s, resp_bind.errorCode.reason, STUN_MAX_STRING); s[STUN_MAX_STRING] = 0; err_reason = s; return false; } // A wrong response has been received. log_file->write_report( "Invalid STUN response received", "::get_stun_binding", LOG_NORMAL); err_code = 500; err_reason = "Server Error"; return false; } // Request timed out log_file->write_report("STUN request timeout", "::get_stun_binding", LOG_NORMAL); err_code = 408; err_reason = "Request Timeout"; return false; }
void t_phone_user::registration(t_register_type register_type, bool re_register, unsigned long expires) { // If STUN is enabled, then do a STUN query before registering to // determine the public IP address. if (register_type == REG_REGISTER && use_stun) { if (stun_public_ip_sip == 0) { send_stun_request(); register_after_stun = true; registration_time = expires; return; } stun_binding_inuse_registration = true; } // Stop registration timer for non-query request if (register_type != REG_QUERY) { phone->stop_timer(PTMR_REGISTRATION, this); } // Create call-id if no call-id is created yet if (register_call_id == "") { register_call_id = NEW_CALL_ID(user_config); } // RFC 3261 10.2 // Construct REGISTER request t_request *req = create_request(REGISTER, t_url(string(USER_SCHEME) + ":" + user_config->get_domain())); // To req->hdr_to.set_uri(user_config->create_user_uri(false)); req->hdr_to.set_display(user_config->get_display(false)); //Call-ID req->hdr_call_id.set_call_id(register_call_id); // CSeq req->hdr_cseq.set_method(REGISTER); req->hdr_cseq.set_seqnr(++register_seqnr); // Contact t_contact_param contact; switch (register_type) { case REG_REGISTER: // URI contact.uri.set_url(user_config->create_user_contact(false, h_ip2str(req->get_local_ip()))); // Expires if (expires > 0) { if (user_config->get_registration_time_in_contact()) { contact.set_expires(expires); } else { req->hdr_expires.set_time(expires); } } // q-value if (user_config->get_reg_add_qvalue()) { contact.set_qvalue(user_config->get_reg_qvalue()); } req->hdr_contact.add_contact(contact); break; case REG_DEREGISTER: contact.uri.set_url(user_config->create_user_contact(false, h_ip2str(req->get_local_ip()))); if (user_config->get_registration_time_in_contact()) { contact.set_expires(0); } else { req->hdr_expires.set_time(0); } req->hdr_contact.add_contact(contact); break; case REG_DEREGISTER_ALL: req->hdr_contact.set_any(); req->hdr_expires.set_time(0); break; default: break; } // Allow SET_HDR_ALLOW(req->hdr_allow, user_config); // Store request in the proper place t_tuid tuid; switch(register_type) { case REG_REGISTER: // Delete a possible pending registration request if (r_register) { MEMMAN_DELETE(r_register); delete r_register; } r_register = new t_client_request(user_config, req, 0); MEMMAN_NEW(r_register); tuid = r_register->get_tuid(); // Store expiration time for re-registration. registration_time = expires; break; case REG_QUERY: // Delete a possible pending query registration request if (r_query_register) { MEMMAN_DELETE(r_query_register); delete r_query_register; } r_query_register = new t_client_request(user_config, req, 0); MEMMAN_NEW(r_query_register); tuid = r_query_register->get_tuid(); break; case REG_DEREGISTER: case REG_DEREGISTER_ALL: // Delete a possible pending de-registration request if (r_deregister) { MEMMAN_DELETE(r_deregister); delete r_deregister; } r_deregister = new t_client_request(user_config, req, 0); MEMMAN_NEW(r_deregister); tuid = r_deregister->get_tuid(); break; default: assert(false); } // Send REGISTER authorizor.set_re_register(re_register); ui->cb_register_inprog(user_config, register_type); phone->send_request(user_config, req, tuid); MEMMAN_DELETE(req); delete req; }
string t_phone_user::get_ip_sip(const string &auto_ip) const { if (stun_public_ip_sip) return h_ip2str(stun_public_ip_sip); if (user_config->get_use_nat_public_ip()) return user_config->get_nat_public_ip(); if (LOCAL_IP == AUTO_IP4_ADDRESS) return auto_ip; return LOCAL_IP; }
// Check if the error is caused by an incoming ICMP error. If so, then deliver // the ICMP error to the transaction manager. // // err - error returned by sendto // dst_addr - destination IP address of packet that failed to be sent // dst_port - destination port of packet that failed to be sent // // Returns true if the packet that failed to be sent, should still be sent. // Returns false if the packet that failed to be sent, should be discarded. static bool handle_socket_err(int err, unsigned long dst_addr, unsigned short dst_port) { string log_msg; // Check if an ICMP error has been received t_icmp_msg icmp; if (sip_socket->get_icmp(icmp)) { log_msg = "Received ICMP from: "; log_msg += h_ip2str(icmp.icmp_src_ipaddr); log_msg += "\nICMP type: "; log_msg += int2str(icmp.type); log_msg += "\nICMP code: "; log_msg += int2str(icmp.code); log_msg += "\nDestination of packet causing ICMP: "; log_msg += h_ip2str(icmp.ipaddr); log_msg += ":"; log_msg += int2str(icmp.port); log_msg += "\nSocket error: "; log_msg += int2str(err); log_msg += " "; log_msg += get_error_str(err); log_file->write_report(log_msg, "::hanlde_socket_err", LOG_NORMAL); evq_trans_mgr->push_icmp(icmp); num_non_icmp_errors = 0; // If the ICMP error comes from the same destination as the // destination of the packet that failed to be sent, then the // packet should be discarded as it can most likely not be // delivered and would cause an infinite loop of ICMP errors // otherwise. if (icmp.ipaddr == dst_addr && icmp.port == dst_port) { return false; } } else { // Even if an ICMP message is received this code can get executed. // Sometimes the error is already present on the socket, but the ICMP // message is not yet queued. log_msg = "Failed to send to SIP UDP socket.\n"; log_msg += "Error code: "; log_msg += int2str(err); log_msg += "\n"; log_msg += get_error_str(err); log_file->write_report(log_msg, "::handle_socket_err"); num_non_icmp_errors++; /* * non-ICMP errors occur when a destination on the same * subnet cannot be reached. So this code seems to be * harmful. if (num_non_icmp_errors > 100) { log_msg = "Excessive number of socket errors."; log_file->write_report(log_msg, "::handle_socket_err", LOG_NORMAL, LOG_CRITICAL); log_msg = TRANSLATE("Excessive number of socket errors."); ui->cb_show_msg(log_msg, MSG_CRITICAL); exit(1); } */ } return true; }
void *sender_loop(void *arg) { t_event *event; t_event_network *ev_network; unsigned long local_ipaddr; bool quit = false; while (!quit) { event = evq_sender->pop(); switch(event->get_type()) { case EV_NETWORK: ev_network = dynamic_cast<t_event_network *>(event); local_ipaddr = get_src_ip4_address_for_dst(ev_network->dst_addr); if (local_ipaddr == 0) { log_file->write_header("::sender_loop", LOG_NORMAL, LOG_CRITICAL); log_file->write_raw("Cannot get source IP address for destination: "); log_file->write_raw(h_ip2str(ev_network->dst_addr)); log_file->write_endl(); log_file->write_footer(); evq_trans_mgr->push_failure(FAIL_TRANSPORT, ev_network->get_msg()->hdr_via.via_list.front().branch, ev_network->get_msg()->hdr_cseq.method); break; } if (!ev_network->get_msg()->local_ip_check()) { log_file->write_report("Local IP check failed", "::sender_loop", LOG_NORMAL, LOG_CRITICAL); break; } if (ev_network->transport == "udp") { send_sip_udp(event); } else if (ev_network->transport == "tcp") { send_sip_tcp(event); } else { log_file->write_header("::sender_loop", LOG_NORMAL, LOG_WARNING); log_file->write_raw("Received unsupported transport: "); log_file->write_raw(ev_network->transport); log_file->write_endl(); log_file->write_footer(); } break; case EV_STUN_REQUEST: send_stun(event); break; case EV_NAT_KEEPALIVE: send_nat_keepalive(event); break; case EV_TCP_PING: send_tcp_ping(event); break; case EV_QUIT: quit = true; break; default: assert(false); } MEMMAN_DELETE(event); delete event; } return NULL; }
void *tcp_sender_loop(void *arg) { string log_msg; list<t_connection *> writable_connections; while(true) { writable_connections.clear(); writable_connections = connection_table->select_write(NULL); if (writable_connections.empty()) { // Another thread cancelled the select command. // Stop listening. break; } // NOTE: The connection table is now locked. for (list<t_connection *>::iterator it = writable_connections.begin(); it != writable_connections.end(); ++it) { try { (*it)->write(); } catch (int err) { if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) { continue; } unsigned long remote_addr; unsigned short remote_port; (*it)->get_remote_address(remote_addr, remote_port); log_msg = "Got error on socket to "; log_msg += h_ip2str(remote_addr); log_msg += ":"; log_msg += int2str(remote_port); log_msg += " - "; log_msg += get_error_str(err); log_file->write_report(log_msg, "::tcp_sender_loop", LOG_SIP, LOG_WARNING); // Connection is broken. // Signal the transaction layer that the connection is broken for // all associated registered URI's. const list<t_url> &uris = (*it)->get_registered_uri_set(); for (list<t_url>::const_iterator it_uri = uris.begin(); it_uri != uris.end(); ++it_uri) { evq_trans_layer->push_broken_connection(*it_uri); } // Remove the broken connection. connection_table->remove_connection(*it); MEMMAN_DELETE(*it); delete *it; continue; } } connection_table->unlock(); } log_file->write_report("TCP sender terminated.", "::tcp_sender_loop"); return NULL; }
static void send_sip_tcp(t_event *event) { t_event_network *e; bool new_connection = false; e = (t_event_network *)event; unsigned long dst_addr = e->dst_addr; unsigned short dst_port = e->dst_port; assert(dst_addr != 0); assert(dst_port != 0); // Set correct transport in topmost Via header of a request. // For a response the Via header is copied from the incoming request. t_sip_message *sip_msg = e->get_msg(); if (sip_msg->get_type() == MSG_REQUEST) { sip_msg->hdr_via.via_list.front().transport = "TCP"; } t_connection *conn = NULL; // If a connection exists then re-use this connection. Otherwise a new connection // must be opened. // For a request a connection to the destination address and port of the event // must be opened. // For a response a connection to the sent-by address and port in the Via header // must be opened. if (sip_msg->get_encoded_size() <= MAX_REUSE_CONN_SIZE) { // Re-use a connection only for small messages. Large messages cause // head of line blocking. conn = connection_table->get_connection(dst_addr, dst_port); } else { log_file->write_report( "Open new connection for large message.", "::send_sip_tcp", LOG_SIP, LOG_DEBUG); } if (!conn) { if (sip_msg->get_type() == MSG_RESPONSE) { t_ip_port dst_ip_port; sip_msg->hdr_via.get_response_dst(dst_ip_port); dst_addr = dst_ip_port.ipaddr; dst_port = dst_ip_port.port; } t_socket_tcp *tcp = new t_socket_tcp(); MEMMAN_NEW(tcp); log_file->write_header("::send_sip_tcp", LOG_SIP, LOG_DEBUG); log_file->write_raw("Open connection to "); log_file->write_raw(h_ip2str(dst_addr)); log_file->write_raw(":"); log_file->write_raw(dst_port); log_file->write_endl(); log_file->write_footer(); try { tcp->connect(dst_addr, dst_port); } catch (int err) { evq_trans_mgr->push_failure(FAIL_TRANSPORT, sip_msg->hdr_via.via_list.front().branch, sip_msg->hdr_cseq.method); log_file->write_header("::send_sip_tcp", LOG_SIP, LOG_WARNING); log_file->write_raw("Failed to open connection to "); log_file->write_raw(h_ip2str(dst_addr)); log_file->write_raw(":"); log_file->write_raw(dst_port); log_file->write_endl(); log_file->write_footer(); delete tcp; MEMMAN_DELETE(tcp); return; } conn = new t_connection(tcp); MEMMAN_NEW(conn); // For large messages always a new connection is established. // No other messages should be sent via this connection to avoid // head of line blocking. if (sip_msg->get_encoded_size() > MAX_REUSE_CONN_SIZE) { conn->set_reuse(false); } new_connection = true; } // NOTE: if an existing connection was found, the connection table is now locked. // If persistent TCP connections are required, then // 1) If the SIP message is a registration request, then add the URI from the To-header // to the registered URI set of the connection. // 2) If the SIP message is a de-registration request then remove the URI from the // To-header from the registered URI set of the connection. if (sip_msg->get_type() == MSG_REQUEST) { t_request *req = dynamic_cast<t_request *>(sip_msg); if (req->method == REGISTER) { t_phone_user *pu = phone->find_phone_user(req->hdr_to.uri); if (pu) { t_user *user_config = pu->get_user_profile(); assert(user_config); if (user_config->get_persistent_tcp()) { conn->update_registered_uri_set(req); } } else { log_file->write_header("::send_sip_tcp", LOG_NORMAL, LOG_WARNING); log_file->write_raw("Cannot find phone user for "); log_file->write_raw(req->hdr_to.uri.encode()); log_file->write_endl(); log_file->write_footer(); } } } string m = sip_msg->encode(); log_file->write_header("::send_sip_tcp", LOG_SIP); log_file->write_raw("Send to: tcp:"); log_file->write_raw(h_ip2str(dst_addr)); log_file->write_raw(":"); log_file->write_raw(dst_port); log_file->write_endl(); log_file->write_raw(m); log_file->write_endl(); log_file->write_footer(); conn->async_send(m.c_str(), m.size()); if (new_connection) { connection_table->add_connection(conn); } else { connection_table->unlock(); } }