/* * 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(); }
/* * Create a thread to report OSP usage * param ospvTransaction OSP transaction handle * param ospvReleaseCode Call release reason * param ospvDurating Call duration * param ospvStartTime Call start time * param ospvEndTime Call end time * param ospvAlertTime Call alert time * param ospvConnectTime Call connected time * param ospvIsPDDInfoPresent If post dial delay information avaliable * param ospvPostDialDelay Post dial delay information, in seconds * param ospvReleaseSource Which side release the call */ void ospReportUsageWrapper( OSPTTRANHANDLE ospvTransaction, unsigned ospvReleaseCode, unsigned ospvDuration, time_t ospvStartTime, time_t ospvEndTime, time_t ospvAlertTime, time_t ospvConnectTime, unsigned ospvIsPDDInfoPresent, unsigned ospvPostDialDelay, OSPE_RELEASE ospvReleaseSource) { osp_usage* usage; OSPTTHREADID threadid; OSPTTHRATTR threadattr; int errorcode; LM_DBG("schedule usage report for '%llu'\n", ospGetTransactionId(ospvTransaction)); usage = (osp_usage*)malloc(sizeof(osp_usage)); usage->transaction = ospvTransaction; usage->cause = ospvReleaseCode; usage->duration = ospvDuration; usage->start = ospvStartTime; usage->end = ospvEndTime; usage->alert = ospvAlertTime; usage->connect = ospvConnectTime; usage->haspdd = ospvIsPDDInfoPresent; usage->pdd = ospvPostDialDelay; usage->release = ospvReleaseSource; OSPM_THRATTR_INIT(threadattr, errorcode); OSPM_SETDETACHED_STATE(threadattr, errorcode); OSPM_CREATE_THREAD(threadid, &threadattr, ospReportUsageWork, usage, errorcode); OSPM_THRATTR_DESTROY(threadattr); }
/* * Get routes from AuthRsp * param transaction Transaction handle * param destcount Expected destination count * param inbound Inbound info * return 0 success, -1 failure */ static int ospLoadRoutes( OSPTTRANHANDLE trans, int destcount, osp_inbound* inbound) { int count; int errcode; osp_dest* dest; osp_dest dests[OSP_DEF_DESTS]; char host[OSP_STRBUF_SIZE]; char destdev[OSP_STRBUF_SIZE]; OSPE_OPERATOR_NAME type; OSPE_DEST_OSPENABLED enabled; int result = 0; ospSetIdentity(trans); for (count = 0; count < destcount; count++) { /* This is necessary because we will save destinations in reverse order */ dest = ospInitDestination(&dests[count]); if (dest == NULL) { result = -1; break; } dest->destcount = count + 1; if (count == 0) { errcode = OSPPTransactionGetFirstDestination( trans, sizeof(dest->validafter), dest->validafter, dest->validuntil, &dest->timelimit, &dest->callidsize, (void*)dest->callid, sizeof(dest->called), dest->called, sizeof(dest->calling), dest->calling, sizeof(host), host, sizeof(destdev), destdev, &dest->tokensize, dest->token); } else { errcode = OSPPTransactionGetNextDestination( trans, 0, sizeof(dest->validafter), dest->validafter, dest->validuntil, &dest->timelimit, &dest->callidsize, (void*)dest->callid, sizeof(dest->called), dest->called, sizeof(dest->calling), dest->calling, sizeof(host), host, sizeof(destdev), destdev, &dest->tokensize, dest->token); } if (errcode != OSPC_ERR_NO_ERROR) { LM_ERR("failed to load routes (%d) expected '%d' current '%d'\n", errcode, destcount, count); result = -1; break; } ospConvertToInAddress(host, dest->host, sizeof(dest->host)); errcode = OSPPTransactionGetNumberPortabilityParameters(trans, sizeof(dest->nprn), dest->nprn, sizeof(dest->npcic), dest->npcic, &dest->npdi); if (errcode != OSPC_ERR_NO_ERROR) { LM_DBG("cannot get number portability parameters (%d)\n", errcode); dest->nprn[0] = '\0'; dest->npcic[0] = '\0'; dest->npdi = 0; } for (type = OSPC_OPNAME_START; type < OSPC_OPNAME_NUMBER; type++) { errcode = OSPPTransactionGetOperatorName(trans, type, sizeof(dest->opname[type]), dest->opname[type]); if (errcode != OSPC_ERR_NO_ERROR) { LM_DBG("cannot get operator name '%d' (%d)\n", type, errcode); dest->opname[type][0] = '\0'; } } errcode = OSPPTransactionGetDestProtocol(trans, &dest->protocol); if (errcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LM_DBG("cannot get dest protocol (%d)\n", errcode); dest->protocol = OSPC_PROTNAME_SIP; } switch (dest->protocol) { case OSPC_PROTNAME_Q931: case OSPC_PROTNAME_LRQ: case OSPC_PROTNAME_IAX: case OSPC_PROTNAME_T37: case OSPC_PROTNAME_T38: case OSPC_PROTNAME_SKYPE: case OSPC_PROTNAME_SMPP: case OSPC_PROTNAME_XMPP: if (_osp_non_sip) { dest->supported = 1; } else { dest->supported = 0; } break; case OSPC_PROTNAME_SIP: case OSPC_PROTNAME_UNDEFINED: case OSPC_PROTNAME_UNKNOWN: default: dest->supported = 1; break; } errcode = OSPPTransactionIsDestOSPEnabled(trans, &enabled); if (errcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LM_DBG("cannot get dest OSP version (%d)\n", errcode); } else if (enabled == OSPC_DOSP_FALSE) { /* Destination device does not support OSP. Do not send token to it */ dest->token[0] = '\0'; dest->tokensize = 0; } errcode = OSPPTransactionGetDestinationNetworkId(trans, sizeof(dest->dnid), dest->dnid); if (errcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LM_DBG("cannot get dest network ID (%d)\n", errcode); dest->dnid[0] = '\0'; } errcode = OSPPTransactionGetCNAM(trans, sizeof(dest->cnam), dest->cnam); if (errcode != OSPC_ERR_NO_ERROR) { LM_DBG("cannot get CNAM (%d)\n", errcode); dest->cnam[0] = '\0'; } OSPPTransactionGetServiceType(trans, &dest->srvtype); dest->type = OSPC_ROLE_SOURCE; dest->transid = ospGetTransactionId(trans); LM_INFO("get destination '%d': " "validafter '%s' " "validuntil '%s' " "timelimit '%d' seconds " "callid '%.*s' " "calling '%s' " "called '%s' " "host '%s' " "nprn '%s' " "npcic '%s' " "npdi '%d' " /* "spid '%s' " "ocn '%s' " "spn '%s' " "altspn '%s' " "mcc '%s' " "mnc '%s' " */ "cnam '%s' " "service '%d' " "protocol '%d' " "supported '%d' " "networkid '%s' " "tokensize '%d'\n", count, dest->validafter, dest->validuntil, dest->timelimit, dest->callidsize, dest->callid, dest->calling, dest->called, host, dest->nprn, dest->npcic, dest->npdi, /* dest->opname[OSPC_OPNAME_SPID], dest->opname[OSPC_OPNAME_OCN], dest->opname[OSPC_OPNAME_SPN], dest->opname[OSPC_OPNAME_ALTSPN], dest->opname[OSPC_OPNAME_MCC], dest->opname[OSPC_OPNAME_MNC], */ dest->cnam, dest->srvtype, dest->protocol, dest->supported, dest->dnid, dest->tokensize); } /* * Save destination in reverse order, * when we start searching avps the destinations * will be in order */ if (result == 0) { if (ospSaveInboundInfo(inbound) == -1) { ospRecordEvent(0, 500); result = -1; } else { for(count = destcount -1; count >= 0; count--) { if (ospSaveOrigDestination(&dests[count]) == -1) { LM_ERR("failed to save originate destination\n"); /* Report terminate CDR */ ospRecordEvent(0, 500); result = -1; break; } } } } 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; }
/* * Get routes from AuthRsp * param transaction Transaction handle * param destcount Expected destination count * param source Source IP * param sourcedev Source device IP * param origcalled Original called number * param authtime Request authorization time * return 0 success, -1 failure */ static int ospLoadRoutes( OSPTTRANHANDLE transaction, int destcount, char* source, char* sourcedev, char* origcalled, time_t authtime) { int count; int errorcode; osp_dest* dest; osp_dest dests[OSP_DEF_DESTS]; OSPE_DEST_PROT protocol; OSPE_DEST_OSP_ENABLED enabled; int result = 0; LOG(L_DBG, "osp: ospLoadRoutes\n"); for (count = 0; count < destcount; count++) { /* This is necessary becuase we will save destinations in reverse order */ dest = ospInitDestination(&dests[count]); if (dest == NULL) { result = -1; break; } dest->destinationCount = count + 1; strncpy(dest->origcalled, origcalled, sizeof(dest->origcalled) - 1); if (count == 0) { errorcode = OSPPTransactionGetFirstDestination( transaction, sizeof(dest->validafter), dest->validafter, dest->validuntil, &dest->timelimit, &dest->callidsize, (void*)dest->callid, sizeof(dest->called), dest->called, sizeof(dest->calling), dest->calling, sizeof(dest->host), dest->host, sizeof(dest->destdev), dest->destdev, &dest->tokensize, dest->token); } else { errorcode = OSPPTransactionGetNextDestination( transaction, 0, sizeof(dest->validafter), dest->validafter, dest->validuntil, &dest->timelimit, &dest->callidsize, (void*)dest->callid, sizeof(dest->called), dest->called, sizeof(dest->calling), dest->calling, sizeof(dest->host), dest->host, sizeof(dest->destdev), dest->destdev, &dest->tokensize, dest->token); } if (errorcode != OSPC_ERR_NO_ERROR) { LOG(L_ERR, "osp: ERROR: failed to load routes (%d) expected '%d' current '%d'\n", errorcode, destcount, count); result = -1; break; } errorcode = OSPPTransactionGetDestProtocol(transaction, &protocol); if (errorcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LOG(L_DBG, "osp: cannot get dest protocol (%d)\n", errorcode); protocol = OSPE_DEST_PROT_SIP; } switch (protocol) { case OSPE_DEST_PROT_H323_LRQ: case OSPE_DEST_PROT_H323_SETUP: case OSPE_DEST_PROT_IAX: dest->supported = 0; break; case OSPE_DEST_PROT_SIP: case OSPE_DEST_PROT_UNDEFINED: case OSPE_DEST_PROT_UNKNOWN: default: dest->supported = 1; break; } errorcode = OSPPTransactionIsDestOSPEnabled(transaction, &enabled); if (errorcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LOG(L_DBG, "osp: cannot get dest OSP version (%d)\n", errorcode); } else if (enabled == OSPE_OSP_FALSE) { /* Destination device does not support OSP. Do not send token to it */ dest->token[0] = '\0'; dest->tokensize = 0; } errorcode = OSPPTransactionGetDestNetworkId(transaction, dest->networkid); if (errorcode != OSPC_ERR_NO_ERROR) { /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */ LOG(L_DBG, "osp: cannot get dest network ID (%d)\n", errorcode); dest->networkid[0] = '\0'; } strncpy(dest->source, source, sizeof(dest->source) - 1); strncpy(dest->srcdev, sourcedev, sizeof(dest->srcdev) - 1); dest->type = OSPC_SOURCE; dest->transid = ospGetTransactionId(transaction); dest->authtime = authtime; LOG(L_INFO, "osp: get destination '%d': " "valid after '%s' " "valid until '%s' " "time limit '%i' seconds " "call id '%.*s' " "calling number '%s' " "called number '%s' " "host '%s' " "supported '%d' " "network id '%s' " "token size '%i'\n", count, dest->validafter, dest->validuntil, dest->timelimit, dest->callidsize, dest->callid, dest->calling, dest->called, dest->host, dest->supported, dest->networkid, dest->tokensize); } /* * Save destination in reverse order, * when we start searching avps the destinations * will be in order */ if (result == 0) { for(count = destcount -1; count >= 0; count--) { ospSaveOrigDestination(&dests[count]); } } return result; }