/* * Report originate call setup usage */ void ospReportOrigSetupUsage(void) { osp_dest* dest = NULL; osp_dest* lastused = NULL; struct usr_avp* destavp = NULL; int_str destval; struct search_state state; OSPTTRANHANDLE transaction = -1; int lastcode = 0; int errorcode; LOG(L_DBG, "osp: ospReportOrigSetupUsage\n"); errorcode = OSPPTransactionNew(_osp_provider, &transaction); for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, &destval, &state); destavp != NULL; destavp = search_next_avp(&state, &destval)) { /* OSP destination is wrapped in a string */ dest = (osp_dest*)destval.s.s; if (dest->used == 1) { if (dest->reported == 1) { LOG(L_DBG, "osp: orig setup already reported\n"); break; } else { dest->reported = 1; } LOG(L_DBG, "osp: iterating through used destination\n"); ospDumpDestination(dest); lastused = dest; errorcode = ospBuildUsageFromDestination(transaction, dest, lastcode); lastcode = dest->lastcode; } else { LOG(L_DBG, "osp: destination has not been used, breaking out\n"); break; } } if (lastused) { LOG(L_INFO, "osp: report orig setup for call_id '%.*s' transaction_id '%llu'\n", lastused->callidsize, lastused->callid, lastused->transid); errorcode = ospReportUsageFromDestination(transaction, lastused); } else { /* If a Toolkit transaction handle was created, but we did not find * any destinations to report, we need to release the handle. Otherwise, * the ospReportUsageFromDestination will release it. */ OSPPTransactionDelete(transaction); } }
int cw_osp_terminate(int handle, int cause, time_t start, time_t duration) { unsigned int dummy = 0; int res = -1; enum OSPEFAILREASON reason; time_t endTime = 0; time_t alertTime = 0; time_t connectTime = 0; unsigned isPddInfoPresent = 0; unsigned pdd = 0; unsigned releaseSource = 0; unsigned char *confId = ""; reason = cause2reason(cause); if (OSPPTransactionRecordFailure(handle, reason)) cw_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle); else if (OSPPTransactionReportUsage(handle, duration, start, endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId, 0, 0, 0, 0, &dummy, NULL)) cw_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle); else { cw_log(LOG_DEBUG, "Completed recording handle %d\n", handle); OSPPTransactionDelete(handle); res = 0; } return res; }
/* * Report OSP usage thread function * param usagearg OSP usage information * return */ static OSPTTHREADRETURN ospReportUsageWork( void* usagearg) { int i; const int MAX_RETRIES = 5; osp_usage* usage; int errorcode; usage = (osp_usage*)usagearg; OSPPTransactionRecordFailure( usage->transaction, usage->cause); #if 0 OSPPTransactionSetTermCause( usage->transaction, OSPC_TCAUSE_SIP, usage->cause, NULL); #endif for (i = 1; i <= MAX_RETRIES; i++) { errorcode = OSPPTransactionReportUsage( usage->transaction, usage->duration, usage->start, usage->end, usage->alert, usage->connect, usage->haspdd, usage->pdd * 1000, usage->release, NULL, -1, -1, -1, -1, NULL, NULL); if (errorcode == OSPC_ERR_NO_ERROR) { LM_DBG("reporte usage for '%llu'\n", ospGetTransactionId(usage->transaction)); break; } else { LM_ERR("failed to report usage for '%llu' (%d) attempt '%d' of '%d'\n", ospGetTransactionId(usage->transaction), errorcode, i, MAX_RETRIES); } } OSPPTransactionDelete(usage->transaction); free(usage); OSPTTHREADRETURN_NULL(); }
/* * Report originate call setup usage */ void ospReportOrigSetupUsage(void) { struct usr_avp* destavp = NULL; int_str destval; osp_dest* dest = NULL; osp_dest* lastused = NULL; OSPTTRANHANDLE trans = -1; int lastcode = 0; OSPE_ROLE_STATE rstate; int errcode; errcode = OSPPTransactionNew(_osp_provider, &trans); if (errcode != OSPC_ERR_NO_ERROR) { return; } for (destavp = search_first_avp(AVP_VAL_STR, _osp_origdest_avpid, NULL, 0); destavp != NULL; destavp = search_next_avp(destavp, NULL)) { get_avp_val(destavp, &destval); /* OSP destination is wrapped in a string */ dest = (osp_dest*)destval.s.s; if (dest->used == 1) { LM_DBG("iterating through used destination\n"); if (dest->reported == 1) { LM_DBG("orig setup already reported\n"); break; } else { dest->reported = 1; ospDumpDestination(dest); lastused = dest; if (dest->lastcode == 200) { rstate = OSPC_RSTATE_START; } else if (dest->lastcode == 300) { rstate = OSPC_RSTATE_REDIRECT; } else { rstate = OSPC_RSTATE_STOP; } /* RoleInfo must be set before BuildUsageFromScratch */ OSPPTransactionSetRoleInfo(trans, rstate, OSPC_RFORMAT_OSP, OSPC_RVENDOR_OPENSIPS); ospBuildUsageFromDestination(trans, dest, lastcode); OSPPTransactionSetProtocol(trans, OSPC_PROTTYPE_SOURCE, OSPC_PROTNAME_SIP); OSPPTransactionSetProtocol(trans, OSPC_PROTTYPE_DESTINATION, dest->protocol); lastcode = dest->lastcode; } } else { LM_DBG("destination has not been used, breaking out\n"); break; } } if (lastused) { LM_INFO("report orig setup for call_id '%.*s' transaction_id '%llu'\n", lastused->callidsize, lastused->callid, lastused->transid); ospReportUsageFromDestination(trans, lastused); } else { /* If a Toolkit transaction handle was created, but we did not find * any destinations to report, we need to release the handle. Otherwise, * the ospReportUsageFromDestination will release it. */ OSPPTransactionDelete(trans); } }
/* * 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; }
/* * Request OSP authorization and routeing * param msg SIP message * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure, MODULE_RETURNCODE_ERROR error */ int ospRequestRouting( struct sip_msg* msg, char* ignore1, char* ignore2) { int errcode; time_t authtime; char calling[OSP_STRBUF_SIZE]; char called[OSP_STRBUF_SIZE]; char rn[OSP_STRBUF_SIZE]; char cic[OSP_STRBUF_SIZE]; int npdi; OSPE_OPERATOR_NAME type; char opname[OSPC_OPNAME_NUMBER][OSP_STRBUF_SIZE]; char source[OSP_STRBUF_SIZE]; char sourcebuf[OSP_STRBUF_SIZE]; char srcdev[OSP_STRBUF_SIZE]; char srcdevbuf[OSP_STRBUF_SIZE]; char rpid[OSP_STRBUF_SIZE]; char pai[OSP_STRBUF_SIZE]; char divuser[OSP_STRBUF_SIZE]; char divhost[OSP_STRBUF_SIZE]; char divhostbuf[OSP_STRBUF_SIZE]; char pci[OSP_STRBUF_SIZE]; struct usr_avp* snidavp = NULL; int_str snidval; char snid[OSP_STRBUF_SIZE]; struct usr_avp* cinfoavp = NULL; int_str cinfoval; unsigned int cinfonum = 0, i; char cinfo[OSP_DEF_CINFOS][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; OSPTTRANHANDLE trans = -1; int result = MODULE_RETURNCODE_FALSE; if ((errcode = OSPPTransactionNew(_osp_provider, &trans)) != OSPC_ERR_NO_ERROR) { LM_ERR("failed to create new OSP transaction (%d)\n", errcode); } else if (ospGetFromUserpart(msg, calling, sizeof(calling)) != 0) { LM_ERR("failed to extract calling number\n"); } else if ((ospGetUriUserpart(msg, called, sizeof(called)) != 0) && (ospGetToUserpart(msg, called, sizeof(called)) != 0)) { LM_ERR("failed to extract called number\n"); } else if (ospGetCallId(msg, &(callids[0])) != 0) { LM_ERR("failed to extract call id\n"); } else if (ospGetSource(msg, source, sizeof(source)) != 0) { LM_ERR("failed to extract source address\n"); } else if (ospGetSourceDevice(msg, srcdev, sizeof(srcdev)) != 0) { LM_ERR("failed to extract source deivce address\n"); } else { authtime = time(NULL); ospConvertToOutAddress(source, sourcebuf, sizeof(sourcebuf)); ospConvertToOutAddress(srcdev, srcdevbuf, sizeof(srcdevbuf)); switch (_osp_service_type) { case 1: OSPPTransactionSetServiceType(trans, OSPC_SERVICE_NPQUERY); ospGetToHostpart(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 (ospGetNpParameters(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 (ospGetRpidUserpart(msg, rpid, sizeof(rpid)) == 0) { OSPPTransactionSetRemotePartyId(trans, OSPC_NFORMAT_E164, rpid); } if (ospGetPaiUserpart(msg, pai, sizeof(pai)) == 0) { OSPPTransactionSetAssertedId(trans, OSPC_NFORMAT_E164, pai); } if (ospGetDiversion(msg, divuser, sizeof(divuser), divhost, sizeof(divhost)) == 0) { ospConvertToOutAddress(divhost, divhostbuf, sizeof(divhostbuf)); } else { divhostbuf[0] = '\0'; } OSPPTransactionSetDiversion(trans, divuser, divhostbuf); OSPPTransactionSetProtocol(trans, OSPC_PROTTYPE_SOURCE, OSPC_PROTNAME_SIP); if (ospGetPChargeInfoUserpart(msg, pci, sizeof(pci)) == 0) { OSPPTransactionSetChargeInfo(trans, OSPC_NFORMAT_E164, pci); } if ((_osp_snid_avpid >= 0) && ((snidavp = search_first_avp(_osp_snid_avptype, _osp_snid_avpid, &snidval, 0)) != NULL) && (snidavp->flags & AVP_VAL_STR) && (snidval.s.s && snidval.s.len)) { snprintf(snid, sizeof(snid), "%.*s", snidval.s.len, snidval.s.s); snid[sizeof(snid) - 1] = '\0'; OSPPTransactionSetNetworkIds(trans, snid, ""); } else { snid[0] = '\0'; } if (_osp_cinfo_avpid >= 0) { for (i = 0, cinfoavp = search_first_avp(_osp_cinfo_avptype, _osp_cinfo_avpid, NULL, 0); ((i < OSP_DEF_CINFOS) && (cinfoavp != NULL)); i++, cinfoavp = search_next_avp(cinfoavp, NULL)) { get_avp_val(cinfoavp, &cinfoval); if ((cinfoavp->flags & AVP_VAL_STR) && (cinfoval.s.s && cinfoval.s.len)) { snprintf(cinfo[i], sizeof(cinfo[i]), "%.*s", cinfoval.s.len, cinfoval.s.s); cinfo[i][sizeof(cinfo[i]) - 1] = '\0'; } 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]); } } cinfostr[sizeof(cinfostr) - 1] = '\0'; } LM_INFO("request auth and routing for: " "service_type '%d' " "source '%s' " "source_dev '%s' " "source_networkid '%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' " */ "rpid '%s' " "pai '%s' " "div_user '%s' " "div_host '%s' " "pci '%s' " "call_id '%.*s' " "dest_count '%d' " "%s\n", _osp_service_type, sourcebuf, srcdevbuf, snid, calling, 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], */ rpid, pai, divuser, divhostbuf, pci, callids[0]->Length, callids[0]->Value, destcount, cinfostr); /* try to request authorization */ errcode = OSPPTransactionRequestAuthorisation( trans, /* transaction handle */ sourcebuf, /* from the configuration file */ srcdevbuf, /* source device of call, protocol specific, in OSP format */ calling, /* calling number in nodotted e164 notation */ OSPC_NFORMAT_E164, /* calling number format */ 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 */ if ((errcode == OSPC_ERR_NO_ERROR) && (ospLoadRoutes(trans, destcount, source, srcdev, called, authtime, rpid, pai, divuser, divhostbuf, pci) == 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_TRAN_ROUTE_BLOCKED: result = -403; break; case OSPC_ERR_TRAN_ROUTE_NOT_FOUND: result = -404; break; case OSPC_ERR_TRAN_CALLING_INVALID: result = -428; break; case OSPC_ERR_TRAN_CALLED_FILTERING: result = -484; 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; }
/* * Validate OSP token * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure */ int ospValidateHeader ( struct sip_msg* msg, char* ignore1, char* ignore2) { int errorcode; OSPTTRANHANDLE transaction = -1; unsigned int authorized = 0; unsigned int timelimit = 0; void* detaillog = NULL; unsigned int logsize = 0; unsigned char* callidval = (unsigned char*)""; OSPTCALLID* callid = NULL; unsigned callidsize = 0; unsigned char token[OSP_TOKENBUF_SIZE]; unsigned int tokensize = sizeof(token); osp_dest dest; int result = MODULE_RETURNCODE_FALSE; LOG(L_DBG, "osp: ospValidateHeader\n"); ospInitDestination(&dest); if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction) != 0)) { LOG(L_ERR, "osp: ERROR: failed to create a new OSP transaction handle (%d)\n", errorcode); } else if ((ospGetRpidUserpart(msg, dest.calling, sizeof(dest.calling)) != 0) && (ospGetFromUserpart(msg, dest.calling, sizeof(dest.calling)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract calling number\n"); } else if ((ospGetUriUserpart(msg, dest.called, sizeof(dest.called)) != 0) && (ospGetToUserpart(msg, dest.called, sizeof(dest.called)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract called number\n"); } else if (ospGetCallId(msg, &callid) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract call id\n"); } else if (ospGetSourceAddress(msg, dest.source, sizeof(dest.source)) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract source address\n"); } else if (ospGetOspHeader(msg, token, &tokensize) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract OSP authorization token\n"); } else { LOG(L_INFO, "osp: validate token for: " "transaction_handle '%i' " "e164_source '%s' " "e164_dest '%s' " "validate_call_id '%s' " "call_id '%.*s'\n", transaction, dest.calling, dest.called, _osp_validate_callid == 0 ? "No" : "Yes", callid->ospmCallIdLen, callid->ospmCallIdVal); if (_osp_validate_callid != 0) { callidsize = callid->ospmCallIdLen; callidval = callid->ospmCallIdVal; } errorcode = OSPPTransactionValidateAuthorisation( transaction, "", "", "", "", dest.calling, OSPC_E164, dest.called, OSPC_E164, callidsize, callidval, tokensize, token, &authorized, &timelimit, &logsize, detaillog, _osp_token_format); if (callid->ospmCallIdLen > sizeof(dest.callid) - 1) { dest.callidsize = sizeof(dest.callid) - 1; } else { dest.callidsize = callid->ospmCallIdLen; } memcpy(dest.callid, callid->ospmCallIdVal, dest.callidsize); dest.callid[dest.callidsize] = 0; dest.tid = ospGetTransactionId(transaction); dest.type = OSPC_DESTINATION; dest.authtime = time(NULL); strcpy(dest.host, _osp_device_ip); ospSaveTermDestination(&dest); if ((errorcode == 0) && (authorized == 1)) { LOG(L_DBG, "osp: call is authorized for %d seconds, call_id '%.*s' transaction_id '%lld'", timelimit, dest.callidsize, dest.callid, dest.tid); ospRecordTermTransaction(msg, transaction, dest.source, dest.calling, dest.called, dest.authtime); result = MODULE_RETURNCODE_TRUE; } else { LOG(L_ERR, "osp: ERROR: token is invalid (%i)\n", errorcode); /* * Update terminating status code to 401 and report terminating setup usage. * We may need to make 401 configurable, just in case a user decides to reply with * a different code. Other options - trigger call setup usage reporting from the cpl * (after replying with an error code), or maybe use a different tm callback. */ ospRecordEvent(0, 401); } } if (transaction != -1) { OSPPTransactionDelete(transaction); } if (callid != NULL) { OSPPCallIdDelete(&callid); } return result; }
int cw_osp_next(struct cw_osp_result *result, int cause) { int res = 0; int tokenlen; unsigned int dummy=0; unsigned int timelimit; unsigned int callidlen; char callidstr[OSPC_CALLID_MAXSIZE] = ""; char callednum[2048]=""; char callingnum[2048]=""; char destination[2048]=""; char token[2000]; OSPE_DEST_PROT prot; OSPE_DEST_OSP_ENABLED ospenabled; result->tech[0] = '\0'; result->dest[0] = '\0'; result->token[0] = '\0'; if (result->handle > -1) { dummy = 0; if (result->numresults) { tokenlen = sizeof(token); while(!res && result->numresults) { result->numresults--; callidlen = sizeof(callidstr); if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { result->token[0] = 0; } else { cw_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); } if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { res = 1; /* Strip leading and trailing brackets */ destination[strlen(destination) - 1] = '\0'; switch(prot) { case OSPE_DEST_PROT_H323_SETUP: cw_copy_string(result->tech, "H323", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; case OSPE_DEST_PROT_SIP: cw_copy_string(result->tech, "SIP", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; case OSPE_DEST_PROT_IAX: cw_copy_string(result->tech, "IAX", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; default: cw_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); res = 0; } } else { cw_log(LOG_DEBUG, "Missing destination protocol\n"); break; } } } } if (!res) { OSPPTransactionDelete(result->handle); result->handle = -1; } } return res; }
int cw_osp_lookup(struct cw_channel *chan, char *provider, char *extension, char *callerid, struct cw_osp_result *result) { int cres; int res = 0; int counts; int tokenlen; unsigned int dummy=0; unsigned int timelimit; unsigned int callidlen; char callidstr[OSPC_CALLID_MAXSIZE] = ""; struct osp_provider *osp; char source[OSP_MAX] = ""; /* Same length as osp->source */ char callednum[2048]=""; char callingnum[2048]=""; char destination[2048]=""; char token[2000]; char tmp[256]="", *l, *n; OSPE_DEST_PROT prot; OSPE_DEST_OSP_ENABLED ospenabled; char *devinfo = NULL; result->handle = -1; result->numresults = 0; result->tech[0] = '\0'; result->dest[0] = '\0'; result->token[0] = '\0'; if (!provider || !strlen(provider)) provider = "default"; if (!callerid) callerid = ""; cw_copy_string(tmp, callerid, sizeof(tmp)); cw_callerid_parse(tmp, &n, &l); if (!l) l = ""; else { cw_shrink_phone_number(l); if (!cw_isphonenumber(l)) l = ""; } callerid = l; if (chan) { cres = cw_autoservice_start(chan); if (cres < 0) return cres; } cw_mutex_lock(&osplock); osp = providers; while(osp) { if (!strcasecmp(osp->name, provider)) { if (OSPPTransactionNew(osp->handle, &result->handle)) { cw_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n"); } else { cw_copy_string(source, osp->source, sizeof(source)); res = 1; } break; } osp = osp->next; } cw_mutex_unlock(&osplock); if (res) { res = 0; /* No more than 10 back */ counts = 10; dummy = 0; devinfo = pbx_builtin_getvar_helper (chan, "OSPPEER"); if (!devinfo) { devinfo = ""; } if (!OSPPTransactionRequestAuthorisation(result->handle, source, devinfo, callerid,OSPC_E164, extension, OSPC_E164, NULL, 0, NULL, NULL, &counts, &dummy, NULL)) { if (counts) { tokenlen = sizeof(token); result->numresults = counts - 1; callidlen = sizeof(callidstr); if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { cw_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n", destination, callednum, callingnum, extension, provider); /* Only support OSP server with only one duration limit */ if (cw_channel_cmpwhentohangup (chan, timelimit) < 0) { cw_channel_setwhentohangup (chan, timelimit); } do { if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { result->token[0] = 0; } else { cw_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); } if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { res = 1; /* Strip leading and trailing brackets */ destination[strlen(destination) - 1] = '\0'; switch(prot) { case OSPE_DEST_PROT_H323_SETUP: cw_copy_string(result->tech, "H323", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; case OSPE_DEST_PROT_SIP: cw_copy_string(result->tech, "SIP", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; case OSPE_DEST_PROT_IAX: cw_copy_string(result->tech, "IAX", sizeof(result->tech)); snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); break; default: cw_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); res = 0; } if (!res && result->numresults) { result->numresults--; callidlen = sizeof(callidstr); if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { break; } } } else { cw_log(LOG_DEBUG, "Missing destination protocol\n"); break; } } while(!res && result->numresults); } } } if (!res) { OSPPTransactionDelete(result->handle); result->handle = -1; } } if (!osp) cw_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider); if (chan) { cres = cw_autoservice_stop(chan); if (cres < 0) return cres; } return res; }
/* * Request OSP authorization and routeing * param msg SIP message * param ignore1 * param ignore2 * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure */ int ospRequestRouting( struct sip_msg* msg, char* ignore1, char* ignore2) { int errorcode; time_t authtime; char source[OSP_E164BUF_SIZE]; char sourcedev[OSP_STRBUF_SIZE]; char src[OSP_STRBUF_SIZE]; char destination[OSP_E164BUF_SIZE]; unsigned int callidnumber = 1; OSPTCALLID* callids[callidnumber]; unsigned int logsize = 0; char* detaillog = NULL; const char** preferred = NULL; unsigned int destcount; OSPTTRANHANDLE transaction = -1; int result = MODULE_RETURNCODE_FALSE; LOG(L_DBG, "osp: ospRequestRouting\n"); authtime = time(NULL); destcount = _osp_max_dests; if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction)) != OSPC_ERR_NO_ERROR) { LOG(L_ERR, "osp: ERROR: failed to create new OSP transaction (%d)\n", errorcode); } else if ((ospGetRpidUserpart(msg, source, sizeof(source)) != 0) && (ospGetFromUserpart(msg, source, sizeof(source)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract calling number\n"); } else if ((ospGetUriUserpart(msg, destination, sizeof(destination)) != 0) && (ospGetToUserpart(msg, destination, sizeof(destination)) != 0)) { LOG(L_ERR, "osp: ERROR: failed to extract called number\n"); } else if (ospGetCallId(msg, &(callids[0])) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract call id\n"); } else if (ospGetSourceAddress(msg, sourcedev, sizeof(sourcedev)) != 0) { LOG(L_ERR, "osp: ERROR: failed to extract source address\n"); } else { ospConvertAddress(sourcedev, src, sizeof(src)); LOG(L_INFO, "osp: request auth and routing for: " "source '%s' " "source_port '%s' " "source_dev '%s' " "e164_source '%s' " "e164_dest '%s' " "call_id '%.*s' " "dest_count '%i'\n", _osp_device_ip, _osp_device_port, src, /* sourcedev in "[x.x.x.x]" or host.domain format */ source, destination, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal, destcount ); /* try to request authorization */ errorcode = OSPPTransactionRequestAuthorisation( transaction, /* transaction handle */ _osp_device_ip, /* from the configuration file */ src, /* source of call, protocol specific, in OSP format */ source, /* calling number in nodotted e164 notation */ OSPC_E164, /* calling number format */ destination, /* called number */ OSPC_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, here always NULL */ &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 */ if ((errorcode == OSPC_ERR_NO_ERROR) && (ospLoadRoutes(transaction, destcount, _osp_device_ip, sourcedev, destination, authtime) == 0)) { LOG(L_INFO, "osp: there are '%d' OSP routes, call_id '%.*s'\n", destcount, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal); result = MODULE_RETURNCODE_TRUE; } else { LOG(L_ERR, "osp: ERROR: failed to request auth and routing (%i), call_id '%.*s\n", errorcode, callids[0]->ospmCallIdLen, callids[0]->ospmCallIdVal); switch (errorcode) { case OSPC_ERR_TRAN_ROUTE_BLOCKED: result = -403; break; case OSPC_ERR_TRAN_ROUTE_NOT_FOUND: result = -404; break; case OSPC_ERR_NO_ERROR: /* AuthRsp ok but ospLoadRoutes fails */ result = -500; break; default: result = MODULE_RETURNCODE_FALSE; break; } } } if (callids[0] != NULL) { OSPPCallIdDelete(&(callids[0])); } if (transaction != -1) { OSPPTransactionDelete(transaction); } return result; }