void SipTransportBroker::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, const std::string &host, std::string &addr, pj_uint16_t &port) const { // Initialize the sip port with the default SIP port port = pjsip_transport_get_default_port_for_type(transportType); // Initialize the sip address with the hostname const pj_str_t *pjMachineName = pj_gethostname(); addr = std::string(pjMachineName->ptr, pjMachineName->slen); // Update address and port with active transport RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port); // get the transport manager associated with the SIP enpoint pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_); RETURN_IF_NULL(tpmgr, "Transport manager is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port); pj_str_t pjstring; pj_cstr(&pjstring, host.c_str()); pjsip_tpselector tp_sel = getTransportSelector(transport); pjsip_tpmgr_fla2_param param = {transportType, &tp_sel, pjstring, PJ_FALSE, {nullptr, 0}, 0, nullptr}; if (pjsip_tpmgr_find_local_addr2(tpmgr, &pool_, ¶m) != PJ_SUCCESS) { WARN("Could not retrieve local address and port from transport, using %s :%d", addr.c_str(), port); return; } // Update local address based on the transport type addr = std::string(param.ret_addr.ptr, param.ret_addr.slen); // Determine the local port based on transport information port = param.ret_port; }
/* * Create app */ static pj_status_t create_app(void) { pj_status_t status; status = pj_init(); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Error initializing pjlib", status); return status; } /* init PJLIB-UTIL: */ status = pjlib_util_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&app.cp, &pj_pool_factory_default_policy, CACHING_POOL_SIZE); /* Create application pool for misc. */ app.pool = pj_pool_create(&app.cp.factory, "app", 1000, 1000, NULL); /* Create the endpoint: */ status = pjsip_endpt_create(&app.cp.factory, pj_gethostname()->ptr, &app.sip_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); return status; }
/* * Get first IP address associated with the hostname. */ PJ_DEF(pj_in_addr) pj_gethostaddr(void) { pj_sockaddr_in addr; const pj_str_t *hostname = pj_gethostname(); pj_sockaddr_in_set_str_addr(&addr, hostname); return addr.sin_addr; }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A0 || p[1]!=A1 || p[2]!=A2 || p[3]!=A3) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -30; /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ return 0; }
int Sdp::createLocalSession(const CodecOrder &selectedCodecs) { setLocalMediaCapabilities(selectedCodecs); localSession_ = PJ_POOL_ZALLOC_T(memPool_, pjmedia_sdp_session); if (!localSession_) { ERROR("Could not create local SDP session"); return !PJ_SUCCESS; } localSession_->conn = PJ_POOL_ZALLOC_T(memPool_, pjmedia_sdp_conn); /* Initialize the fields of the struct */ localSession_->origin.version = 0; pj_time_val tv; pj_gettimeofday(&tv); localSession_->origin.user = pj_str(pj_gethostname()->ptr); // Use Network Time Protocol format timestamp to ensure uniqueness. localSession_->origin.id = tv.sec + 2208988800UL; localSession_->origin.net_type = pj_str((char*)"IN"); localSession_->origin.addr_type = pj_str((char*)"IP4"); localSession_->origin.addr = pj_str((char*)localIpAddr_.c_str()); localSession_->name = pj_str((char*)"sflphone"); localSession_->conn->net_type = localSession_->origin.net_type; localSession_->conn->addr_type = localSession_->origin.addr_type; localSession_->conn->addr = localSession_->origin.addr; // RFC 3264: An offer/answer model session description protocol // As the session is created and destroyed through an external signaling mean (SIP), the line // should have a value of "0 0". localSession_->time.start = 0; localSession_->time.stop = 0; // For DTMF RTP events localSession_->media_count = 1; localSession_->media[0] = setMediaDescriptorLine(); if (!srtpCrypto_.empty()) addSdesAttribute(srtpCrypto_); DEBUG("Local SDP Session:"); printSession(localSession_); return pjmedia_sdp_validate(localSession_); }
void SipTransportBroker::findLocalAddressFromSTUN(pjsip_transport *transport, pj_str_t *stunServerName, int stunPort, std::string &addr, pj_uint16_t &port) const { // Initialize the sip port with the default SIP port port = DEFAULT_SIP_PORT; // Initialize the sip address with the hostname const pj_str_t *pjMachineName = pj_gethostname(); addr = std::string(pjMachineName->ptr, pjMachineName->slen); // Update address and port with active transport RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s:%d", addr.c_str(), port); IpAddr mapped_addr; pj_sock_t sipSocket = pjsip_udp_transport_get_socket(transport); const pjstun_setting stunOpt = {PJ_TRUE, *stunServerName, stunPort, *stunServerName, stunPort}; const pj_status_t stunStatus = pjstun_get_mapped_addr2(&cp_.factory, &stunOpt, 1, &sipSocket, &static_cast<pj_sockaddr_in&>(mapped_addr)); switch (stunStatus) { case PJLIB_UTIL_ESTUNNOTRESPOND: ERROR("No response from STUN server %.*s", stunServerName->slen, stunServerName->ptr); return; case PJLIB_UTIL_ESTUNSYMMETRIC: ERROR("Different mapped addresses are returned by servers."); return; case PJ_SUCCESS: port = mapped_addr.getPort(); addr = mapped_addr.toString(); default: break; } WARN("Using address %s provided by STUN server %.*s", IpAddr(mapped_addr).toString(true).c_str(), stunServerName->slen, stunServerName->ptr); }
/* Resolve the IP address of local machine */ PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr) { unsigned i, count, cand_cnt; enum { CAND_CNT = 8, /* Weighting to be applied to found addresses */ WEIGHT_HOSTNAME = 1, /* hostname IP is not always valid! */ WEIGHT_DEF_ROUTE = 2, WEIGHT_INTERFACE = 1, WEIGHT_LOOPBACK = -5, WEIGHT_LINK_LOCAL = -4, WEIGHT_DISABLED = -50, MIN_WEIGHT = WEIGHT_DISABLED+1 /* minimum weight to use */ }; /* candidates: */ pj_sockaddr cand_addr[CAND_CNT]; int cand_weight[CAND_CNT]; int selected_cand; char strip[PJ_INET6_ADDRSTRLEN+10]; /* Special IPv4 addresses. */ struct spec_ipv4_t { pj_uint32_t addr; pj_uint32_t mask; int weight; } spec_ipv4[] = { /* 127.0.0.0/8, loopback addr will be used if there is no other * addresses. */ { 0x7f000000, 0xFF000000, WEIGHT_LOOPBACK }, /* 0.0.0.0/8, special IP that doesn't seem to be practically useful */ { 0x00000000, 0xFF000000, WEIGHT_DISABLED }, /* 169.254.0.0/16, a zeroconf/link-local address, which has higher * priority than loopback and will be used if there is no other * valid addresses. */ { 0xa9fe0000, 0xFFFF0000, WEIGHT_LINK_LOCAL } }; /* Special IPv6 addresses */ struct spec_ipv6_t { pj_uint8_t addr[16]; pj_uint8_t mask[16]; int weight; } spec_ipv6[] = { /* Loopback address, ::1/128 */ { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, WEIGHT_LOOPBACK }, /* Link local, fe80::/10 */ { {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0xff,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, WEIGHT_LINK_LOCAL }, /* Disabled, ::/128 */ { {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, WEIGHT_DISABLED } }; pj_addrinfo ai; pj_status_t status; /* May not be used if TRACE_ is disabled */ PJ_UNUSED_ARG(strip); #ifdef _MSC_VER /* Get rid of "uninitialized he variable" with MS compilers */ pj_bzero(&ai, sizeof(ai)); #endif cand_cnt = 0; pj_bzero(cand_addr, sizeof(cand_addr)); pj_bzero(cand_weight, sizeof(cand_weight)); for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) { cand_addr[i].addr.sa_family = (pj_uint16_t)af; PJ_SOCKADDR_RESET_LEN(&cand_addr[i]); } addr->addr.sa_family = (pj_uint16_t)af; PJ_SOCKADDR_RESET_LEN(addr); #if !defined(PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION) || \ PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION == 0 TRACE_((THIS_FILE, "pj_gethostip() pj_getaddrinfo1")); /* Get hostname's IP address */ count = 1; status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai); if (status == PJ_SUCCESS) { pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af); pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr); pj_sockaddr_set_port(&cand_addr[cand_cnt], 0); cand_weight[cand_cnt] += WEIGHT_HOSTNAME; ++cand_cnt; TRACE_((THIS_FILE, "hostname IP is %s", pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0))); } TRACE_((THIS_FILE, "pj_gethostip() pj_getaddrinfo2")); #else PJ_UNUSED_ARG(ai); PJ_UNUSED_ARG(count); #endif /* Get default interface (interface for default route) */ if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) { status = pj_getdefaultipinterface(af, addr); if (status == PJ_SUCCESS) { TRACE_((THIS_FILE, "default IP is %s", pj_sockaddr_print(addr, strip, sizeof(strip), 0))); pj_sockaddr_set_port(addr, 0); for (i=0; i<cand_cnt; ++i) { if (pj_sockaddr_cmp(&cand_addr[i], addr)==0) break; } cand_weight[i] += WEIGHT_DEF_ROUTE; if (i >= cand_cnt) { pj_sockaddr_copy_addr(&cand_addr[i], addr); ++cand_cnt; } } } /* Enumerate IP interfaces */ if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) { unsigned start_if = cand_cnt; unsigned count = PJ_ARRAY_SIZE(cand_addr) - start_if; status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]); if (status == PJ_SUCCESS && count) { /* Clear the port number */ for (i=0; i<count; ++i) pj_sockaddr_set_port(&cand_addr[start_if+i], 0); /* For each candidate that we found so far (that is the hostname * address and default interface address, check if they're found * in the interface list. If found, add the weight, and if not, * decrease the weight. */ for (i=0; i<cand_cnt; ++i) { unsigned j; for (j=0; j<count; ++j) { if (pj_sockaddr_cmp(&cand_addr[i], &cand_addr[start_if+j])==0) break; } if (j == count) { /* Not found */ cand_weight[i] -= WEIGHT_INTERFACE; } else { cand_weight[i] += WEIGHT_INTERFACE; } } /* Add remaining interface to candidate list. */ for (i=0; i<count; ++i) { unsigned j; for (j=0; j<cand_cnt; ++j) { if (pj_sockaddr_cmp(&cand_addr[start_if+i], &cand_addr[j])==0) break; } if (j == cand_cnt) { pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &cand_addr[start_if+i]); cand_weight[cand_cnt] += WEIGHT_INTERFACE; ++cand_cnt; } } } } /* Apply weight adjustment for special IPv4/IPv6 addresses * See http://trac.pjsip.org/repos/ticket/1046 */ if (af == PJ_AF_INET) { for (i=0; i<cand_cnt; ++i) { unsigned j; for (j=0; j<PJ_ARRAY_SIZE(spec_ipv4); ++j) { pj_uint32_t a = pj_ntohl(cand_addr[i].ipv4.sin_addr.s_addr); pj_uint32_t pa = spec_ipv4[j].addr; pj_uint32_t pm = spec_ipv4[j].mask; if ((a & pm) == pa) { cand_weight[i] += spec_ipv4[j].weight; break; } } } } else if (af == PJ_AF_INET6) { for (i=0; i<PJ_ARRAY_SIZE(spec_ipv6); ++i) { unsigned j; for (j=0; j<cand_cnt; ++j) { pj_uint8_t *a = cand_addr[j].ipv6.sin6_addr.s6_addr; pj_uint8_t am[16]; pj_uint8_t *pa = spec_ipv6[i].addr; pj_uint8_t *pm = spec_ipv6[i].mask; unsigned k; for (k=0; k<16; ++k) { am[k] = (pj_uint8_t)((a[k] & pm[k]) & 0xFF); } if (pj_memcmp(am, pa, 16)==0) { cand_weight[j] += spec_ipv6[i].weight; } } } } else { return PJ_EAFNOTSUP; } /* Enumerate candidates to get the best IP address to choose */ selected_cand = -1; for (i=0; i<cand_cnt; ++i) { TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d", pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 0), cand_weight[i])); if (cand_weight[i] < MIN_WEIGHT) { continue; } if (selected_cand == -1) selected_cand = i; else if (cand_weight[i] > cand_weight[selected_cand]) selected_cand = i; } /* If else fails, returns loopback interface as the last resort */ if (selected_cand == -1) { if (af==PJ_AF_INET) { addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001); } else { pj_in6_addr *s6_addr; s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr); pj_bzero(s6_addr, sizeof(pj_in6_addr)); s6_addr->s6_addr[15] = 1; } TRACE_((THIS_FILE, "Loopback IP %s returned", pj_sockaddr_print(addr, strip, sizeof(strip), 0))); } else { pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]); TRACE_((THIS_FILE, "Candidate %s selected", pj_sockaddr_print(addr, strip, sizeof(strip), 0))); } return PJ_SUCCESS; }
/* * main() * * If called with argument, treat argument as SIP URL to be called. * Otherwise wait for incoming calls. */ int main(int argc, char *argv[]) { pj_pool_t *pool = NULL; pj_status_t status; unsigned i; /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); pj_log_set_level(5); /* Then init PJLIB-UTIL: */ status = pjlib_util_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* Create global endpoint: */ { const pj_str_t *hostname; const char *endpt_name; /* Endpoint MUST be assigned a globally unique name. * The name will be used as the hostname in Warning header. */ /* For this implementation, we'll use hostname for simplicity */ hostname = pj_gethostname(); endpt_name = hostname->ptr; /* Create the endpoint: */ status = pjsip_endpt_create(&cp.factory, endpt_name, &g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* * Add UDP transport, with hard-coded port * Alternatively, application can use pjsip_udp_transport_attach() to * start UDP transport, if it already has an UDP socket (e.g. after it * resolves the address with STUN). */ { pj_sockaddr addr; pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT); if (AF == pj_AF_INET()) { status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL, 1, NULL); } else if (AF == pj_AF_INET6()) { status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL, 1, NULL); } else { status = PJ_EAFNOTSUP; } if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to start UDP transport", status); return 1; } } /* * Init transaction layer. * This will create/initialize transaction hash tables etc. */ status = pjsip_tsx_layer_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Initialize UA layer module. * This will create/initialize dialog hash tables etc. */ status = pjsip_ua_init_module( g_endpt, NULL ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Init invite session module. * The invite session module initialization takes additional argument, * i.e. a structure containing callbacks to be called on specific * occurence of events. * * The on_state_changed and on_new_session callbacks are mandatory. * Application must supply the callback function. * * We use on_media_update() callback in this application to start * media transmission. */ { pjsip_inv_callback inv_cb; /* Init the callback for INVITE session: */ pj_bzero(&inv_cb, sizeof(inv_cb)); inv_cb.on_state_changed = &call_on_state_changed; inv_cb.on_new_session = &call_on_forked; inv_cb.on_media_update = &call_on_media_update; /* Initialize invite session module: */ status = pjsip_inv_usage_init(g_endpt, &inv_cb); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* Initialize 100rel support */ status = pjsip_100rel_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* * Register our module to receive incoming requests. */ status = pjsip_endpt_register_module( g_endpt, &mod_simpleua); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Register message logger module. */ status = pjsip_endpt_register_module( g_endpt, &msg_logger); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Initialize media endpoint. * This will implicitly initialize PJMEDIA too. */ #if PJ_HAS_THREADS status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt); #else status = pjmedia_endpt_create(&cp.factory, pjsip_endpt_get_ioqueue(g_endpt), 0, &g_med_endpt); #endif PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Add PCMA/PCMU codec to the media endpoint. */ #if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0 status = pjmedia_codec_g711_init(g_med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); #endif #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) /* Init video subsystem */ pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512); status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_converter_mgr_create(pool, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_vid_codec_mgr_create(pool, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_vid_dev_subsys_init(&cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); # if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0 /* Init ffmpeg video codecs */ status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); # endif /* PJMEDIA_HAS_FFMPEG_VID_CODEC */ #endif /* PJMEDIA_HAS_VIDEO */ /* * Create media transport used to send/receive RTP/RTCP socket. * One media transport is needed for each call. Application may * opt to re-use the same media transport for subsequent calls. */ for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) { status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL, RTP_PORT + i*2, 0, &g_med_transport[i]); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create media transport", status); return 1; } /* * Get socket info (address, port) of the media transport. We will * need this info to create SDP (i.e. the address and port info in * the SDP). */ pjmedia_transport_info_init(&g_med_tpinfo[i]); pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]); pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info, sizeof(pjmedia_sock_info)); } /* * If URL is specified, then make call immediately. */ if (argc > 1) { pj_sockaddr hostaddr; char hostip[PJ_INET6_ADDRSTRLEN+2]; char temp[80]; pj_str_t dst_uri = pj_str(argv[1]); pj_str_t local_uri; pjsip_dialog *dlg; pjmedia_sdp_session *local_sdp; pjsip_tx_data *tdata; if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to retrieve local host IP", status); return 1; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>", hostip, SIP_PORT); local_uri = pj_str(temp); /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &local_uri, /* local URI */ &local_uri, /* local Contact */ &dst_uri, /* remote URI */ &dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create UAC dialog", status); return 1; } /* If we expect the outgoing INVITE to be challenged, then we should * put the credentials in the dialog here, with something like this: * { pjsip_cred_info cred[1]; cred[0].realm = pj_str("sip.server.realm"); cred[0].scheme = pj_str("digest"); cred[0].username = pj_str("theuser"); cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; cred[0].data = pj_str("thepassword"); pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred); } * */ /* Get the SDP body to be put in the outgoing INVITE, by asking * media endpoint to create one for us. */ status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */ dlg->pool, /* pool. */ MAX_MEDIA_CNT, /* # of streams */ g_sock_info, /* RTP sock info */ &local_sdp); /* the SDP result */ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create the INVITE session, and pass the SDP returned earlier * as the session's initial capability. */ status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* If we want the initial INVITE to travel to specific SIP proxies, * then we should put the initial dialog's route set here. The final * route set will be updated once a dialog has been established. * To set the dialog's initial route set, we do it with something * like this: * { pjsip_route_hdr route_set; pjsip_route_hdr *route; const pj_str_t hname = { "Route", 5 }; char *uri = "sip:proxy.server;lr"; pj_list_init(&route_set); route = pjsip_parse_hdr( dlg->pool, &hname, uri, strlen(uri), NULL); PJ_ASSERT_RETURN(route != NULL, 1); pj_list_push_back(&route_set, route); pjsip_dlg_set_route_set(dlg, &route_set); } * * Note that Route URI SHOULD have an ";lr" parameter! */ /* Create initial INVITE request. * This INVITE request will contain a perfectly good request and * an SDP body as well. */ status = pjsip_inv_invite(g_inv, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Send initial INVITE request. * From now on, the invite session's state will be reported to us * via the invite session callbacks. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } else { /* No URL to make call to */ PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls...")); } /* Loop until one call is completed */ for (;!g_complete;) { pj_time_val timeout = {0, 10}; pjsip_endpt_handle_events(g_endpt, &timeout); } /* On exit, dump current memory usage: */ dump_pool_usage(THIS_FILE, &cp); /* Destroy audio ports. Destroy the audio port first * before the stream since the audio port has threads * that get/put frames to the stream. */ if (g_snd_port) pjmedia_snd_port_destroy(g_snd_port); #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) /* Destroy video ports */ if (g_vid_capturer) pjmedia_vid_port_destroy(g_vid_capturer); if (g_vid_renderer) pjmedia_vid_port_destroy(g_vid_renderer); #endif /* Destroy streams */ if (g_med_stream) pjmedia_stream_destroy(g_med_stream); #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) if (g_med_vstream) pjmedia_vid_stream_destroy(g_med_vstream); /* Deinit ffmpeg codec */ # if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0 pjmedia_codec_ffmpeg_vid_deinit(); # endif #endif /* Destroy media transports */ for (i = 0; i < MAX_MEDIA_CNT; ++i) { if (g_med_transport[i]) pjmedia_transport_close(g_med_transport[i]); } /* Deinit pjmedia endpoint */ if (g_med_endpt) pjmedia_endpt_destroy(g_med_endpt); /* Deinit pjsip endpoint */ if (g_endpt) pjsip_endpt_destroy(g_endpt); /* Release pool */ if (pool) pj_pool_release(pool); return 0; }
pj_status_t init_stack(const std::string& system_name, const std::string& sas_address, int trusted_port, int untrusted_port, const std::string& local_host, const std::string& home_domain, const std::string& sprout_cluster_domain, const std::string& alias_hosts, int num_pjsip_threads, int num_worker_threads) { pj_status_t status; pj_sockaddr pri_addr; pj_sockaddr addr_list[16]; unsigned addr_cnt = PJ_ARRAY_SIZE(addr_list); unsigned i; // Set up the vectors of threads. The threads don't get created until // start_stack is called. pjsip_threads.resize(num_pjsip_threads); worker_threads.resize(num_worker_threads); // Get ports and host names specified on options. If local host was not // specified, use the host name returned by pj_gethostname. memset(&stack_data, 0, sizeof(stack_data)); char* local_host_cstr = strdup(local_host.c_str()); char* home_domain_cstr = strdup(home_domain.c_str()); char* sprout_cluster_domain_cstr = strdup(sprout_cluster_domain.c_str()); stack_data.trusted_port = trusted_port; stack_data.untrusted_port = untrusted_port; stack_data.local_host = (local_host != "") ? pj_str(local_host_cstr) : *pj_gethostname(); stack_data.home_domain = (home_domain != "") ? pj_str(home_domain_cstr) : stack_data.local_host; stack_data.sprout_cluster_domain = (sprout_cluster_domain != "") ? pj_str(sprout_cluster_domain_cstr) : stack_data.local_host; // Initialize SAS logging. if (system_name != "") { SAS::init(system_name.length(), system_name.c_str(), sas_address); } else { SAS::init(stack_data.local_host.slen, stack_data.local_host.ptr, sas_address); } // Initialise PJSIP and all the associated resources. status = init_pjsip(); // Register the stack module. pjsip_endpt_register_module(stack_data.endpt, &mod_stack); stack_data.module_id = mod_stack.id; // Create listening transports for trusted and untrusted ports. if (stack_data.trusted_port != 0) { status = create_listener_transports(stack_data.trusted_port, &stack_data.tcp_factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } if (stack_data.untrusted_port != 0) { status = create_listener_transports(stack_data.untrusted_port, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } // List all names matching local endpoint. // Note that PJLIB version 0.6 and newer has a function to // enumerate local IP interface (pj_enum_ip_interface()), so // by using it would be possible to list all IP interfaces in // this host. // The first address is important since this would be the one // to be added in Record-Route. stack_data.name[stack_data.name_cnt] = stack_data.local_host; stack_data.name_cnt++; if (pj_gethostip(pj_AF_INET(), &pri_addr) == PJ_SUCCESS) { pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], pj_inet_ntoa(pri_addr.ipv4.sin_addr)); stack_data.name_cnt++; } // Get the rest of IP interfaces. if (pj_enum_ip_interface(pj_AF_INET(), &addr_cnt, addr_list) == PJ_SUCCESS) { for (i = 0; i < addr_cnt; ++i) { if (addr_list[i].ipv4.sin_addr.s_addr == pri_addr.ipv4.sin_addr.s_addr) { continue; } pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], pj_inet_ntoa(addr_list[i].ipv4.sin_addr)); stack_data.name_cnt++; } } // Add loopback address. #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF stack_data.name[stack_data.name_cnt] = pj_str("127.0.0.1"); stack_data.name_cnt++; #endif stack_data.name[stack_data.name_cnt] = pj_str("localhost"); stack_data.name_cnt++; // Parse the list of alias host names. if (alias_hosts != "") { std::list<std::string> hosts; Utils::split_string(alias_hosts, ',', hosts, 0, true); for (std::list<std::string>::iterator it = hosts.begin(); it != hosts.end(); ++it) { pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], it->c_str()); stack_data.name_cnt++; } } LOG_STATUS("Local host aliases:"); for (i = 0; i < stack_data.name_cnt; ++i) { LOG_STATUS(" %.*s", (int)stack_data.name[i].slen, stack_data.name[i].ptr); } stack_data.stats_aggregator = new LastValueCache(Statistic::known_stats_count(), Statistic::known_stats()); latency_accumulator = new StatisticAccumulator("latency_us"); return status; }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; const unsigned char A[] = {127, 0, 0, 1}; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -22; #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 /* pj_inet_pton() */ /* pj_inet_ntop() */ { const pj_str_t s_ipv4 = pj_str("127.0.0.1"); const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42"); char buf_ipv4[PJ_INET_ADDRSTRLEN]; char buf_ipv6[PJ_INET6_ADDRSTRLEN]; pj_in_addr ipv4; pj_in6_addr ipv6; if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS) return -24; p = (unsigned char*)&ipv4; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { return -25; } if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS) return -26; p = (unsigned char*)&ipv6; if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 || p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 || p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff || p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42) { return -27; } if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS) return -28; if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0) return -29; if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS) return -30; if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0) return -31; } #endif /* PJ_HAS_IPV6 */ /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ /* Various constants */ #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0 if (PJ_AF_INET==0xFFFF) return -5500; if (PJ_AF_INET6==0xFFFF) return -5501; /* 0xFFFF could be a valid SOL_SOCKET (e.g: on some Win or Mac) */ //if (PJ_SOL_SOCKET==0xFFFF) return -5503; if (PJ_SOL_IP==0xFFFF) return -5502; if (PJ_SOL_TCP==0xFFFF) return -5510; if (PJ_SOL_UDP==0xFFFF) return -5520; if (PJ_SOL_IPV6==0xFFFF) return -5530; if (PJ_SO_TYPE==0xFFFF) return -5540; if (PJ_SO_RCVBUF==0xFFFF) return -5550; if (PJ_SO_SNDBUF==0xFFFF) return -5560; if (PJ_TCP_NODELAY==0xFFFF) return -5570; if (PJ_SO_REUSEADDR==0xFFFF) return -5580; if (PJ_MSG_OOB==0xFFFF) return -5590; if (PJ_MSG_PEEK==0xFFFF) return -5600; #endif return 0; }
static int purity_test(void) { PJ_LOG(3,("test", "...purity_test()")); #if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0 /* Check on "sin_len" member of sockaddr */ { const pj_str_t str_ip = {"1.1.1.1", 7}; pj_sockaddr addr[16]; pj_addrinfo ai[16]; unsigned cnt; pj_status_t rc; /* pj_enum_ip_interface() */ cnt = PJ_ARRAY_SIZE(addr); rc = pj_enum_ip_interface(pj_AF_UNSPEC(), &cnt, addr); if (rc == PJ_SUCCESS) { while (cnt--) CHECK_SA_ZERO_LEN(&addr[cnt], -10); } /* pj_gethostip() on IPv4 */ rc = pj_gethostip(pj_AF_INET(), &addr[0]); if (rc == PJ_SUCCESS) CHECK_SA_ZERO_LEN(&addr[0], -20); /* pj_gethostip() on IPv6 */ rc = pj_gethostip(pj_AF_INET6(), &addr[0]); if (rc == PJ_SUCCESS) CHECK_SA_ZERO_LEN(&addr[0], -30); /* pj_getdefaultipinterface() on IPv4 */ rc = pj_getdefaultipinterface(pj_AF_INET(), &addr[0]); if (rc == PJ_SUCCESS) CHECK_SA_ZERO_LEN(&addr[0], -40); /* pj_getdefaultipinterface() on IPv6 */ rc = pj_getdefaultipinterface(pj_AF_INET6(), &addr[0]); if (rc == PJ_SUCCESS) CHECK_SA_ZERO_LEN(&addr[0], -50); /* pj_getaddrinfo() on a host name */ cnt = PJ_ARRAY_SIZE(ai); rc = pj_getaddrinfo(pj_AF_UNSPEC(), pj_gethostname(), &cnt, ai); if (rc == PJ_SUCCESS) { while (cnt--) CHECK_SA_ZERO_LEN(&ai[cnt].ai_addr, -60); } /* pj_getaddrinfo() on an IP address */ cnt = PJ_ARRAY_SIZE(ai); rc = pj_getaddrinfo(pj_AF_UNSPEC(), &str_ip, &cnt, ai); if (rc == PJ_SUCCESS) { pj_assert(cnt == 1); CHECK_SA_ZERO_LEN(&ai[0].ai_addr, -70); } } #endif return 0; }
static pj_status_t init_proxy(void) { pj_sockaddr pri_addr; pj_sockaddr addr_list[16]; unsigned addr_cnt = PJ_ARRAY_SIZE(addr_list); unsigned i; /* List all names matching local endpoint. * Note that PJLIB version 0.6 and newer has a function to * enumerate local IP interface (pj_enum_ip_interface()), so * by using it would be possible to list all IP interfaces in * this host. */ /* The first address is important since this would be the one * to be added in Record-Route. */ if (pj_gethostip(pj_AF_INET(), &pri_addr)==PJ_SUCCESS) { pj_strdup2(global.pool, &global.name[global.name_cnt].host, pj_inet_ntoa(pri_addr.ipv4.sin_addr)); global.name[global.name_cnt].port = global.port; global.name_cnt++; } /* Get the rest of IP interfaces */ if (pj_enum_ip_interface(pj_AF_INET(), &addr_cnt, addr_list) == PJ_SUCCESS) { for (i=0; i<addr_cnt; ++i) { if (addr_list[i].ipv4.sin_addr.s_addr == pri_addr.ipv4.sin_addr.s_addr) continue; pj_strdup2(global.pool, &global.name[global.name_cnt].host, pj_inet_ntoa(addr_list[i].ipv4.sin_addr)); global.name[global.name_cnt].port = global.port; global.name_cnt++; } } /* Add loopback address. */ #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF global.name[global.name_cnt].host = pj_str("127.0.0.1"); global.name[global.name_cnt].port = global.port; global.name_cnt++; #endif global.name[global.name_cnt].host = *pj_gethostname(); global.name[global.name_cnt].port = global.port; global.name_cnt++; global.name[global.name_cnt].host = pj_str("localhost"); global.name[global.name_cnt].port = global.port; global.name_cnt++; PJ_LOG(3,(THIS_FILE, "Proxy started, listening on port %d", global.port)); PJ_LOG(3,(THIS_FILE, "Local host aliases:")); for (i=0; i<global.name_cnt; ++i) { PJ_LOG(3,(THIS_FILE, " %.*s:%d", (int)global.name[i].host.slen, global.name[i].host.ptr, global.name[i].port)); } if (global.record_route) { PJ_LOG(3,(THIS_FILE, "Using Record-Route mode")); } return PJ_SUCCESS; }
std::string SIPAccount::getMachineName (void) const { return std::string (pj_gethostname()->ptr, pj_gethostname()->slen); }
/* Esta función es invocada desde MAIN=>Plugin, al igual que en TCP Es invocada desde un thread. Básicamente lo que hace es bootear PJSIP y luego se queda loopeando eventos SIP (con un pseudo polling que tiene la LIB) Adicionalmente lanza el thread para controlar los eventos TUN (el tráfico es bidireccional) */ int sip_start(int argc,char **argv) { pj_status_t status; /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); pj_log_set_level(5); /* Then init PJLIB-UTIL: */ status = pjlib_util_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* Create global endpoint: */ { const pj_str_t *hostname; const char *endpt_name; /* Endpoint MUST be assigned a globally unique name. * The name will be used as the hostname in Warning header. */ /* For this implementation, we'll use hostname for simplicity */ hostname = pj_gethostname(); endpt_name = hostname->ptr; /* Create the endpoint: */ status = pjsip_endpt_create(&cp.factory, endpt_name, &g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* * Add UDP transport, with hard-coded port * Alternatively, application can use pjsip_udp_transport_attach() to * start UDP transport, if it already has an UDP socket (e.g. after it * resolves the address with STUN). */ { pj_sockaddr addr; pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to start UDP transport", status); return 1; } } /* * Init transaction layer. * This will create/initialize transaction hash tables etc. */ status = pjsip_tsx_layer_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Initialize UA layer module. * This will create/initialize dialog hash tables etc. */ status = pjsip_ua_init_module( g_endpt, NULL ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Esto seguramente no haga falta nada de esto de INVITE's ... */ /* * Init invite session module. * The invite session module initialization takes additional argument, * i.e. a structure containing callbacks to be called on specific * occurence of events. * * The on_state_changed and on_new_session callbacks are mandatory. * Application must supply the callback function. * * We use on_media_update() callback in this application to start * media transmission. */ { pjsip_inv_callback inv_cb; /* Init the callback for INVITE session: */ pj_bzero(&inv_cb, sizeof(inv_cb)); inv_cb.on_state_changed = &call_on_state_changed; inv_cb.on_new_session = &call_on_forked; // inv_cb.on_media_update = &call_on_media_update; /* Initialize invite session module: */ status = pjsip_inv_usage_init(g_endpt, &inv_cb); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* Initialize 100rel support */ status = pjsip_100rel_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* * Register our module to receive incoming requests. */ status = pjsip_endpt_register_module( g_endpt, &mod_simpleua); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Register message logger module. */ status = pjsip_endpt_register_module( g_endpt, &msg_logger); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); debug(1,"SIP Plugin launching thread for looping events"); pthread_create( &sip_plugin_event_thread, NULL, sip_loop_sip_events, NULL); /* Aqui es donde estamos esperando a recibir datos del PIPE (que viene del TUN DRIVER) hacemos I/O BLOCK con select */ sip_loop_tun_events(); // Aqui llegamos cuando ha muerto todo ;) return 0; }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; const unsigned char A[] = {127, 0, 0, 1}; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -22; #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 /* pj_inet_pton() */ /* pj_inet_ntop() */ { const pj_str_t s_ipv4 = pj_str("127.0.0.1"); const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42"); char buf_ipv4[PJ_INET_ADDRSTRLEN]; char buf_ipv6[PJ_INET6_ADDRSTRLEN]; pj_in_addr ipv4; pj_in6_addr ipv6; if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS) return -24; p = (unsigned char*)&ipv4; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { return -25; } if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS) return -26; p = (unsigned char*)&ipv6; if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 || p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 || p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff || p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42) { return -27; } if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS) return -28; if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0) return -29; if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS) return -30; if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0) return -31; } #endif /* PJ_HAS_IPV6 */ /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ return 0; }
pj_status_t init_stack(const std::string& system_name, const std::string& sas_address, int pcscf_trusted_port, int pcscf_untrusted_port, int scscf_port, int icscf_port, const std::string& local_host, const std::string& public_host, const std::string& home_domain, const std::string& additional_home_domains, const std::string& scscf_uri, const std::string& alias_hosts, SIPResolver* sipresolver, int num_pjsip_threads, int num_worker_threads, int record_routing_model, const int default_session_expires, QuiescingManager *quiescing_mgr_arg, LoadMonitor *load_monitor_arg, const std::string& cdf_domain) { pj_status_t status; pj_sockaddr pri_addr; pj_sockaddr addr_list[16]; unsigned addr_cnt = PJ_ARRAY_SIZE(addr_list); unsigned i; // Set up the vectors of threads. The threads don't get created until // start_stack is called. pjsip_threads.resize(num_pjsip_threads); worker_threads.resize(num_worker_threads); // Get ports and host names specified on options. If local host was not // specified, use the host name returned by pj_gethostname. char* local_host_cstr = strdup(local_host.c_str()); char* public_host_cstr = strdup(public_host.c_str()); char* home_domain_cstr = strdup(home_domain.c_str()); char* scscf_uri_cstr; if (scscf_uri.empty()) { // Create a default S-CSCF URI using the localhost and S-CSCF port. std::string tmp_scscf_uri = "sip:" + local_host + ":" + std::to_string(scscf_port) + ";transport=TCP"; scscf_uri_cstr = strdup(tmp_scscf_uri.c_str()); } else { // Use the specified URI. scscf_uri_cstr = strdup(scscf_uri.c_str()); } // This is only set on Bono nodes (it's the empty string otherwise) char* cdf_domain_cstr = strdup(cdf_domain.c_str()); // Copy port numbers to stack data. stack_data.pcscf_trusted_port = pcscf_trusted_port; stack_data.pcscf_untrusted_port = pcscf_untrusted_port; stack_data.scscf_port = scscf_port; stack_data.icscf_port = icscf_port; stack_data.sipresolver = sipresolver; // Copy other functional options to stack data. stack_data.default_session_expires = default_session_expires; // Work out local and public hostnames and cluster domain names. stack_data.local_host = (local_host != "") ? pj_str(local_host_cstr) : *pj_gethostname(); stack_data.public_host = (public_host != "") ? pj_str(public_host_cstr) : stack_data.local_host; stack_data.default_home_domain = (home_domain != "") ? pj_str(home_domain_cstr) : stack_data.local_host; stack_data.scscf_uri = pj_str(scscf_uri_cstr); stack_data.cdf_domain = pj_str(cdf_domain_cstr); // Build a set of home domains stack_data.home_domains = std::unordered_set<std::string>(); stack_data.home_domains.insert(PJUtils::pj_str_to_string(&stack_data.default_home_domain)); if (additional_home_domains != "") { std::list<std::string> domains; Utils::split_string(additional_home_domains, ',', domains, 0, true); stack_data.home_domains.insert(domains.begin(), domains.end()); } // Set up the default address family. This is IPv4 unless our local host is an IPv6 address. stack_data.addr_family = AF_INET; struct in6_addr dummy_addr; if (inet_pton(AF_INET6, local_host_cstr, &dummy_addr) == 1) { LOG_DEBUG("Local host is an IPv6 address - enabling IPv6 mode"); stack_data.addr_family = AF_INET6; } stack_data.record_route_on_every_hop = false; stack_data.record_route_on_initiation_of_originating = false; stack_data.record_route_on_initiation_of_terminating = false; stack_data.record_route_on_completion_of_originating = false; stack_data.record_route_on_completion_of_terminating = false; stack_data.record_route_on_diversion = false; if (scscf_port != 0) { switch (record_routing_model) { case 1: stack_data.record_route_on_initiation_of_originating = true; stack_data.record_route_on_completion_of_terminating = true; break; case 2: stack_data.record_route_on_initiation_of_originating = true; stack_data.record_route_on_initiation_of_terminating = true; stack_data.record_route_on_completion_of_originating = true; stack_data.record_route_on_completion_of_terminating = true; stack_data.record_route_on_diversion = true; break; case 3: stack_data.record_route_on_every_hop = true; stack_data.record_route_on_initiation_of_originating = true; stack_data.record_route_on_initiation_of_terminating = true; stack_data.record_route_on_completion_of_originating = true; stack_data.record_route_on_completion_of_terminating = true; stack_data.record_route_on_diversion = true; break; default: LOG_ERROR("Record-Route setting should be 1, 2, or 3, is %d. Defaulting to Record-Route on every hop.", record_routing_model); stack_data.record_route_on_every_hop = true; } } std::string system_name_sas = system_name; std::string system_type_sas = (pcscf_trusted_port != 0) ? "bono" : "sprout"; // Initialize SAS logging. if (system_name_sas == "") { system_name_sas = std::string(stack_data.local_host.ptr, stack_data.local_host.slen); } SAS::init(system_name, system_type_sas, SASEvent::CURRENT_RESOURCE_BUNDLE, sas_address, sas_write); // Initialise PJSIP and all the associated resources. status = init_pjsip(); // Register the stack module. pjsip_endpt_register_module(stack_data.endpt, &mod_stack); stack_data.module_id = mod_stack.id; // Initialize the PJUtils module. PJUtils::init(); // Create listening transports for the ports whichtrusted and untrusted ports. stack_data.pcscf_trusted_tcp_factory = NULL; if (stack_data.pcscf_trusted_port != 0) { status = start_transports(stack_data.pcscf_trusted_port, stack_data.local_host, &stack_data.pcscf_trusted_tcp_factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } stack_data.pcscf_untrusted_tcp_factory = NULL; if (stack_data.pcscf_untrusted_port != 0) { status = start_transports(stack_data.pcscf_untrusted_port, stack_data.public_host, &stack_data.pcscf_untrusted_tcp_factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } stack_data.scscf_tcp_factory = NULL; if (stack_data.scscf_port != 0) { status = start_transports(stack_data.scscf_port, stack_data.public_host, &stack_data.scscf_tcp_factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } stack_data.icscf_tcp_factory = NULL; if (stack_data.icscf_port != 0) { status = start_transports(stack_data.icscf_port, stack_data.public_host, &stack_data.icscf_tcp_factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); } // List all names matching local endpoint. // Note that PJLIB version 0.6 and newer has a function to // enumerate local IP interface (pj_enum_ip_interface()), so // by using it would be possible to list all IP interfaces in // this host. // The first address is important since this would be the one // to be added in Record-Route. stack_data.name[stack_data.name_cnt] = stack_data.local_host; stack_data.name_cnt++; if (strcmp(local_host_cstr, public_host_cstr)) { stack_data.name[stack_data.name_cnt] = stack_data.public_host; stack_data.name_cnt++; } if ((scscf_port != 0) && (!scscf_uri.empty())) { // S-CSCF enabled with a specified URI, so add host name from the URI to hostnames. pjsip_sip_uri* uri = (pjsip_sip_uri*)PJUtils::uri_from_string(scscf_uri, stack_data.pool); if (uri != NULL) { stack_data.name[stack_data.name_cnt] = uri->host; stack_data.name_cnt++; } } if (pj_gethostip(pj_AF_INET(), &pri_addr) == PJ_SUCCESS) { pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], pj_inet_ntoa(pri_addr.ipv4.sin_addr)); stack_data.name_cnt++; } // Get the rest of IP interfaces. if (pj_enum_ip_interface(pj_AF_INET(), &addr_cnt, addr_list) == PJ_SUCCESS) { for (i = 0; i < addr_cnt; ++i) { if (addr_list[i].ipv4.sin_addr.s_addr == pri_addr.ipv4.sin_addr.s_addr) { continue; } pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], pj_inet_ntoa(addr_list[i].ipv4.sin_addr)); stack_data.name_cnt++; } } // Note that we no longer consider 127.0.0.1 and localhost as aliases. // Parse the list of alias host names. stack_data.aliases = std::unordered_set<std::string>(); if (alias_hosts != "") { std::list<std::string> aliases; Utils::split_string(alias_hosts, ',', aliases, 0, true); stack_data.aliases.insert(aliases.begin(), aliases.end()); for (std::unordered_set<std::string>::iterator it = stack_data.aliases.begin(); it != stack_data.aliases.end(); ++it) { pj_strdup2(stack_data.pool, &stack_data.name[stack_data.name_cnt], it->c_str()); stack_data.name_cnt++; } } LOG_STATUS("Local host aliases:"); for (i = 0; i < stack_data.name_cnt; ++i) { LOG_STATUS(" %.*s", (int)stack_data.name[i].slen, stack_data.name[i].ptr); } // Set up the Last Value Cache, accumulators and counters. std::string zmq_port = SPROUT_ZMQ_PORT; if ((stack_data.pcscf_trusted_port != 0) && (stack_data.pcscf_untrusted_port != 0)) { zmq_port = BONO_ZMQ_PORT; } stack_data.stats_aggregator = new LastValueCache(num_known_stats, known_statnames, zmq_port); latency_accumulator = new StatisticAccumulator("latency_us", stack_data.stats_aggregator); queue_size_accumulator = new StatisticAccumulator("queue_size", stack_data.stats_aggregator); requests_counter = new StatisticCounter("incoming_requests", stack_data.stats_aggregator); overload_counter = new StatisticCounter("rejected_overload", stack_data.stats_aggregator); if (load_monitor_arg != NULL) { load_monitor = load_monitor_arg; } if (quiescing_mgr_arg != NULL) { quiescing_mgr = quiescing_mgr_arg; // Create an instance of the stack quiesce handler. This acts as a glue // class between the stack modulem connections tracker, and the quiescing // manager. stack_quiesce_handler = new StackQuiesceHandler(); // Create a new connection tracker, and register the quiesce handler with // it. connection_tracker = new ConnectionTracker(stack_quiesce_handler); // Register the quiesce handler with the quiescing manager (the former // implements the connection handling interface). quiescing_mgr->register_conns_handler(stack_quiesce_handler); } return status; }