usage.c

Go to the documentation of this file.
00001 /*
00002  * openser osp module. 
00003  *
00004  * This module enables openser to communicate with an Open Settlement 
00005  * Protocol (OSP) server.  The Open Settlement Protocol is an ETSI 
00006  * defined standard for Inter-Domain VoIP pricing, authorization
00007  * and usage exchange.  The technical specifications for OSP 
00008  * (ETSI TS 101 321 V4.1.1) are available at www.etsi.org.
00009  *
00010  * Uli Abend was the original contributor to this module.
00011  * 
00012  * Copyright (C) 2001-2005 Fhg Fokus
00013  *
00014  * This file is part of Kamailio, a free SIP server.
00015  *
00016  * Kamailio is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version
00020  *
00021  * Kamailio is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00029  * 
00030  * History:
00031  * ---------
00032  *  2006-03-13  RR functions are loaded via API function (bogdan)
00033  */
00034 
00035 #include <osp/osp.h>
00036 #include "../rr/api.h"
00037 #include "../../usr_avp.h"
00038 #include "usage.h"
00039 #include "destination.h"
00040 #include "osptoolkit.h"
00041 #include "sipheader.h"
00042 
00043 #define OSP_ORIG_COOKIE         "osp-o"
00044 #define OSP_TERM_COOKIE         "osp-t"
00045 
00046 #define OSP_RELEASE_ORIG        0
00047 #define OSP_RELEASE_TERM        1
00048 
00049 /* The up case tags for the destinations may corrupt OSP cookies */
00050 #define OSP_COOKIE_TRANSID      't'
00051 #define OSP_COOKIE_TRANSIDUP    'T'
00052 #define OSP_COOKIE_SRCIP        's'
00053 #define OSP_COOKIE_SRCIPUP      'S'
00054 #define OSP_COOKIE_AUTHTIME     'a'
00055 #define OSP_COOKIE_AUTHTIMEUP   'A'
00056 #define OSP_COOKIE_DSTCOUNT     'c'
00057 #define OSP_COOKIE_DSTCOUNTUP   'C'
00058 
00059 /* Flags for OSP cookies */
00060 #define OSP_COOKIEHAS_TRANSID   (1 << 0)
00061 #define OSP_COOKIEHAS_SRCIP     (1 << 1)
00062 #define OSP_COOKIEHAS_AUTHTIME  (1 << 2)
00063 #define OSP_COOKIEHAS_DSTCOUNT  (1 << 3)
00064 #define OSP_COOKIEHAS_ORIGALL   (OSP_COOKIEHAS_TRANSID | OSP_COOKIEHAS_SRCIP | OSP_COOKIEHAS_AUTHTIME | OSP_COOKIEHAS_DSTCOUNT) 
00065 #define OSP_COOKIEHAS_TERMALL   (OSP_COOKIEHAS_TRANSID | OSP_COOKIEHAS_SRCIP | OSP_COOKIEHAS_AUTHTIME) 
00066 
00067 extern char* _osp_device_ip;
00068 extern OSPTPROVHANDLE _osp_provider;
00069 extern str OSP_ORIGDEST_NAME;
00070 extern struct rr_binds osp_rr;
00071 
00072 static void ospRecordTransaction(struct sip_msg* msg, unsigned long long transid, char* uac, char* from, char* to, time_t authtime, int isorig, unsigned destinationCount);
00073 static int ospBuildUsageFromDestination(OSPTTRANHANDLE transaction, osp_dest* dest, int lastcode);
00074 static int ospReportUsageFromDestination(OSPTTRANHANDLE transaction, osp_dest* dest);
00075 static int ospReportUsageFromCookie(struct sip_msg* msg, char* cooky, OSPTCALLID* callid, int release, OSPE_MSG_ROLETYPES type);
00076 
00077 /*
00078  * Create OSP cookie and insert it into Record-Route header
00079  * param msg SIP message
00080  * param tansid Transaction ID
00081  * param uac Source IP
00082  * param from
00083  * param to
00084  * param authtime Request authorization time
00085  * param isorig Originate / Terminate
00086  * param destinationCount Destination count
00087  */
00088 static void ospRecordTransaction(
00089     struct sip_msg* msg, 
00090     unsigned long long transid,
00091     char* uac, 
00092     char* from, 
00093     char* to, 
00094     time_t authtime, 
00095     int isorig,
00096     unsigned destinationCount)
00097 {
00098     str cookie;
00099     char buffer[OSP_STRBUF_SIZE];
00100 
00101     if (osp_rr.add_rr_param == 0) {
00102         LM_WARN("add_rr_param function is not found, cannot record information about the OSP transaction\n");
00103         return;
00104     }
00105 
00106     cookie.s = buffer;
00107 
00108     if (isorig == 1) {
00109         cookie.len = snprintf(
00110             buffer,
00111             sizeof(buffer),
00112             ";%s=%c%llu_%c%s_%c%d_%c%d",
00113             OSP_ORIG_COOKIE,
00114             OSP_COOKIE_TRANSID,
00115             transid,
00116             OSP_COOKIE_SRCIP,
00117             uac,
00118             OSP_COOKIE_AUTHTIME,
00119             (unsigned int)authtime,
00120             OSP_COOKIE_DSTCOUNT,
00121             destinationCount);
00122     } else {
00123         cookie.len = snprintf(
00124             buffer,
00125             sizeof(buffer),
00126             ";%s=%c%llu_%c%s_%c%d",
00127             OSP_TERM_COOKIE,
00128             OSP_COOKIE_TRANSID,
00129             transid,
00130             OSP_COOKIE_SRCIP,
00131             uac,
00132             OSP_COOKIE_AUTHTIME,
00133             (unsigned int)authtime);
00134     }
00135 
00136     if (cookie.len < 0) {
00137         LM_ERR("failed to create OSP cookie\n");
00138         return;
00139     }
00140 
00141     LM_DBG("adding RR parameter '%s'\n", buffer);
00142     osp_rr.add_rr_param(msg, &cookie);
00143 }
00144 
00145 /*
00146  * Create OSP originate cookie and insert it into Record-Route header
00147  * param msg SIP message
00148  * param tansid Transaction ID
00149  * param uac Source IP
00150  * param from
00151  * param to
00152  * param authtime Request authorization time
00153  * param destinationCount Destination count
00154  */
00155 void ospRecordOrigTransaction(
00156     struct sip_msg* msg, 
00157     unsigned long long transid, 
00158     char* uac, 
00159     char* from, 
00160     char* to, 
00161     time_t authtime,
00162     unsigned destinationCount)
00163 {
00164     int isorig = 1;
00165 
00166     ospRecordTransaction(msg, transid, uac, from, to, authtime, isorig, destinationCount);
00167 }
00168 
00169 /*
00170  * Create OSP terminate cookie and insert it into Record-Route header
00171  * param msg SIP message
00172  * param tansid Transaction ID
00173  * param uac Source IP
00174  * param from
00175  * param to
00176  * param authtime Request authorization time
00177  */
00178 void ospRecordTermTransaction(
00179     struct sip_msg* msg, 
00180     unsigned long long transid, 
00181     char* uac, 
00182     char* from, 
00183     char* to, 
00184     time_t authtime)
00185 {
00186     int isorig = 0;
00187     unsigned destinationCount = 0; /* N/A */
00188 
00189     ospRecordTransaction(msg, transid, uac, from, to, authtime, isorig, destinationCount);
00190 }
00191 
00192 /*
00193  * Report OSP usage from OSP cookie
00194  * param msg SIP message
00195  * param cookie OSP cookie (buffer owned by ospReportUsage, can be modified)
00196  * param callid Call ID
00197  * param release Who releases the call first. 0 orig, 1 term
00198  * param type Usage type
00199  * return
00200  */
00201 static int ospReportUsageFromCookie(
00202     struct sip_msg* msg,
00203     char* cookie, 
00204     OSPTCALLID* callid, 
00205     int release,
00206     OSPE_MSG_ROLETYPES type)
00207 {
00208     char* tmp;
00209     char* token;
00210     char tag;
00211     char* value;
00212     unsigned long long transid = 0;
00213     time_t authtime = 0;
00214     unsigned destinationCount = 0;
00215     time_t duration = 0;
00216     time_t endtime = time(NULL);
00217     int cookieflags = 0;
00218     unsigned releasecode;
00219     char firstvia[OSP_STRBUF_SIZE];
00220     char from[OSP_STRBUF_SIZE];
00221     char to[OSP_STRBUF_SIZE];
00222     char nexthop[OSP_STRBUF_SIZE];
00223     char* calling;
00224     char* called;
00225     char* originator = NULL;
00226     char* terminator;
00227     char* source;
00228     char srcbuf[OSP_STRBUF_SIZE];
00229     char* destination;
00230     char dstbuf[OSP_STRBUF_SIZE];
00231     char* srcdev;
00232     char devbuf[OSP_STRBUF_SIZE];
00233     OSPTTRANHANDLE transaction = -1;
00234     int errorcode;
00235 
00236     LM_DBG("'%s' type '%d'\n", cookie, type);
00237     if (cookie != NULL) {
00238         for (token = strtok_r(cookie, "_", &tmp);
00239             token;
00240             token = strtok_r(NULL, "_", &tmp))
00241         {
00242             tag = *token;
00243             value= token + 1;
00244 
00245             switch (tag) {
00246                 case OSP_COOKIE_TRANSID:
00247                 case OSP_COOKIE_TRANSIDUP:
00248                     transid = atoll(value);
00249                     cookieflags |= OSP_COOKIEHAS_TRANSID;
00250                     break;
00251                 case OSP_COOKIE_AUTHTIME:
00252                 case OSP_COOKIE_AUTHTIMEUP:
00253                     authtime = atoi(value);
00254                     duration = endtime - authtime;
00255                     cookieflags |= OSP_COOKIEHAS_AUTHTIME;
00256                     break;
00257                 case OSP_COOKIE_SRCIP:
00258                 case OSP_COOKIE_SRCIPUP:
00259                     originator = value;
00260                     cookieflags |= OSP_COOKIEHAS_SRCIP;
00261                     break;
00262                 case OSP_COOKIE_DSTCOUNT:
00263                 case OSP_COOKIE_DSTCOUNTUP:
00264                     destinationCount = (unsigned)atoi(value);
00265                     cookieflags |= OSP_COOKIEHAS_DSTCOUNT;
00266                     break;
00267                 default:
00268                     LM_ERR("unexpected tag '%c' / value '%s'\n", tag, value);
00269                     break;
00270             }
00271         }
00272     }
00273 
00274     switch (type) {
00275         case OSPC_DESTINATION:
00276             if (cookieflags == OSP_COOKIEHAS_TERMALL) {
00277                 releasecode = 10016;
00278             } else {
00279                 releasecode = 9016;
00280             }
00281             break;
00282         case OSPC_SOURCE:
00283         case OSPC_OTHER:
00284         case OSPC_UNDEFINED_ROLE:
00285         default:
00286             if (cookieflags == OSP_COOKIEHAS_ORIGALL) {
00287                 releasecode = 10016;
00288             } else {
00289                 releasecode = 9016;
00290             }
00291             break;
00292     }
00293 
00294     if (releasecode == 9016) {
00295         transid = 0;
00296         originator = NULL;
00297         authtime = 0;
00298         duration = 0;
00299         destinationCount = 0;
00300     }
00301 
00302     ospGetSourceAddress(msg, firstvia, sizeof(firstvia));
00303     ospGetFromUserpart(msg, from, sizeof(from));
00304     ospGetToUserpart(msg, to, sizeof(to));
00305     ospGetNextHop(msg, nexthop, sizeof(nexthop));
00306 
00307     LM_DBG("first via '%s' from '%s' to '%s' next hop '%s'\n",
00308         firstvia,
00309         from,
00310         to,
00311         nexthop);
00312 
00313     if (release == OSP_RELEASE_ORIG) {
00314         LM_DBG("orig '%s' released the call, call_id '%.*s' transaction_id '%llu'\n",
00315             firstvia,
00316             callid->ospmCallIdLen,
00317             callid->ospmCallIdVal,
00318             transid);
00319         if (originator == NULL) {
00320             originator = firstvia;
00321         }
00322         calling = from;
00323         called = to;
00324         terminator = nexthop;
00325     } else {
00326         release = OSP_RELEASE_TERM;
00327         LM_DBG("term '%s' released the call, call_id '%.*s' transaction_id '%llu'\n",
00328             firstvia,
00329             callid->ospmCallIdLen,
00330             callid->ospmCallIdVal,
00331             transid);
00332         if (originator == NULL) {
00333             originator = nexthop;
00334         }
00335         calling = to;
00336         called = from;
00337         terminator = firstvia;
00338     }
00339 
00340     errorcode = OSPPTransactionNew(_osp_provider, &transaction);
00341 
00342     LM_DBG("created transaction handle '%d' (%d)\n", transaction, errorcode);
00343 
00344     switch (type) {
00345         case OSPC_DESTINATION:
00346             ospConvertAddress(originator, srcbuf, sizeof(srcbuf));
00347             source = srcbuf;
00348             destination = _osp_device_ip;
00349             srcdev = "";
00350             break;
00351         case OSPC_SOURCE:
00352         case OSPC_OTHER:
00353         case OSPC_UNDEFINED_ROLE:
00354         default:
00355             source = _osp_device_ip;
00356             ospConvertAddress(terminator, dstbuf, sizeof(dstbuf));
00357             destination = dstbuf;
00358             ospConvertAddress(originator, devbuf, sizeof(devbuf));
00359             srcdev = devbuf;
00360             break;
00361     }
00362 
00363     errorcode = OSPPTransactionBuildUsageFromScratch(
00364         transaction,
00365         transid,
00366         type,
00367         source,
00368         destination,
00369         srcdev,
00370         "",
00371         calling,
00372         OSPC_E164,
00373         called,
00374         OSPC_E164,
00375         callid->ospmCallIdLen,
00376         callid->ospmCallIdVal,
00377         (enum OSPEFAILREASON)0,
00378         NULL,
00379         NULL);
00380 
00381     LM_DBG("built usage handle '%d' (%d)\n", transaction, errorcode);
00382 
00383     if ((errorcode == OSPC_ERR_NO_ERROR) && (destinationCount > 0)) {
00384         errorcode = OSPPTransactionSetDestinationCount(
00385             transaction,
00386             destinationCount);
00387     }
00388 
00389     ospReportUsageWrapper(
00390         transaction,
00391         releasecode,
00392         duration,
00393         authtime,
00394         endtime,
00395         0,
00396         0,
00397         0,
00398         0,
00399         release);
00400 
00401     return errorcode;
00402 }
00403 
00404 /*
00405  * Report OSP usage
00406  * param msg SIP message
00407  * param whorelease Who releases the call first, 0 orig, 1 term
00408  * param ignore2
00409  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
00410  */
00411 int ospReportUsage(
00412     struct sip_msg* msg, 
00413     char* whorelease, 
00414     char* ignore2)
00415 {
00416     int release;
00417     char* tmp;
00418     char* token;
00419     char parameters[OSP_HEADERBUF_SIZE];
00420     OSPTCALLID* callid = NULL;
00421     int result = MODULE_RETURNCODE_FALSE;
00422 
00423     ospGetCallId(msg, &callid);
00424 
00425     if (callid != NULL) {
00426         /* Who releases the call first, 0 orig, 1 term */
00427         if (sscanf(whorelease, "%d", &release) != 1 || (release != OSP_RELEASE_ORIG && release != OSP_RELEASE_TERM)) {
00428             release = OSP_RELEASE_ORIG;
00429         }
00430         LM_DBG("who releases the call first '%d'\n", release);
00431 
00432         if (ospGetRouteParameters(msg, parameters, sizeof(parameters)) == 0) {
00433             for (token = strtok_r(parameters, ";", &tmp);
00434                  token;
00435                  token = strtok_r(NULL, ";", &tmp))
00436             {
00437                 if (strncmp(token, OSP_ORIG_COOKIE, strlen(OSP_ORIG_COOKIE)) == 0) {
00438                     LM_INFO("report orig duration for call_id '%.*s'\n",
00439                         callid->ospmCallIdLen,
00440                         callid->ospmCallIdVal);
00441                     ospReportUsageFromCookie(msg, token + strlen(OSP_ORIG_COOKIE) + 1, callid, release, OSPC_SOURCE);
00442                     result = MODULE_RETURNCODE_TRUE;
00443                 } else if (strncmp(token, OSP_TERM_COOKIE, strlen(OSP_TERM_COOKIE)) == 0) {
00444                     LM_INFO("report term duration for call_id '%.*s'\n",
00445                         callid->ospmCallIdLen,
00446                         callid->ospmCallIdVal);
00447                     ospReportUsageFromCookie(msg, token + strlen(OSP_TERM_COOKIE) + 1, callid, release, OSPC_DESTINATION);
00448                     result = MODULE_RETURNCODE_TRUE;
00449                 } else {
00450                     LM_DBG("ignoring parameter '%s'\n", token);
00451                 }
00452             }
00453         }
00454 
00455         if (result == MODULE_RETURNCODE_FALSE) {
00456             LM_DBG("without orig or term OSP information\n");
00457             LM_INFO("report other duration for call_id '%.*s'\n",
00458                callid->ospmCallIdLen,
00459                callid->ospmCallIdVal);
00460             ospReportUsageFromCookie(msg, NULL, callid, release, OSPC_SOURCE);
00461             result = MODULE_RETURNCODE_TRUE;
00462         }
00463 
00464         OSPPCallIdDelete(&callid);
00465     }
00466 
00467     if (result == MODULE_RETURNCODE_FALSE) {
00468         LM_ERR("failed to report usage\n");
00469     }
00470 
00471     return result;
00472 }
00473 
00474 /*
00475  * Build OSP usage from destination
00476  * param transaction OSP transaction handle
00477  * param dest Destination
00478  * param lastcode Destination status
00479  * return 0 success, others failure
00480  */
00481 static int ospBuildUsageFromDestination(
00482     OSPTTRANHANDLE transaction, 
00483     osp_dest* dest, 
00484     int lastcode)
00485 {
00486     int errorcode;
00487     char addr[OSP_STRBUF_SIZE];
00488     char* source;
00489     char* srcdev;
00490 
00491     if (dest->type == OSPC_SOURCE) {
00492         ospConvertAddress(dest->srcdev, addr, sizeof(addr));
00493         source = dest->source;
00494         srcdev = addr;
00495     } else {
00496         ospConvertAddress(dest->source, addr, sizeof(addr));
00497         source = addr;
00498         srcdev = dest->srcdev;
00499     }
00500 
00501     errorcode = OSPPTransactionBuildUsageFromScratch(
00502         transaction,
00503         dest->transid,
00504         dest->type,
00505         source,
00506         dest->host,
00507         srcdev,
00508         dest->destdev,
00509         dest->calling,
00510         OSPC_E164,
00511         dest->origcalled,       /* Report original called number */
00512         OSPC_E164,
00513         dest->callidsize,
00514         dest->callid,
00515         (enum OSPEFAILREASON)lastcode,
00516         NULL,
00517         NULL);
00518 
00519     return errorcode;
00520 }
00521 
00522 /*
00523  * Report OSP usage from destination
00524  * param transaction OSP transaction handle
00525  * param dest Destination
00526  * return 0 success
00527  */
00528 static int ospReportUsageFromDestination(
00529     OSPTTRANHANDLE transaction, 
00530     osp_dest* dest)
00531 {
00532     ospReportUsageWrapper(
00533         transaction,                                          /* In - Transaction handle */
00534         dest->lastcode,                                       /* In - Release Code */    
00535         0,                                                    /* In - Length of call */
00536         dest->authtime,                                       /* In - Call start time */
00537         0,                                                    /* In - Call end time */
00538         dest->time180,                                        /* In - Call alert time */
00539         dest->time200,                                        /* In - Call connect time */
00540         dest->time180 ? 1 : 0,                                /* In - Is PDD Info present */
00541         dest->time180 ? dest->time180 - dest->authtime : 0,   /* In - Post Dial Delay */
00542         0);
00543 
00544     return 0;
00545 }
00546 
00547 /*
00548  * Report originate call setup usage
00549  */
00550 void ospReportOrigSetupUsage(void)
00551 {
00552     osp_dest* dest = NULL;
00553     osp_dest* lastused = NULL;
00554     struct usr_avp* destavp = NULL;
00555     int_str destval;
00556     OSPTTRANHANDLE transaction = -1;
00557     int lastcode = 0;
00558     int errorcode;
00559 
00560     errorcode = OSPPTransactionNew(_osp_provider, &transaction);
00561 
00562     for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, NULL, 0);
00563         destavp != NULL;
00564         destavp = search_next_avp(destavp, NULL))
00565     {
00566         get_avp_val(destavp, &destval);
00567 
00568         /* OSP destination is wrapped in a string */
00569         dest = (osp_dest*)destval.s.s;
00570 
00571         if (dest->used == 1) {
00572             if (dest->reported == 1) {
00573                 LM_DBG("orig setup already reported\n");
00574                 break;
00575             } else {
00576                 dest->reported = 1;
00577             }
00578 
00579             LM_DBG("iterating through used destination\n");
00580 
00581             ospDumpDestination(dest);
00582 
00583             lastused = dest;
00584 
00585             errorcode = ospBuildUsageFromDestination(transaction, dest, lastcode);
00586 
00587             lastcode = dest->lastcode;
00588         } else {
00589             LM_DBG("destination has not been used, breaking out\n");
00590             break;
00591         }
00592     }
00593 
00594     if (lastused) {
00595         LM_INFO("report orig setup for call_id '%.*s' transaction_id '%llu'\n",
00596             lastused->callidsize,
00597             lastused->callid,
00598             lastused->transid);
00599         errorcode = ospReportUsageFromDestination(transaction, lastused);
00600     } else {
00601         /* If a Toolkit transaction handle was created, but we did not find
00602          * any destinations to report, we need to release the handle. Otherwise,
00603          * the ospReportUsageFromDestination will release it.
00604          */
00605         OSPPTransactionDelete(transaction);
00606     }
00607 }
00608 
00609 /*
00610  * Report terminate call setup usage
00611  */
00612 void ospReportTermSetupUsage(void)
00613 {
00614     osp_dest* dest = NULL;
00615     OSPTTRANHANDLE transaction = -1;
00616     int errorcode;
00617 
00618     if ((dest = ospGetTermDestination())) {
00619         if (dest->reported == 0) {
00620             dest->reported = 1;
00621             LM_INFO("report term setup for call_id '%.*s' transaction_id '%llu'\n",
00622                 dest->callidsize,
00623                 dest->callid,
00624                 dest->transid);
00625             errorcode = OSPPTransactionNew(_osp_provider, &transaction);
00626             errorcode = ospBuildUsageFromDestination(transaction, dest, 0);
00627             errorcode = ospReportUsageFromDestination(transaction, dest);
00628         } else {
00629             LM_DBG("term setup already reported\n");
00630         }
00631     } else {
00632         LM_ERR("without term setup to report\n");
00633     }
00634 }

Generated on Thu May 24 22:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6