modules_s/osp/orig_transaction.c
62689231
 /*
05914c3f
  * ser osp module. 
62689231
  *
05914c3f
  * This module enables ser to communicate with an Open Settlement 
62689231
  * Protocol (OSP) server.  The Open Settlement Protocol is an ETSI 
  * defined standard for Inter-Domain VoIP pricing, authorization
  * and usage exchange.  The technical specifications for OSP 
  * (ETSI TS 101 321 V4.1.1) are available at www.etsi.org.
  *
  * Uli Abend was the original contributor to this module.
  * 
  * Copyright (C) 2001-2005 Fhg Fokus
  *
05914c3f
  * This file is part of ser, a free SIP server.
62689231
  *
05914c3f
  * ser is free software; you can redistribute it and/or modify
62689231
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
05914c3f
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
62689231
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
e4997e23
 #include <string.h>
 #include <osp/osp.h>
 #include "../../dset.h"
 #include "../../usr_avp.h"
 #include "../../mem/mem.h"
62689231
 #include "orig_transaction.h"
 #include "destination.h"
e4997e23
 #include "osptoolkit.h"
 #include "sipheader.h"
62689231
 #include "usage.h"
 
3b990ec3
 extern char* _osp_device_ip;
 extern char* _osp_device_port;
e4997e23
 extern int _osp_max_dests;
 extern OSPTPROVHANDLE _osp_provider;
05914c3f
 extern int _osp_redir_uri;
62689231
 
e4997e23
 const int OSP_FIRST_ROUTE = 1;
 const int OSP_NEXT_ROUTE = 0;
 const int OSP_MAIN_ROUTE = 1;
 const int OSP_BRANCH_ROUTE = 0;
549d858c
 const str OSP_CALLING_NAME = {"_osp_calling_translated_", 24};
62689231
 
3b990ec3
 static int ospLoadRoutes(OSPTTRANHANDLE transaction, int destcount, char* source, char* sourcedev, char* origcalled, time_t authtime);
 static int ospPrepareDestination(struct sip_msg* msg, int isfirst, int type, int format);
62689231
 
e4997e23
 /*
  * Get routes from AuthRsp
  * param transaction Transaction handle
  * param destcount Expected destination count
  * param source Source IP
  * param sourcedev Source device IP
3b990ec3
  * param origcalled Original called number
e4997e23
  * param authtime Request authorization time
f38ea9b7
  * return 0 success, -1 failure
e4997e23
  */
 static int ospLoadRoutes(
     OSPTTRANHANDLE transaction, 
     int destcount, 
3b990ec3
     char* source, 
     char* sourcedev, 
     char* origcalled, 
e4997e23
     time_t authtime)
 {
     int count;
     int errorcode;
3b990ec3
     osp_dest* dest;
e4997e23
     osp_dest dests[OSP_DEF_DESTS];
549d858c
     OSPE_DEST_PROT protocol;
     OSPE_DEST_OSP_ENABLED enabled;
f38ea9b7
     int result = 0;
e4997e23
     
05914c3f
     LOG(L_DBG, "osp: ospLoadRoutes\n");
 
e4997e23
     for (count = 0; count < destcount; count++) {
05914c3f
         /* This is necessary becuase we will save destinations in reverse order */
e4997e23
         dest = ospInitDestination(&dests[count]);
 
         if (dest == NULL) {
f38ea9b7
             result = -1;
e4997e23
             break;
         }
 
de6cfeb0
         dest->destinationCount = count + 1;
3b990ec3
         strncpy(dest->origcalled, origcalled, sizeof(dest->origcalled) - 1);
5f902046
 
e4997e23
         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);
         }
         
f38ea9b7
         if (errorcode != OSPC_ERR_NO_ERROR) {
05914c3f
             LOG(L_ERR, 
                 "osp: ERROR: failed to load routes (%d) expected '%d' current '%d'\n", 
e4997e23
                 errorcode, 
                 destcount, 
                 count);
f38ea9b7
             result = -1;
e4997e23
             break;
         }
 
         errorcode = OSPPTransactionGetDestProtocol(transaction, &protocol);
f38ea9b7
         if (errorcode != OSPC_ERR_NO_ERROR) {
549d858c
             /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */
05914c3f
             LOG(L_DBG, "osp: cannot get dest protocol (%d)\n", errorcode);
549d858c
             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;
e4997e23
         }
 
         errorcode = OSPPTransactionIsDestOSPEnabled(transaction, &enabled);
f38ea9b7
         if (errorcode != OSPC_ERR_NO_ERROR) {
549d858c
             /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */
05914c3f
             LOG(L_DBG, "osp: cannot get dest OSP version (%d)\n", errorcode);
e4997e23
         } 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;
         }
 
1b097dd4
         errorcode = OSPPTransactionGetDestNetworkId(transaction, dest->networkid);
f38ea9b7
         if (errorcode != OSPC_ERR_NO_ERROR) {
1b097dd4
             /* This does not mean an ERROR. The OSP server may not support OSP 2.1.1 */
05914c3f
             LOG(L_DBG, "osp: cannot get dest network ID (%d)\n", errorcode);
1b097dd4
             dest->networkid[0] = '\0';
         }
 
3b990ec3
         strncpy(dest->source, source, sizeof(dest->source) - 1);
         strncpy(dest->srcdev, sourcedev, sizeof(dest->srcdev) - 1);
e4997e23
         dest->type = OSPC_SOURCE;
de6cfeb0
         dest->transid = ospGetTransactionId(transaction);
e4997e23
         dest->authtime = authtime;
 
05914c3f
         LOG(L_INFO,
             "osp: get destination '%d': "
e4997e23
             "valid after '%s' "
             "valid until '%s' "
05914c3f
             "time limit '%i' seconds "
54939215
             "call id '%.*s' "
05914c3f
             "calling number '%s' "
             "called number '%s' "
e4997e23
             "host '%s' "
             "supported '%d' "
             "network id '%s' "
05914c3f
             "token size '%i'\n",
e4997e23
             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 
      */
f38ea9b7
     if (result == 0) {
e4997e23
         for(count = destcount -1; count >= 0; count--) {
05914c3f
             ospSaveOrigDestination(&dests[count]);
e4997e23
         }
     }
 
     return result;
62689231
 }
 
e4997e23
 /*
  * Request OSP authorization and routeing
  * param msg SIP message
  * param ignore1
  * param ignore2
05914c3f
  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
e4997e23
  */
efb3fe1c
 int ospRequestRouting(
3b990ec3
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
e4997e23
 {
     int errorcode;
     time_t authtime;
05914c3f
     char source[OSP_E164BUF_SIZE];
e4997e23
     char sourcedev[OSP_STRBUF_SIZE];
05914c3f
     char src[OSP_STRBUF_SIZE];
     char destination[OSP_E164BUF_SIZE];
e4997e23
     unsigned int callidnumber = 1;
3b990ec3
     OSPTCALLID* callids[callidnumber];
e4997e23
     unsigned int logsize = 0;
3b990ec3
     char* detaillog = NULL;
     const char** preferred = NULL;
e4997e23
     unsigned int destcount;
     OSPTTRANHANDLE transaction = -1;
     int result = MODULE_RETURNCODE_FALSE;
 
05914c3f
     LOG(L_DBG, "osp: ospRequestRouting\n");
 
e4997e23
     authtime = time(NULL);
 
     destcount = _osp_max_dests;
 
f38ea9b7
     if ((errorcode = OSPPTransactionNew(_osp_provider, &transaction)) != OSPC_ERR_NO_ERROR) {
05914c3f
         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)) 
549d858c
     {
05914c3f
         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)) 
549d858c
     {
05914c3f
         LOG(L_ERR, "osp: ERROR: failed to extract called number\n");
e4997e23
     } else if (ospGetCallId(msg, &(callids[0])) != 0) {
05914c3f
         LOG(L_ERR, "osp: ERROR: failed to extract call id\n");
e4997e23
     } else if (ospGetSourceAddress(msg, sourcedev, sizeof(sourcedev)) != 0) {
05914c3f
         LOG(L_ERR, "osp: ERROR: failed to extract source address\n");
e4997e23
     } else {
05914c3f
         ospConvertAddress(sourcedev, src, sizeof(src));
48beaa85
 
05914c3f
         LOG(L_INFO,
             "osp: request auth and routing for: "
             "source '%s' "
54939215
             "source_port '%s' "
             "source_dev '%s' "
05914c3f
             "e164_source '%s' "
             "e164_dest '%s' "
54939215
             "call_id '%.*s' "
05914c3f
             "dest_count '%i'\n",
e4997e23
             _osp_device_ip,
             _osp_device_port,
05914c3f
             src,                        /* sourcedev in "[x.x.x.x]" or host.domain format */
             source,
             destination,
e4997e23
             callids[0]->ospmCallIdLen,
             callids[0]->ospmCallIdVal,
             destcount
         );    
 
         /* try to request authorization */
         errorcode = OSPPTransactionRequestAuthorisation(
             transaction,       /* transaction handle */
             _osp_device_ip,    /* from the configuration file */
05914c3f
             src,               /* source of call, protocol specific, in OSP format */
             source,            /* calling number in nodotted e164 notation */
e4997e23
             OSPC_E164,         /* calling number format */
05914c3f
             destination,       /* called number */
e4997e23
             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 */
 
f38ea9b7
         if ((errorcode == OSPC_ERR_NO_ERROR) &&
05914c3f
             (ospLoadRoutes(transaction, destcount, _osp_device_ip, sourcedev, destination, authtime) == 0))
f38ea9b7
         {
05914c3f
             LOG(L_INFO,
                 "osp: there are '%d' OSP routes, call_id '%.*s'\n",
e4997e23
                 destcount,
de6cfeb0
                 callids[0]->ospmCallIdLen,
f38ea9b7
                 callids[0]->ospmCallIdVal);
             result = MODULE_RETURNCODE_TRUE;
e4997e23
         } else {
05914c3f
             LOG(L_ERR,
                 "osp: ERROR: failed to request auth and routing (%i), call_id '%.*s\n",
e4997e23
                 errorcode,
                 callids[0]->ospmCallIdLen,
f38ea9b7
                 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 */
05914c3f
                     result = -500;
f38ea9b7
                     break;
                 default:
                     result = MODULE_RETURNCODE_FALSE;
                     break;
             }
e4997e23
         }
     }
 
     if (callids[0] != NULL) {
         OSPPCallIdDelete(&(callids[0]));
     }
 
     if (transaction != -1) {
         OSPPTransactionDelete(transaction);
     }
     
     return result;
62689231
 }
 
e4997e23
 /*
  * Check if there is a route
549d858c
  * param msg SIP message
e4997e23
  * param ignore1
  * param ignore2
  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
  */
efb3fe1c
 int ospCheckRoute(
3b990ec3
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
e4997e23
 {
05914c3f
     LOG(L_DBG, "osp: ospCheckRoute\n");
 
e4997e23
     if (ospCheckOrigDestination() == 0) {
         return MODULE_RETURNCODE_TRUE;
     } else {
         return MODULE_RETURNCODE_FALSE;
     }
62689231
 }
 
549d858c
 /*
05914c3f
  * Append route specific OSP headers
  *     This function only works in branch route block. 
  *     This function is only for SER. SER does not support rewrite_uri in BRANCH_ROUTE.
549d858c
  * param msg SIP message
  * param ignore1
  * param ignore2
05914c3f
  * return MODULE_RETURNCODE_TRUE success MODULE_RETURNCODE_FALSE failed
549d858c
  */
05914c3f
 int ospAppendHeaders(
3b990ec3
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
549d858c
 {
05914c3f
     osp_dest* dest;
549d858c
     int result = MODULE_RETURNCODE_FALSE;
 
05914c3f
     LOG(L_DBG, "osp: ospAppendHeaders\n");
 
     dest = ospGetLastOrigDestination();
     if (dest != NULL) {
         ospAddOspHeader(msg, dest->token, dest->tokensize);
         result = MODULE_RETURNCODE_TRUE;
549d858c
     } else {
05914c3f
         LOG(L_ERR, "osp: ERROR: failed to get last used destination\n");
549d858c
     }
 
     return result;
 }
 
e4997e23
 /*
  * Build SIP message for destination
  * param msg SIP message
  * param isfirst Is first destination
  * param type Main or branch route block
992946a6
  * param format URI format
e4997e23
  * return MODULE_RETURNCODE_TRUE success MODULE_RETURNCODE_FALSE failure
  */
 static int ospPrepareDestination(
3b990ec3
     struct sip_msg* msg, 
e4997e23
     int isfirst,
992946a6
     int type,
     int format)
e4997e23
 {
f43336c3
     str newuri = {NULL, 0};
     int result = MODULE_RETURNCODE_FALSE;
e4997e23
 
05914c3f
     LOG(L_DBG, "osp: ospPrepareDestination\n");
 
     osp_dest *dest = ospGetNextOrigDestination();
e4997e23
 
     if (dest != NULL) {
992946a6
         ospRebuildDestionationUri(&newuri, dest->called, dest->host, "", format);
e4997e23
 
05914c3f
         LOG(L_INFO, 
             "osp: prepare route to URI '%.*s' for call_id '%.*s' transaction_id '%llu'\n",
e4997e23
             newuri.len,
             newuri.s,
             dest->callidsize,
             dest->callid,
de6cfeb0
             dest->transid);
e4997e23
 
         if (type == OSP_MAIN_ROUTE) {
             if (isfirst == OSP_FIRST_ROUTE) {
                 rewrite_uri(msg, &newuri);
             } else {
bf527133
                 append_branch(msg, &newuri, NULL, NULL, Q_UNSPECIFIED,
                               0, NULL);
549d858c
             }
f43336c3
 
             result = MODULE_RETURNCODE_TRUE;
e4997e23
         } else {
05914c3f
             LOG(L_ERR, "osp: ERROR: unsupported route block type\n");
e4997e23
         }
     } else {
05914c3f
         LOG(L_DBG, "osp: there is no more routes\n");
e4997e23
         ospReportOrigSetupUsage();
     }
 
     if (newuri.len > 0) {
         pkg_free(newuri.s);
     }
     
     return result;
 }
62689231
 
e4997e23
 /*
05914c3f
  * Prepare OSP first route
  *     This function prepare the first OSP route
  *     This function is only for SER. SER does not support rewrite_uri in BRANCH_ROUTE.
549d858c
  * param msg SIP message
e4997e23
  * param ignore1
  * param ignore2
  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
  */
05914c3f
 int ospPrepareFirstRoute(
3b990ec3
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
e4997e23
 {
     int result = MODULE_RETURNCODE_TRUE;
62689231
 
05914c3f
     LOG(L_DBG, "osp: ospPrepareFirstRoute\n");
 
     result = ospPrepareDestination(msg, OSP_FIRST_ROUTE, OSP_MAIN_ROUTE, 0);
 
     return result;
 }
 
 /*
  * Prepare OSP next route
  *     This function prepare the next OSP route
  *     This function is only for SER. SER does not support rewrite_uri in BRANCH_ROUTE.
  * param msg SIP message
  * param ignore1
  * param ignore2
  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
  */
 int ospPrepareNextRoute(
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
 {
     int result = MODULE_RETURNCODE_TRUE;
 
     LOG(L_DBG, "osp: ospPrepareNextRoute\n");
 
     result = ospPrepareDestination(msg, OSP_NEXT_ROUTE, OSP_MAIN_ROUTE, 0);
62689231
 
e4997e23
     return result;
 }
62689231
 
e4997e23
 /*
  * Prepare all OSP routes
  *     This function does not work in branch route block.
549d858c
  * param msg SIP message
e4997e23
  * param ignore1
  * param ignore2
  * return MODULE_RETURNCODE_TRUE success, MODULE_RETURNCODE_FALSE failure
  */
efb3fe1c
 int ospPrepareAllRoutes(
3b990ec3
     struct sip_msg* msg, 
     char* ignore1, 
     char* ignore2)
e4997e23
 {
     int result = MODULE_RETURNCODE_TRUE;
 
05914c3f
     LOG(L_DBG, "osp: ospPrepareAllRoutes\n");
 
992946a6
     for(result = ospPrepareDestination(msg, OSP_FIRST_ROUTE, OSP_MAIN_ROUTE, _osp_redir_uri);
e4997e23
         result == MODULE_RETURNCODE_TRUE;
992946a6
         result = ospPrepareDestination(msg, OSP_NEXT_ROUTE, OSP_MAIN_ROUTE, _osp_redir_uri))
e4997e23
     {
     }
 
     return MODULE_RETURNCODE_TRUE;
62689231
 }
54939215