destination.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 
00031 #include <string.h>
00032 #include <stdio.h>
00033 #include <sys/socket.h>
00034 #include <netinet/in.h>
00035 #include <arpa/inet.h>
00036 #include "../../str.h"
00037 #include "../../dprint.h"
00038 #include "../../usr_avp.h"
00039 #include "destination.h"
00040 #include "usage.h"
00041 
00042 /* Name of AVP of OSP destination list */
00043 const str OSP_ORIGDEST_NAME = {"_osp_orig_dests_", 16};
00044 const str OSP_TERMDEST_NAME = {"_osp_term_dests_", 16};
00045 
00046 static int ospSaveDestination(osp_dest* dest, const str* name);
00047 static void ospRecordCode(int code, osp_dest* dest);
00048 static int ospIsToReportUsage(int code);
00049 
00050 /*
00051  * Initialize destination structure
00052  * param dest Destination data structure
00053  * return initialized destination sturcture
00054  */
00055 osp_dest* ospInitDestination(
00056     osp_dest* dest)
00057 {
00058     memset(dest, 0, sizeof(osp_dest));
00059 
00060     dest->callidsize = sizeof(dest->callid);
00061     dest->tokensize = sizeof(dest->token);
00062 
00063     LM_DBG("callidsize '%d' tokensize '%d'\n", dest->callidsize, dest->tokensize);
00064 
00065     return dest;
00066 }
00067 
00068 /* 
00069  * Save destination as an AVP
00070  *     name - OSP_ORIGDEST_NAME / OSP_TERMDEST_NAME
00071  *     value - osp_dest wrapped in a string
00072  * param dest Destination structure
00073  * param name Name of AVP
00074  * return 0 success, -1 failure
00075  */
00076 static int ospSaveDestination(
00077     osp_dest* dest, 
00078     const str* name)
00079 {
00080     str wrapper;
00081     int result = -1;
00082 
00083     wrapper.s = (char*)dest;
00084     wrapper.len = sizeof(osp_dest);
00085 
00086     /* 
00087      * add_avp will make a private copy of both the name and value in shared memory 
00088      * which will be released by TM at the end of the transaction
00089      */
00090     if (add_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)*name, (int_str)wrapper) == 0) {
00091         LM_DBG("destination saved\n");
00092         result = 0;
00093     } else {
00094         LM_ERR("failed to save destination\n");
00095     }
00096 
00097     return result;
00098 }
00099 
00100 /*
00101  * Save originate destination
00102  * param dest Originate destination structure
00103  * return 0 success, -1 failure
00104  */
00105 int ospSaveOrigDestination(
00106     osp_dest* dest)
00107 {
00108     return ospSaveDestination(dest, &OSP_ORIGDEST_NAME);
00109 }
00110 
00111 /*
00112  * Save terminate destination
00113  * param dest Terminate destination structure
00114  * return 0 success, -1 failure
00115  */
00116 int ospSaveTermDestination(
00117     osp_dest* dest)
00118 {
00119     return ospSaveDestination(dest, &OSP_TERMDEST_NAME);
00120 }
00121 
00122 /* 
00123  * Check if there is an unused and supported originate destination from an AVP
00124  *     name - OSP_ORIGDEST_NAME
00125  *     value - osp_dest wrapped in a string
00126  *     search unused (used==0) & supported (support==1)
00127  * return 0 success, -1 failure
00128  */
00129 int ospCheckOrigDestination(void)
00130 {
00131     struct usr_avp* destavp = NULL;
00132     int_str destval;
00133     osp_dest* dest = NULL;
00134     int result = -1;
00135 
00136     for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, NULL, 0);
00137         destavp != NULL;
00138         destavp = search_next_avp(destavp, NULL))
00139     {
00140         get_avp_val(destavp, &destval);
00141 
00142         /* OSP destintaion is wrapped in a string */
00143         dest = (osp_dest*)destval.s.s;
00144 
00145         if (dest->used == 0) {
00146             if (dest->supported == 1) {
00147                 LM_DBG("orig dest exist\n");
00148                 result = 0;
00149                 break;
00150             } else {
00151                 LM_DBG("destination does not been supported\n");
00152             }
00153         } else {
00154             LM_DBG("destination has already been used\n");
00155         }
00156     }
00157 
00158     if (result == -1) {
00159         LM_DBG("there is not unused destination\n");
00160     }
00161 
00162     return result;
00163 }
00164 
00165 /* 
00166  * Retrieved an unused and supported originate destination from an AVP
00167  *     name - OSP_ORIGDEST_NAME
00168  *     value - osp_dest wrapped in a string
00169  *     There can be 0, 1 or more originate destinations. 
00170  *     Find the 1st unused destination (used==0) & supported (support==1),
00171  *     return it, and mark it as used (used==1).
00172  * return NULL on failure
00173  */
00174 osp_dest* ospGetNextOrigDestination(void)
00175 {
00176     struct usr_avp* destavp = NULL;
00177     int_str destval;
00178     osp_dest* dest = NULL;
00179     osp_dest* result = NULL;
00180 
00181     for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, NULL, 0);
00182         destavp != NULL;
00183         destavp = search_next_avp(destavp, NULL))
00184     {
00185         get_avp_val(destavp, &destval);
00186 
00187         /* OSP destintaion is wrapped in a string */
00188         dest = (osp_dest*)destval.s.s;
00189 
00190         if (dest->used == 0) {
00191             if (dest->supported == 1) {
00192                 LM_DBG("orig dest found\n");
00193                 dest->used = 1;
00194                 result = dest;
00195                 break;
00196             } else {
00197                 /* Make it looks like used */
00198                 dest->used = 1;
00199                 /* 111 means wrong protocol */
00200                 dest->lastcode = 111;
00201                 LM_DBG("destination does not been supported\n");
00202             }
00203         } else {
00204             LM_DBG("destination has already been used\n");
00205         }
00206     }
00207 
00208     if (result == NULL) {
00209         LM_DBG("there is not unused destination\n");
00210     }
00211 
00212     return result;
00213 }
00214 
00215 /*
00216  * Retrieved the last used originate destination from an AVP
00217  *    name - OSP_ORIGDEST_NAME
00218  *    value - osp_dest wrapped in a string
00219  *    There can be 0, 1 or more destinations. 
00220  *    Find the last used destination (used==1) & supported (support==1),
00221  *    and return it.
00222  *    In normal condition, this one is the current destination. But it may
00223  *    be wrong for loop condition.
00224  *  return NULL on failure
00225  */
00226 osp_dest* ospGetLastOrigDestination(void)
00227 {
00228     struct usr_avp* destavp = NULL;
00229     int_str destval;
00230     osp_dest* dest = NULL;
00231     osp_dest* lastdest = NULL;
00232 
00233     for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, NULL, 0);
00234         destavp != NULL;
00235         destavp = search_next_avp(destavp, NULL))
00236     {
00237         get_avp_val(destavp, &destval);
00238 
00239         /* OSP destination is wrapped in a string */
00240         dest = (osp_dest*)destval.s.s;
00241 
00242         if (dest->used == 1) {
00243             if (dest->supported == 1) {
00244                 lastdest = dest;
00245                 LM_DBG("curent destination '%s'\n", lastdest->host);
00246             }
00247         } else {
00248             break;
00249         }
00250     }
00251 
00252     return lastdest;
00253 }
00254 
00255 /* 
00256  * Retrieved the terminate destination from an AVP
00257  *     name - OSP_TERMDEST_NAME
00258  *     value - osp_dest wrapped in a string
00259  *     There can be 0 or 1 term destinations. Find and return it.
00260  *  return NULL on failure (no terminate destination)
00261  */
00262 osp_dest* ospGetTermDestination(void)
00263 {
00264     int_str destval;
00265     osp_dest* dest = NULL;
00266 
00267     if (search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_TERMDEST_NAME, &destval, 0) != NULL) {
00268         /* OSP destination is wrapped in a string */
00269         dest = (osp_dest*)destval.s.s;
00270 
00271         LM_DBG("term dest found\n");
00272     }
00273 
00274     return dest;
00275 }
00276 
00277 /*
00278  * Record destination status
00279  * param code Destination status
00280  * param dest Destination
00281  */
00282 static void ospRecordCode(
00283     int code, 
00284     osp_dest* dest)
00285 {
00286     LM_DBG("code '%d'\n", code);
00287     dest->lastcode = code;
00288 
00289     switch (code) {
00290         case 100:
00291             if (!dest->time100) {
00292                 dest->time100 = time(NULL);
00293             } else {
00294                 LM_DBG("100 already recorded\n");
00295             }
00296             break;
00297         case 180:
00298         case 181:
00299         case 182:
00300         case 183:
00301             if (!dest->time180) {
00302                 dest->time180 = time(NULL);
00303             } else {
00304                 LM_DBG("180, 181, 182 or 183 allready recorded\n");
00305             }
00306             break;
00307         case 200:
00308         case 202:
00309             if (!dest->time200) {
00310                 dest->time200 = time(NULL);
00311             } else {
00312                 LM_DBG("200 or 202 allready recorded\n");
00313             }
00314             break;
00315         default:
00316             LM_DBG("will not record time for '%d'\n", code);
00317     }
00318 }
00319 
00320 /*
00321  * Check destination status for reporting usage
00322  * param code Destination status
00323  * return 1 should report, 0 should not report
00324  */
00325 static int ospIsToReportUsage(
00326     int code)
00327 {
00328     int istime = 0;
00329 
00330     LM_DBG("code '%d'\n", code);
00331     if (code >= 200) {
00332         istime = 1;
00333     }
00334 
00335     return istime;
00336 }
00337 
00338 /*
00339  * Report call setup usage for both client and server side
00340  * param clientcode Client status
00341  * param servercode Server status
00342  */
00343 void ospRecordEvent(
00344     int clientcode, 
00345     int servercode)
00346 {
00347     osp_dest* dest;
00348 
00349     LM_DBG("client status '%d'\n", clientcode);
00350     if ((clientcode != 0) && (dest = ospGetLastOrigDestination())) {
00351         ospRecordCode(clientcode, dest);
00352 
00353         if (ospIsToReportUsage(servercode) == 1) {
00354             ospReportOrigSetupUsage();
00355         }
00356     }
00357 
00358     LM_DBG("server status '%d'\n", servercode);
00359     if ((servercode != 0) && (dest = ospGetTermDestination())) {
00360         ospRecordCode(servercode, dest);
00361 
00362         if (ospIsToReportUsage(servercode) == 1) {
00363             ospReportTermSetupUsage();
00364         }
00365     }
00366 }
00367 
00368 /*
00369  * Dump destination information
00370  * param dest Destination
00371  */
00372 void ospDumpDestination(
00373     osp_dest* dest)
00374 {
00375     LM_DBG("dest->host..........'%s'\n", dest->host);
00376     LM_DBG("dest->used..........'%d'\n", dest->used);
00377     LM_DBG("dest->lastcode......'%d'\n", dest->lastcode);
00378     LM_DBG("dest->time100.......'%d'\n", (unsigned int)dest->time100);
00379     LM_DBG("dest->time180.......'%d'\n", (unsigned int)dest->time180);
00380     LM_DBG("dest->time200.......'%d'\n", (unsigned int)dest->time200);
00381 }
00382 
00383 /*
00384  * Dump all destination information
00385  */
00386 void ospDumpAllDestination(void)
00387 {
00388     struct usr_avp* destavp = NULL;
00389     int_str destval;
00390     osp_dest* dest = NULL;
00391     int count = 0;
00392 
00393     for (destavp = search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_ORIGDEST_NAME, NULL, 0);
00394         destavp != NULL;
00395         destavp = search_next_avp(destavp, NULL))
00396     {
00397         get_avp_val(destavp, &destval);
00398 
00399         /* OSP destination is wrapped in a string */
00400         dest = (osp_dest*)destval.s.s;
00401 
00402         LM_DBG("....originate '%d'....\n", count++);
00403 
00404         ospDumpDestination(dest);
00405     }
00406     if (count == 0) {
00407         LM_DBG("there is not originate destination AVP\n");
00408     }
00409 
00410     if (search_first_avp(AVP_NAME_STR | AVP_VAL_STR, (int_str)OSP_TERMDEST_NAME, &destval, 0) != NULL) {
00411         /* OSP destination is wrapped in a string */
00412         dest = (osp_dest*)destval.s.s;
00413 
00414         LM_DBG("....terminate....\n");
00415 
00416         ospDumpDestination(dest);
00417     } else {
00418         LM_DBG("there is not terminate destination AVP\n");
00419     }
00420 }
00421 
00422 /*
00423  * Convert address to "[x.x.x.x]" or "host.domain" format
00424  * param src Source address
00425  * param dst Destination address
00426  * param buffersize Size of dst buffer
00427  */
00428 void ospConvertAddress(
00429     char* src,
00430     char* dst,
00431     int buffersize)
00432 {
00433     struct in_addr inp;
00434 
00435     if (inet_aton(src, &inp) != 0) {
00436         snprintf(dst, buffersize, "[%s]", src);
00437     } else {
00438         snprintf(dst, buffersize, "%s", src);
00439     }
00440 }
00441 

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6