/* * Get called number from To header * param msg SIP message * param touser User part of To header * param buffersize Size of touser buffer * return 0 success, -1 failure */ int ospGetToUserpart( struct sip_msg* msg, char* touser, int buffersize) { struct to_body* to; struct sip_uri uri; int result = -1; touser[0] = '\0'; if (msg->to != NULL) { if (parse_headers(msg, HDR_TO_F, 0) == 0) { to = get_to(msg); if (parse_uri(to->uri.s, to->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, touser, buffersize); ospSkipPlus(touser); result = 0; } else { LM_ERR("failed to parse To uri\n"); } } else { LM_ERR("failed to parse To header\n"); } } else { LM_ERR("failed to find To header\n"); } return result; }
/* * Get display name from From header * param msg SIP message * param fromdisplay Display name of From header * param bufsize Size of fromdisplay buffer * return 0 success, -1 failure */ int ospGetFromDisplay( struct sip_msg* msg, char* fromdisplay, int bufsize) { struct to_body* from; int result = -1; if ((fromdisplay != NULL) && (bufsize > 0)) { fromdisplay[0] = '\0'; if (msg->from != NULL) { if (parse_from_header(msg) == 0) { from = get_from(msg); if ((from->display.s != NULL) && (from->display.len > 0)) { ospCopyStrToBuffer(&from->display, fromdisplay, bufsize); result = 0; } } else { LM_ERR("failed to parse From header\n"); } } else { LM_ERR("failed to find From header\n"); } } else { LM_ERR("bad parameters to parse display name from From header\n"); } return result; }
/* * Get user part from Remote-Party-ID header * param msg SIP message * param user User part of Remote-Party-ID header * param bufsize Size of fromuser buffer * return 0 success, 1 without RPID, -1 failure */ int ospGetRpidUserpart( struct sip_msg* msg, char* rpiduser, int bufsize) { struct to_body* rpid; struct sip_uri uri; int result = -1; if ((rpiduser != NULL) && (bufsize > 0)) { rpiduser[0] = '\0'; if (msg->rpid != NULL) { if (parse_rpid_header(msg) == 0) { rpid = get_rpid(msg); if (parse_uri(rpid->uri.s, rpid->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, rpiduser, bufsize); ospSkipUserParam(rpiduser); result = 0; } else { LM_ERR("failed to parse RPID uri\n"); } } else { LM_ERR("failed to parse RPID uri\n"); } } else { LM_DBG("without RPID header\n"); result = 1; } } else { LM_ERR("bad parameters to parse user part from RPID\n"); } return result; }
/* * Get display name from To header * param msg SIP message * param todisplay Display name of To header * param bufsize Size of todisplay buffer * return 0 success, -1 failure */ int ospGetToDisplay( struct sip_msg* msg, char* todisplay, int bufsize) { struct to_body* to; int result = -1; if ((todisplay != NULL) && (bufsize > 0)) { todisplay[0] = '\0'; if (msg->to != NULL) { if (parse_headers(msg, HDR_TO_F, 0) == 0) { to = get_to(msg); if ((to->display.s != NULL) && (to->display.len > 0)) { ospCopyStrToBuffer(&to->display, todisplay, bufsize); result = 0; } } else { LM_ERR("failed to parse To header\n"); } } else { LM_ERR("failed to find To header\n"); } } else { LM_ERR("bad parameters to parse display name from To header\n"); } return result; }
/* * Get user part from P-Asserted-Identity header * param msg SIP message * param user User part of P-Asserted-Identity header * param bufsize Size of fromuser buffer * return 0 success, 1 without PAI, -1 failure */ int ospGetPaiUserpart( struct sip_msg* msg, char* paiuser, int bufsize) { struct to_body* pai; struct sip_uri uri; int result = -1; if ((paiuser != NULL) && (bufsize > 0)) { paiuser[0] = '\0'; if (msg->pai != NULL) { if (parse_pai_header(msg) == 0) { pai = get_pai(msg); if (parse_uri(pai->uri.s, pai->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, paiuser, bufsize); ospSkipUserParam(paiuser); result = 0; } else { LM_ERR("failed to parse PAI uri\n"); } } else { LM_ERR("failed to parse PAI uri\n"); } } else { LM_DBG("without PAI header\n"); result = 1; } } else { LM_ERR("bad parameters to parse user part from PAI\n"); } return result; }
/* * Get first VIA header and use the IP or host name * param msg SIP message * param sourceaddress Source address * param buffersize Size of sourceaddress * return 0 success, -1 failure */ int ospGetSourceAddress( struct sip_msg* msg, char* sourceaddress, int buffersize) { struct hdr_field* hf; struct via_body* via; int result = -1; /* * No need to call parse_headers, called already and VIA is parsed * anyway by default */ for (hf = msg->headers; hf; hf = hf->next) { if (hf->type == HDR_VIA_T) { // found first VIA via = (struct via_body*)hf->parsed; ospCopyStrToBuffer(&via->host, sourceaddress, buffersize); LM_DBG("source address '%s'\n", sourceaddress); result = 0; break; } } return result; }
/* * Get calling number from Remote-Party-ID header * param msg SIP message * param rpiduser User part of Remote-Party-ID header * param buffersize Size of fromuser buffer * return 0 success, -1 failure */ int ospGetRpidUserpart( struct sip_msg* msg, char* rpiduser, int buffersize) { struct to_body* rpid; struct sip_uri uri; int result = -1; rpiduser[0] = '\0'; if (_osp_use_rpid != 0) { if (msg->rpid != NULL) { if (parse_rpid_header(msg) == 0) { rpid = get_rpid(msg); if (parse_uri(rpid->uri.s, rpid->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, rpiduser, buffersize); ospSkipPlus(rpiduser); result = 0; } else { LM_ERR("failed to parse RPID uri\n"); } } else { LM_ERR("failed to parse RPID header\n"); } } else { LM_DBG("without RPID header\n"); } } else { LM_DBG("do not use RPID header\n"); } return result; }
/* * Get calling number from From header * param msg SIP message * param fromuser User part of From header * param buffersize Size of fromuser buffer * return 0 success, -1 failure */ int ospGetFromUserpart( struct sip_msg* msg, char* fromuser, int buffersize) { struct to_body* from; struct sip_uri uri; int result = -1; fromuser[0] = '\0'; if (msg->from != NULL) { if (parse_from_header(msg) == 0) { from = get_from(msg); if (parse_uri(from->uri.s, from->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, fromuser, buffersize); ospSkipPlus(fromuser); result = 0; } else { LM_ERR("failed to parse From uri\n"); } } else { LM_ERR("failed to parse From header\n"); } } else { LM_ERR("failed to find From header\n"); } return result; }
/* * Get route parameters from the 1st Route or Request-Line * param msg SIP message * param routeparameters Route parameters * param bufsize Size of routeparameters * return 0 success, -1 failure */ int ospGetRouteParameters( struct sip_msg* msg, char* routeparameters, int bufsize) { struct hdr_field* hf; rr_t* rt; struct sip_uri uri; int result = -1; if ((routeparameters != NULL) && (bufsize > 0)) { LM_DBG("parsed uri host '%.*s' port '%d' vars '%.*s'\n", msg->parsed_uri.host.len, msg->parsed_uri.host.s, msg->parsed_uri.port_no, msg->parsed_uri.params.len, msg->parsed_uri.params.s); if (!(hf = msg->route)) { LM_DBG("there is no Route headers\n"); } else if (!(rt = (rr_t*)hf->parsed)) { LM_ERR("route headers are not parsed\n"); } else if (parse_uri(rt->nameaddr.uri.s, rt->nameaddr.uri.len, &uri) != 0) { LM_ERR("failed to parse the Route uri '%.*s'\n", rt->nameaddr.uri.len, rt->nameaddr.uri.s); } else if (check_self(&uri.host, uri.port_no ? uri.port_no : SIP_PORT, PROTO_NONE) != 1) { LM_DBG("the Route uri is NOT mine\n"); LM_DBG("host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no); LM_DBG("params '%.*s'\n", uri.params.len, uri.params.s); } else { LM_DBG("the Route uri IS mine - '%.*s'\n", uri.params.len, uri.params.s); LM_DBG("host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no); ospCopyStrToBuffer(&uri.params, routeparameters, bufsize); result = 0; } if ((result == -1) && (msg->parsed_uri.params.len > 0)) { LM_DBG("using route parameters from Request-Line uri\n"); ospCopyStrToBuffer(&msg->parsed_uri.params, routeparameters, bufsize); routeparameters[msg->parsed_uri.params.len] = '\0'; result = 0; } } else { LM_ERR("bad parameters to parse parameters from Route header\n"); } return result; }
/* * Get next hop using the first Route not generated by this proxy or URI from the Request-Line * param msg SIP message * param nexthop Next hop IP * param buffersize Size of nexthop */ void ospGetNextHop( struct sip_msg* msg, char* nexthop, int buffersize) { struct hdr_field* hf; struct sip_uri uri; rr_t* rt; int found = 0; for (hf = msg->headers; hf; hf = hf->next) { if (hf->type == HDR_ROUTE_T) { for (rt = (rr_t*)hf->parsed; rt; rt = rt->next) { if (parse_uri(rt->nameaddr.uri.s, rt->nameaddr.uri.len, &uri) == 0) { LM_DBG("host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no); if (check_self(&uri.host, uri.port_no ? uri.port_no : SIP_PORT, PROTO_NONE) != 1) { LM_DBG("it is NOT me, FOUND!\n"); ospCopyStrToBuffer(&uri.host, nexthop, buffersize); found = 1; break; } else { LM_DBG("it IS me, keep looking\n"); } } else { LM_ERR("failed to parse route uri '%.*s'\n", rt->nameaddr.uri.len, rt->nameaddr.uri.s); } } if (found == 1) { break; } } } if (!found) { LM_DBG("using the Request-Line instead host '%.*s' port '%d'\n", msg->parsed_uri.host.len, msg->parsed_uri.host.s, msg->parsed_uri.port_no); ospCopyStrToBuffer(&msg->parsed_uri.host, nexthop, buffersize); found = 1; } }
/* * Get number and domain from Diversion header * param msg SIP message * param user User part of Diversion header * param userbufsize Size of user buffer * param host Host part of Diversion header * param hostbufsize Size of host buffer * return 0 success, 1 without Diversion, -1 failure */ int ospGetDiversion( struct sip_msg* msg, char* user, int userbufsize, char* host, int hostbufsize) { struct to_body* diversion; struct sip_uri uri; int result = -1; if (((user != NULL) && (userbufsize > 0)) && ((host != NULL) && (hostbufsize > 0))){ user[0] = '\0'; host[0] = '\0'; if (msg->diversion != NULL) { if (parse_diversion_header(msg) == 0) { diversion = get_diversion(msg); if (parse_uri(diversion->uri.s, diversion->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, user, userbufsize); ospSkipUserParam(user); if (uri.port_no != 0) { snprintf(host, hostbufsize, "%.*s:%d", uri.host.len, uri.host.s, uri.port_no); host[hostbufsize - 1] = '\0'; } else { ospCopyStrToBuffer(&uri.host, host, hostbufsize); } result = 0; } else { LM_ERR("failed to parse Diversion uri\n"); } } else { LM_ERR("failed to parse Diversion header\n"); } } else { LM_DBG("without Diversion header\n"); result = 1; } } else { LM_ERR("bad paraneters to parse number from Diversion\n"); } return result; }
/* * Get user part from P-Charge-Info header * param msg SIP message * param user User part of P-Charge-Info header * param bufsize Size of fromuser buffer * return 0 success, 1 without P-Charge-Info, -1 failure */ int ospGetPChargeInfoUserpart( struct sip_msg* msg, char* pciuser, int bufsize) { static const char* header = "P-Charge-Info"; struct to_body body; struct to_body* pci=NULL; struct hdr_field *hf; struct sip_uri uri; int result = -1; if ((pciuser != NULL) && (bufsize > 0)) { pciuser[0] = '\0'; if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse message\n"); return -1; } for (hf = msg->headers; hf; hf = hf->next) { if ((hf->type == HDR_OTHER_T) && (hf->name.len == strlen(header)) && (strncasecmp(hf->name.s, header, hf->name.len) == 0)) { if (!(pci = hf->parsed)) { pci = &body; parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pci); } if (pci->error != PARSE_ERROR) { if (parse_uri(pci->uri.s, pci->uri.len, &uri) == 0) { ospCopyStrToBuffer(&uri.user, pciuser, bufsize); ospSkipUserParam(pciuser); result = 0; } else { LM_ERR("failed to parse P-Charge-Info uri\n"); } if (pci == &body) { free_to_params(pci); } } else { LM_ERR("bad P-Charge-Info header\n"); } break; } } if (!hf) { LM_DBG("without P-Charge-Info header\n"); result = 1; } } else { LM_ERR("bad parameters to parse user part from PAI\n"); } return result; }
/* * Get called number from Request-Line header * param msg SIP message * param touser User part of To header * param buffersize Size of touser buffer * return 0 success, -1 failure */ int ospGetUriUserpart( struct sip_msg* msg, char* uriuser, int buffersize) { int result = -1; uriuser[0] = '\0'; if (parse_sip_msg_uri(msg) >= 0) { ospCopyStrToBuffer(&msg->parsed_uri.user, uriuser, buffersize); ospSkipPlus(uriuser); result = 0; } else { LM_ERR("failed to parse Request-Line URI\n"); } return result; }
/* * Get host info from To header * param msg SIP message * param tohost Host part of To header * param bufsize Size of tohost buffer * return 0 success, -1 failure */ int ospGetToHostpart( struct sip_msg* msg, char* tohost, int bufsize) { struct to_body* to; struct sip_uri uri; int result = -1; if ((tohost != NULL) && (bufsize > 0)) { tohost[0] = '\0'; if (msg->to != NULL) { if (parse_headers(msg, HDR_TO_F, 0) == 0) { to = get_to(msg); if (parse_uri(to->uri.s, to->uri.len, &uri) == 0) { if (uri.port_no != 0) { snprintf(tohost, bufsize, "%.*s:%d", uri.host.len, uri.host.s, uri.port_no); tohost[bufsize - 1] = '\0'; } else { ospCopyStrToBuffer(&uri.host, tohost, bufsize); } result = 0; } else { LM_ERR("failed to parse To uri\n"); } } else { LM_ERR("failed to parse To header\n"); } } else { LM_ERR("failed to find To header\n"); } } else { LM_ERR("bad parameters to parse hsto info from To header\n"); } return result; }
/* * Get first VIA header and use the IP or host name * param msg SIP message * param viaaddr Via header IP address * param bufsize Size of viaaddr * return 0 success, -1 failure */ int ospGetViaAddress( struct sip_msg* msg, char* viaaddr, int bufsize) { struct hdr_field* hf; struct via_body* via; int result = -1; if ((viaaddr != NULL) && (bufsize > 0)) { /* * No need to call parse_headers, called already and VIA is parsed * anyway by default */ for (hf = msg->headers; hf; hf = hf->next) { if (hf->type == HDR_VIA_T) { /* found first VIA */ via = (struct via_body*)hf->parsed; if (via->port != 0) { snprintf(viaaddr, bufsize, "%.*s:%d", via->host.len, via->host.s, via->port); viaaddr[bufsize - 1] = '\0'; } else { ospCopyStrToBuffer(&via->host, viaaddr, bufsize); } LM_DBG("via address '%s'\n", viaaddr); result = 0; break; } } } else { LM_ERR("bad parameters to parse host from VIA header\n"); } return result; }
/* * Get user part from Request-Line header * param msg SIP message * param uriuser User part of To header * param bufsize Size of touser buffer * return 0 success, -1 failure */ int ospGetUriUserpart( struct sip_msg* msg, char* uriuser, int bufsize) { int result = -1; if ((uriuser != NULL) && (bufsize > 0)) { uriuser[0] = '\0'; if (parse_sip_msg_uri(msg) >= 0) { ospCopyStrToBuffer(&msg->parsed_uri.user, uriuser, bufsize); ospSkipUserParam(uriuser); result = 0; } else { LM_ERR("failed to parse Request-Line URI\n"); } } else { LM_ERR("bad parameters to parse user part from RURI\n"); } return result; }
/* * Get User-Agent header * param msg SIP message * param useragent User-Agent buffer * param bufsize Size of useragent * return 0 success, -1 failure */ int ospGetUserAgent( struct sip_msg* msg, char* useragent, int bufsize) { int result = -1; if ((useragent != NULL) && (bufsize > 0)) { useragent[0] = '\0'; if (parse_headers(msg, HDR_USERAGENT_F, 0) == 0) { if ((msg->user_agent != NULL) && (msg->user_agent->body.s != NULL) && (msg->user_agent->body.len > 0)) { ospCopyStrToBuffer(&msg->user_agent->body, useragent, bufsize); } result = 0; } else { LM_ERR("failed to parse User-Agent header\n"); } } else { LM_ERR("bad paraneters to parse User-Agent header\n"); } return result; }
/* * Get operator name from Request-Line * param msg SIP message * param type Operator name type * param name Operator name buffer * param namebufsize Size of name buffer * return 0 success, 1 not use NP or without operator name, -1 failure */ int ospGetOperatorName( struct sip_msg* msg, OSPE_OPERATOR_NAME type, char* name, int namebufsize) { str sv; param_hooks_t phooks; param_t* params = NULL; param_t* pit; int result = -1; if (((name != NULL) && (namebufsize > 0))) { name[0] = '\0'; if (_osp_use_np != 0) { if (parse_sip_msg_uri(msg) >= 0) { switch (msg->parsed_uri.type) { case TEL_URI_T: case TELS_URI_T: sv = msg->parsed_uri.params; break; case ERROR_URI_T: case SIP_URI_T: case SIPS_URI_T: default: sv = msg->parsed_uri.user; break; } parse_params(&sv, CLASS_ANY, &phooks, ¶ms); for (pit = params; pit; pit = pit->next) { switch (type) { case OSPC_OPNAME_SPID: if ((pit->name.len == OSP_SPID_SIZE) && (strncasecmp(pit->name.s, OSP_SPID_NAME, OSP_SPID_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; case OSPC_OPNAME_OCN: if ((pit->name.len == OSP_OCN_SIZE) && (strncasecmp(pit->name.s, OSP_OCN_NAME, OSP_OCN_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; case OSPC_OPNAME_SPN: if ((pit->name.len == OSP_SPN_SIZE) && (strncasecmp(pit->name.s, OSP_SPN_NAME, OSP_SPN_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; case OSPC_OPNAME_ALTSPN: if ((pit->name.len == OSP_ALTSPN_SIZE) && (strncasecmp(pit->name.s, OSP_ALTSPN_NAME, OSP_ALTSPN_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; case OSPC_OPNAME_MCC: if ((pit->name.len == OSP_MCC_SIZE) && (strncasecmp(pit->name.s, OSP_MCC_NAME, OSP_MCC_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; case OSPC_OPNAME_MNC: if ((pit->name.len == OSP_MNC_SIZE) && (strncasecmp(pit->name.s, OSP_MNC_NAME, OSP_MNC_SIZE) == 0) && (name[0] == '\0')) { ospCopyStrToBuffer(&pit->body, name, namebufsize); } break; default: break; } } if (params != NULL) { free_params(params); } if (name[0] != '\0') { result = 0; } else { LM_DBG("without operator name\n"); result = 1; } } else { LM_ERR("failed to parse Request-Line URI\n"); } } else { LM_DBG("do not use number portability\n"); result = 1; } } else { LM_ERR("bad parameters to parse operator name\n"); } return result; }
/* * Request OSP authorization and routeing * param msg SIP message * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure, others error */ int ospRequestRouting( struct sip_msg* msg, char* ignore1, char* ignore2) { int i, errcode; char rn[OSP_STRBUF_SIZE]; char cic[OSP_STRBUF_SIZE]; int npdi; OSPE_OPERATOR_NAME type; char opname[OSPC_OPNAME_NUMBER][OSP_STRBUF_SIZE]; osp_inbound inbound; char sourcebuf[OSP_STRBUF_SIZE]; char srcdevbuf[OSP_STRBUF_SIZE]; char divhostbuf[OSP_STRBUF_SIZE]; char useragent[OSP_STRBUF_SIZE]; struct usr_avp* avp = NULL; int_str avpval; unsigned int cinfonum = 0; char cinfo[OSP_DEF_CINFONUM][OSP_STRBUF_SIZE]; char cinfostr[OSP_STRBUF_SIZE]; unsigned int callidnumber = 1; OSPT_CALL_ID* callids[callidnumber]; unsigned int logsize = 0; char* detaillog = NULL; char tohost[OSP_STRBUF_SIZE]; char tohostbuf[OSP_STRBUF_SIZE]; const char* preferred[2] = { NULL }; unsigned int destcount; struct timeval ts, te, td; char datebuf[OSP_STRBUF_SIZE]; unsigned int sdpfpnum = 0; char sdpfp[OSP_DEF_SDPFPNUM][OSP_STRBUF_SIZE]; char* sdpfpstr[OSP_DEF_SDPFPNUM]; OSPTTRANHANDLE trans = -1; int result = MODULE_RETURNCODE_FALSE; ospInitInboundInfo(&inbound); if ((errcode = OSPPTransactionNew(_osp_provider, &trans)) != OSPC_ERR_NO_ERROR) { LM_ERR("failed to create new OSP transaction (%d)\n", errcode); } else if (ospGetCallId(msg, &(callids[0])) != 0) { LM_ERR("failed to extract call id\n"); } else if (ospGetFromUser(msg, inbound.calling, sizeof(inbound.calling)) != 0) { LM_ERR("failed to extract calling number\n"); } else if ((ospGetUriUser(msg, inbound.called, sizeof(inbound.called)) != 0) && (ospGetToUser(msg, inbound.called, sizeof(inbound.called)) != 0)) { LM_ERR("failed to extract called number\n"); } else if (ospGetSource(msg, inbound.source, sizeof(inbound.source)) != 0) { LM_ERR("failed to extract source address\n"); } else if (ospGetSrcDev(msg, inbound.srcdev, sizeof(inbound.srcdev)) != 0) { LM_ERR("failed to extract source deivce address\n"); } else { inbound.authtime = time(NULL); if(msg->rcv.bind_address && msg->rcv.bind_address->address_str.s) { ospCopyStrToBuffer(&msg->rcv.bind_address->address_str, inbound.ingressaddr, sizeof(inbound.ingressaddr)); } ospConvertToOutAddress(inbound.source, sourcebuf, sizeof(sourcebuf)); ospConvertToOutAddress(inbound.srcdev, srcdevbuf, sizeof(srcdevbuf)); switch (_osp_service_type) { case 1: case 2: OSPPTransactionSetServiceType(trans, (_osp_service_type == 1) ? OSPC_SERVICE_NPQUERY : OSPC_SERVICE_CNAMQUERY); ospGetToHost(msg, tohost, sizeof(tohost)); ospConvertToOutAddress(tohost, tohostbuf, sizeof(tohostbuf)); preferred[0] = tohostbuf; destcount = 1; break; case 0: default: OSPPTransactionSetServiceType(trans, OSPC_SERVICE_VOICE); destcount = _osp_max_dests; break; } if (ospGetNpParam(msg, rn, sizeof(rn), cic, sizeof(cic), &npdi) == 0) { OSPPTransactionSetNumberPortability(trans, rn, cic, npdi); } for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) { if (ospGetOperatorName(msg, type, opname[type], sizeof(opname[type])) == 0) { OSPPTransactionSetOperatorName(trans, type, opname[type]); } } if (ospGetFromDisplay(msg, inbound.fromdisplay, sizeof(inbound.fromdisplay)) == 0) { OSPPTransactionSetFrom(trans, OSPC_NFORMAT_DISPLAYNAME, inbound.fromdisplay); } if (ospGetFromUri(msg, inbound.fromuri, sizeof(inbound.fromuri)) == 0) { OSPPTransactionSetFrom(trans, OSPC_NFORMAT_URL, inbound.fromuri); } if (ospGetToUri(msg, inbound.touri, sizeof(inbound.touri)) == 0) { OSPPTransactionSetTo(trans, OSPC_NFORMAT_URL, inbound.touri); } if (ospGetPaiUser(msg, inbound.paiuser, sizeof(inbound.paiuser)) == 0) { OSPPTransactionSetAssertedId(trans, OSPC_NFORMAT_E164, inbound.paiuser); } if (ospGetRpidUser(msg, inbound.rpiduser, sizeof(inbound.rpiduser)) == 0) { OSPPTransactionSetRemotePartyId(trans, OSPC_NFORMAT_E164, inbound.rpiduser); } if (ospGetPciUser(msg, inbound.pciuser, sizeof(inbound.pciuser)) == 0) { OSPPTransactionSetChargeInfo(trans, OSPC_NFORMAT_E164, inbound.pciuser); } if (ospGetDiversion(msg, inbound.divuser, sizeof(inbound.divuser), inbound.divhost, sizeof(inbound.divhost)) == 0) { ospConvertToOutAddress(inbound.divhost, divhostbuf, sizeof(divhostbuf)); } else { divhostbuf[0] = '\0'; } OSPPTransactionSetDiversion(trans, inbound.divuser, divhostbuf); if (ospGetUserAgent(msg, useragent, sizeof(useragent)) == 0) { OSPPTransactionSetUserAgent(trans, useragent); } OSPPTransactionSetProtocol(trans, OSPC_PROTTYPE_SOURCE, OSPC_PROTNAME_SIP); if (ospGetAVP(_osp_snid_avpid, _osp_snid_avptype, inbound.snid, sizeof(inbound.snid)) == 0) { OSPPTransactionSetNetworkIds(trans, inbound.snid, ""); } else { inbound.snid[0] = '\0'; } if (_osp_cinfo_avpid >= 0) { for (i = 0, avp = search_first_avp(_osp_cinfo_avptype, _osp_cinfo_avpid, NULL, 0); ((i < OSP_DEF_CINFONUM) && (avp != NULL)); i++, avp = search_next_avp(avp, NULL)) { get_avp_val(avp, &avpval); if ((avp->flags & AVP_VAL_STR) && (avpval.s.s && avpval.s.len)) { snprintf(cinfo[i], sizeof(cinfo[i]), "%.*s", avpval.s.len, avpval.s.s); } else { cinfo[i][0] = '\0'; } } cinfonum = i; cinfostr[0] = '\0'; for (i = 0; i < cinfonum; i++) { if (cinfo[cinfonum - i - 1][0] != '\0') { OSPPTransactionSetCustomInfo(trans, i, cinfo[cinfonum - i - 1]); snprintf(cinfostr + strlen(cinfostr), sizeof(cinfostr) - strlen(cinfostr), "custom_info%d '%s' ", i + 1, cinfo[cinfonum - i - 1]); } } } if (ospGetAVP(_osp_srcmedia_avpid, _osp_srcmedia_avptype, inbound.srcmedia, sizeof(inbound.srcmedia)) == 0) { OSPPTransactionSetSrcAudioAddr(trans, inbound.srcmedia); } else { inbound.srcmedia[0] = '\0'; } inbound.date = 0; if (ospGetAVP(_osp_reqdate_avpid, _osp_reqdate_avptype, datebuf, sizeof(datebuf)) == 0) { if (ospStrToTime(datebuf, &inbound.date) == 0) { OSPPTransactionSetRequestDate(trans, inbound.date); } } if (_osp_sdpfp_avpid >= 0) { for (i = 0, avp = search_first_avp(_osp_sdpfp_avptype, _osp_sdpfp_avpid, NULL, 0); ((i < OSP_DEF_SDPFPNUM) && (avp != NULL)); i++, avp = search_next_avp(avp, NULL)) { get_avp_val(avp, &avpval); if ((avp->flags & AVP_VAL_STR) && (avpval.s.s && avpval.s.len)) { snprintf(sdpfp[i], sizeof(sdpfp[i]), "%.*s", avpval.s.len, avpval.s.s); } else { sdpfp[i][0] = '\0'; } } sdpfpnum = i; for (i = 0; i < sdpfpnum; i++) { sdpfpstr[i] = sdpfp[sdpfpnum - i - 1]; } OSPPTransactionSetFingerPrint(trans, sdpfpnum, (const char**)sdpfpstr); } ospReportIdentity(trans); LM_INFO("request auth and routing for: " "service '%d' " "source '%s' " "srcdev '%s' " "snid '%s' " "calling '%s' " "called '%s' " "preferred '%s' " "nprn '%s' " "npcic '%s' " "npdi '%d' " /* "spid '%s' " "ocn '%s' " "spn '%s' " "altspn '%s' " "mcc '%s' " "mnc '%s' " */ "fromdisplay '%s' " "paiuser '%s' " "rpiduser '%s' " "pciuser '%s' " "divuser '%s' " "divhost '%s' " "srcmedia '%s' " "callid '%.*s' " "destcount '%d' " "%s\n", _osp_service_type, sourcebuf, srcdevbuf, inbound.snid, inbound.calling, inbound.called, (preferred[0] == NULL) ? "" : preferred[0], rn, cic, npdi, /* opname[OSPC_OPNAME_SPID], opname[OSPC_OPNAME_OCN], opname[OSPC_OPNAME_SPN], opname[OSPC_OPNAME_ALTSPN], opname[OSPC_OPNAME_MCC], opname[OSPC_OPNAME_MNC], */ inbound.fromdisplay, inbound.paiuser, inbound.rpiduser, inbound.pciuser, inbound.divuser, divhostbuf, inbound.srcmedia, callids[0]->Length, callids[0]->Value, destcount, cinfostr); gettimeofday(&ts, NULL); /* try to request authorization */ errcode = OSPPTransactionRequestAuthorisation( trans, /* transaction handle */ sourcebuf, /* from the configuration file */ srcdevbuf, /* source device of call, protocol specific, in OSP format */ inbound.calling, /* calling number in nodotted e164 notation */ OSPC_NFORMAT_E164, /* calling number format */ inbound.called, /* called number */ OSPC_NFORMAT_E164, /* called number format */ "", /* optional username string, used if no number */ callidnumber, /* number of call ids, here always 1 */ callids, /* sized-1 array of call ids */ preferred, /* preferred destinations */ &destcount, /* max destinations, after call dest_count */ &logsize, /* size allocated for detaillog (next param) 0=no log */ detaillog); /* memory location for detaillog to be stored */ gettimeofday(&te, NULL); timersub(&te, &ts, &td); LM_INFO("authreq cost = %lu.%06lu for call-id '%.*s'\n", td.tv_sec, td.tv_usec, callids[0]->Length, callids[0]->Value); if ((errcode == OSPC_ERR_NO_ERROR) && (ospLoadRoutes(trans, destcount, &inbound) == 0)) { LM_INFO("there are '%d' OSP routes, call_id '%.*s'\n", destcount, callids[0]->Length, callids[0]->Value); result = MODULE_RETURNCODE_TRUE; } else { LM_ERR("failed to request auth and routing (%d), call_id '%.*s'\n", errcode, callids[0]->Length, callids[0]->Value); switch (errcode) { case OSPC_ERR_HTTP_BAD_REQUEST: result = -4000; break; case OSPC_ERR_TRAN_BAD_REQUEST: result = -4001; break; case OSPC_ERR_HTTP_UNAUTHORIZED: result = -4010; break; case OSPC_ERR_TRAN_UNAUTHORIZED: result = -4011; break; case OSPC_ERR_TRAN_ROUTE_BLOCKED: result = -4030; break; case OSPC_ERR_TRAN_ROUTE_NOT_FOUND: result = -4040; break; case OSPC_ERR_TRAN_MAY_NOT_ORIGINATE: result = -4050; break; case OSPC_ERR_TRAN_CALLING_INVALID: result = -4280; break; case OSPC_ERR_SOCK_CONNECT_FAILED: result = -4800; break; case OSPC_ERR_SOCK_SELECT_FAILED: result = -4801; break; case OSPC_ERR_HTTP_SERVER_NOT_READY: result = -4802; break; case OSPC_ERR_TRAN_CALLED_FILTERING: result = -4840; break; case OSPC_ERR_HTTP_SERVICE_UNAVAILABLE: result = -5030; break; case OSPC_ERR_TRAN_DECLINE: result = -6030; break; case OSPC_ERR_NO_ERROR: /* AuthRsp ok but ospLoadRoutes fails */ result = MODULE_RETURNCODE_ERROR; break; default: result = MODULE_RETURNCODE_FALSE; break; } } } if (callids[0] != NULL) { OSPPCallIdDelete(&(callids[0])); } if (trans != -1) { OSPPTransactionDelete(trans); } return result; }
/* * Get next hop using the first Route not generated by this proxy or URI from the Request-Line * param msg SIP message * param nexthop Next hop IP * param bufsize Size of nexthop * return 0 success, -1 failure */ int ospGetNextHop( struct sip_msg* msg, char* nexthop, int bufsize) { struct hdr_field* hf; struct sip_uri uri; rr_t* rt; int found = 0; int result = -1; if ((nexthop != NULL) && (bufsize > 0)) { result = 0; for (hf = msg->headers; hf; hf = hf->next) { if (hf->type == HDR_ROUTE_T) { for (rt = (rr_t*)hf->parsed; rt; rt = rt->next) { if (parse_uri(rt->nameaddr.uri.s, rt->nameaddr.uri.len, &uri) == 0) { LM_DBG("host '%.*s' port '%d'\n", uri.host.len, uri.host.s, uri.port_no); if (check_self(&uri.host, uri.port_no ? uri.port_no : SIP_PORT, PROTO_NONE) != 1) { LM_DBG("it is NOT me, FOUND!\n"); if (uri.port_no != 0) { snprintf(nexthop, bufsize, "%.*s:%d", uri.host.len, uri.host.s, uri.port_no); nexthop[bufsize - 1] = '\0'; } else { ospCopyStrToBuffer(&uri.host, nexthop, bufsize); } found = 1; break; } else { LM_DBG("it IS me, keep looking\n"); } } else { LM_ERR("failed to parse route uri '%.*s'\n", rt->nameaddr.uri.len, rt->nameaddr.uri.s); } } if (found == 1) { break; } } } if (!found) { LM_DBG("using the Request-Line instead host '%.*s' port '%d'\n", msg->parsed_uri.host.len, msg->parsed_uri.host.s, msg->parsed_uri.port_no); if (msg->parsed_uri.port_no != 0) { snprintf(nexthop, bufsize, "%.*s:%d", msg->parsed_uri.host.len, msg->parsed_uri.host.s, msg->parsed_uri.port_no); nexthop[bufsize - 1] = '\0'; } else { ospCopyStrToBuffer(&msg->parsed_uri.host, nexthop, bufsize); } found = 1; } } else { LM_ERR("bad parameters to get next hop\n"); } return result; }
/* * Report OSP usage from OSP cookie * param msg SIP message * param cookie OSP cookie (buffer owned by ospReportUsage, can be modified) * param callid Call ID * param release Who releases the call first. 0 orig, 1 term * param type Usage type * return */ static int ospReportUsageFromCookie( struct sip_msg* msg, char* cookie, OSPT_CALL_ID* callid, OSPE_RELEASE release, OSPE_ROLE type) { char* tmp; char* token; char tag; char* value; unsigned long long transid = 0; time_t authtime = 0; unsigned destcount = 0; time_t duration = 0; time_t endtime = time(NULL); int cookieflags = 0; unsigned releasecode; char firstvia[OSP_STRBUF_SIZE]; char fromdisplay[OSP_STRBUF_SIZE]; char from[OSP_STRBUF_SIZE]; char rpid[OSP_STRBUF_SIZE]; char pai[OSP_STRBUF_SIZE]; char divuser[OSP_STRBUF_SIZE]; char divhost[OSP_STRBUF_SIZE]; char pci[OSP_STRBUF_SIZE]; char todisplay[OSP_STRBUF_SIZE]; char to[OSP_STRBUF_SIZE]; char nexthop[OSP_STRBUF_SIZE]; char* snid = NULL; char* dnid = NULL; char* display; char* calling; char* called; char* originator = NULL; char* terminator; char source[OSP_STRBUF_SIZE]; char dest[OSP_STRBUF_SIZE]; char srcdev[OSP_STRBUF_SIZE]; char receive[OSP_STRBUF_SIZE]; char* ingress = NULL; char* egress = NULL; OSPTTRANHANDLE transaction = -1; int errorcode; LM_DBG("cookie '%s' type '%d'\n", cookie == NULL ? "NULL" : cookie, type); if (cookie != NULL) { for (token = strtok_r(cookie, "_", &tmp); token; token = strtok_r(NULL, "_", &tmp)) { tag = *token; value= token + 1; switch (tag) { case OSP_COOKIE_TRANSID: case OSP_COOKIE_TRANSIDUP: transid = atoll(value); cookieflags |= OSP_COOKIEHAS_TRANSID; break; case OSP_COOKIE_AUTHTIME: case OSP_COOKIE_AUTHTIMEUP: authtime = atoi(value); duration = endtime - authtime; cookieflags |= OSP_COOKIEHAS_AUTHTIME; break; case OSP_COOKIE_SRCIP: case OSP_COOKIE_SRCIPUP: originator = value; cookieflags |= OSP_COOKIEHAS_SRCIP; break; case OSP_COOKIE_DCOUNT: case OSP_COOKIE_DCOUNTUP: destcount = (unsigned)atoi(value); cookieflags |= OSP_COOKIEHAS_DSTCOUNT; break; case OSP_COOKIE_SNID: case OSP_COOKIE_SNIDUP: snid = value; break; case OSP_COOKIE_DNID: case OSP_COOKIE_DNIDUP: dnid = value; break; default: LM_ERR("unexpected tag '%c' / value '%s'\n", tag, value); break; } } } switch (type) { case OSPC_ROLE_DESTINATION: if (cookieflags == OSP_COOKIEHAS_TERMALL) { releasecode = 10016; } else { releasecode = 9016; } break; case OSPC_ROLE_SOURCE: case OSPC_ROLE_OTHER: case OSPC_ROLE_UNDEFINED: default: if (cookieflags == OSP_COOKIEHAS_ORIGALL) { releasecode = 10016; } else { releasecode = 9016; } break; } if (releasecode == 9016) { transid = 0; originator = NULL; authtime = 0; duration = 0; destcount = 0; } if(msg->rcv.bind_address && msg->rcv.bind_address->address_str.s) { ospCopyStrToBuffer(&msg->rcv.bind_address->address_str, receive, sizeof(receive)); } ospGetViaAddress(msg, firstvia, sizeof(firstvia)); ospGetFromDisplay(msg, fromdisplay, sizeof(fromdisplay)); ospGetFromUserpart(msg, from, sizeof(from)); ospGetRpidUserpart(msg, rpid, sizeof(rpid)); ospGetPaiUserpart(msg, pai, sizeof(pai)); ospGetDiversion(msg, divuser, sizeof(divuser), divhost, sizeof(divhost)); ospGetPChargeInfoUserpart(msg, pci, sizeof(pci)); ospGetToDisplay(msg, todisplay, sizeof(todisplay)); ospGetToUserpart(msg, to, sizeof(to)); ospGetNextHop(msg, nexthop, sizeof(nexthop)); LM_DBG("first via '%s' from '%s' to '%s' next hop '%s'\n", firstvia, from, to, nexthop); if (release == OSPC_RELEASE_DESTINATION) { LM_DBG("term '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->Length, callid->Value, transid); if (originator == NULL) { originator = nexthop; } display = todisplay; calling = to; called = from; terminator = firstvia; egress = receive; } else { if (release == OSPC_RELEASE_SOURCE) { LM_DBG("orig '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->Length, callid->Value, transid); } else { LM_DBG("unknown '%s' released the call, call_id '%.*s' transaction_id '%llu'\n", firstvia, callid->Length, callid->Value, transid); } if (originator == NULL) { originator = firstvia; } display = fromdisplay; calling = from; called = to; terminator = nexthop; ingress = receive; } errorcode = OSPPTransactionNew(_osp_provider, &transaction); LM_DBG("created transaction handle '%d' (%d)\n", transaction, errorcode); switch (type) { case OSPC_ROLE_DESTINATION: srcdev[0] = '\0'; ospConvertToOutAddress(originator, source, sizeof(source)); strncpy(dest, _osp_out_device, sizeof(dest)); dest[sizeof(dest) - 1] = '\0'; break; case OSPC_ROLE_SOURCE: case OSPC_ROLE_OTHER: case OSPC_ROLE_UNDEFINED: default: ospConvertToOutAddress(originator, srcdev, sizeof(srcdev)); strncpy(source, _osp_out_device, sizeof(source)); source[sizeof(source) - 1] = '\0'; ospConvertToOutAddress(terminator, dest, sizeof(dest)); break; } /* RoleInfo must be set before BuildUsageFromScratch */ OSPPTransactionSetRoleInfo(transaction, OSPC_RSTATE_STOP, OSPC_RFORMAT_OSP, OSPC_RVENDOR_OPENSIPS); errorcode = OSPPTransactionBuildUsageFromScratch( transaction, transid, type, source, dest, srcdev, "", calling, OSPC_NFORMAT_E164, called, OSPC_NFORMAT_E164, callid->Length, callid->Value, 0, NULL, NULL); LM_DBG("built usage handle '%d' (%d)\n", transaction, errorcode); if ((errorcode == OSPC_ERR_NO_ERROR) && (destcount > 0)) { errorcode = OSPPTransactionSetDestinationCount( transaction, destcount); errorcode = OSPPTransactionSetTotalSetupAttempts( transaction, destcount); } if (errorcode == OSPC_ERR_NO_ERROR) { OSPPTransactionSetProtocol(transaction, OSPC_PROTTYPE_SOURCE, OSPC_PROTNAME_SIP); OSPPTransactionSetProtocol(transaction, OSPC_PROTTYPE_DESTINATION, OSPC_PROTNAME_SIP); OSPPTransactionSetSrcNetworkId(transaction, snid); OSPPTransactionSetDestNetworkId(transaction, dnid); OSPPTransactionSetFrom(transaction, OSPC_NFORMAT_DISPLAYNAME, display); OSPPTransactionSetRemotePartyId(transaction, OSPC_NFORMAT_E164, rpid); OSPPTransactionSetAssertedId(transaction, OSPC_NFORMAT_E164, pai); OSPPTransactionSetDiversion(transaction, divuser, divhost); OSPPTransactionSetChargeInfo(transaction, OSPC_NFORMAT_E164, pci); OSPPTransactionSetProxyIngressAddr(transaction, ingress); OSPPTransactionSetProxyEgressAddr(transaction, egress); OSPPTransactionSetCDRProxy(transaction, _osp_in_device, OSP_OPENSIPS, NULL); ospReportUsageWrapper( transaction, releasecode, duration, authtime, endtime, 0, 0, 0, 0, release); } return errorcode; }
/* * Report OSP usage * SER uses AVP to add RR pararmters * param msg SIP message * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure */ int ospReportUsage( struct sip_msg* msg, char* ignore1, char* ignore2) { int_str cookieval; struct usr_avp* cookieavp = NULL; static const int FROMFLAGS = AVP_TRACK_FROM | AVP_CLASS_URI | AVP_NAME_STR | AVP_VAL_STR; static const int TOFLAGS = AVP_TRACK_TO | AVP_CLASS_URI | AVP_NAME_STR | AVP_VAL_STR; char buffer[OSP_HEADERBUF_SIZE]; OSPTCALLID* callid = NULL; int result = MODULE_RETURNCODE_FALSE; LOG(L_DBG, "osp: ospReportUsage\n"); ospGetCallId(msg, &callid); if (callid != NULL) { if ((cookieavp = search_first_avp(FROMFLAGS, (int_str)OSP_ORIGCOOKIE_NAME, &cookieval, NULL)) != 0 || (cookieavp = search_first_avp(TOFLAGS, (int_str)OSP_ORIGCOOKIE_NAME, &cookieval, NULL)) != 0) { ospCopyStrToBuffer(&cookieval.s, buffer, sizeof(buffer)); LOG(L_DBG, "orig cookie '%s'\n", buffer); LOG(L_INFO, "osp: report orig duration for call_id '%.*s'\n", callid->ospmCallIdLen, callid->ospmCallIdVal); ospReportUsageFromCookie(msg, buffer, callid, OSPC_SOURCE); result = MODULE_RETURNCODE_TRUE; } if ((cookieavp = search_first_avp(FROMFLAGS, (int_str)OSP_TERMCOOKIE_NAME, &cookieval, NULL)) != 0 || (cookieavp = search_first_avp(TOFLAGS, (int_str)OSP_TERMCOOKIE_NAME, &cookieval, NULL)) != 0) { ospCopyStrToBuffer(&cookieval.s, buffer, sizeof(buffer)); LOG(L_DBG, "term cookie '%s'\n", buffer); LOG(L_INFO, "osp: report term duration for call_id '%.*s'\n", callid->ospmCallIdLen, callid->ospmCallIdVal); ospReportUsageFromCookie(msg, buffer, callid, OSPC_DESTINATION); result = MODULE_RETURNCODE_TRUE; } if (result == MODULE_RETURNCODE_FALSE) { LOG(L_DBG, "without orig or term OSP information\n"); LOG(L_INFO, "report other duration for call_id '%.*s'\n", callid->ospmCallIdLen, callid->ospmCallIdVal); ospReportUsageFromCookie(msg, NULL, callid, OSPC_SOURCE); result = MODULE_RETURNCODE_TRUE; } OSPPCallIdDelete(&callid); } if (result == MODULE_RETURNCODE_FALSE) { LOG(L_DBG, "osp: failed to report usage\n"); } return result; }
/* * Get number portability parameter from Request-Line * param msg SIP message * param rn Routing number * param rnbufsize Size of rn buffer * param cic Carrier identification code * param cicbufsize Size of cic buffer * param npdi NP database dip indicator * return 0 success, 1 not use NP or without NP parameters, -1 failure */ int ospGetNpParameters( struct sip_msg* msg, char* rn, int rnbufsize, char* cic, int cicbufsize, int* npdi) { str sv; param_hooks_t phooks; param_t* params = NULL; param_t* pit; int result = -1; if (((rn != NULL) && (rnbufsize > 0)) && ((cic != NULL) && (cicbufsize > 0)) && (npdi != NULL)) { rn[0] = '\0'; cic[0] = '\0'; *npdi = 0; if (_osp_use_np != 0) { if (parse_sip_msg_uri(msg) >= 0) { switch (msg->parsed_uri.type) { case TEL_URI_T: case TELS_URI_T: sv = msg->parsed_uri.params; break; case ERROR_URI_T: case SIP_URI_T: case SIPS_URI_T: default: sv = msg->parsed_uri.user; break; } parse_params(&sv, CLASS_ANY, &phooks, ¶ms); for (pit = params; pit; pit = pit->next) { if ((pit->name.len == OSP_RN_SIZE) && (strncasecmp(pit->name.s, OSP_RN_NAME, OSP_RN_SIZE) == 0) && (rn[0] == '\0')) { ospCopyStrToBuffer(&pit->body, rn, rnbufsize); } else if ((pit->name.len == OSP_CIC_SIZE) && (strncasecmp(pit->name.s, OSP_CIC_NAME, OSP_CIC_SIZE) == 0) && (cic[0] == '\0')) { ospCopyStrToBuffer(&pit->body, cic, cicbufsize); } else if ((pit->name.len == OSP_NPDI_SIZE) && (strncasecmp(pit->name.s, OSP_NPDI_NAME, OSP_NPDI_SIZE) == 0)) { *npdi = 1; } } if (params != NULL) { free_params(params); } if ((rn[0] != '\0') || (cic[0] != '\0') || (*npdi != 0)) { result = 0; } else { LM_DBG("without number portability parameters\n"); result = 1; } } else { LM_ERR("failed to parse Request-Line URI\n"); } } else { LM_DBG("do not use number portability\n"); result = 1; } } else { LM_ERR("bad parameters to parse number portability parameters\n"); } return result; }